MifareClassicTool を再作成しようとしています ( https://github.com/ikarus23/MifareClassicToolを参照)。誰かが私を助けてくれれば、非常に感謝しています。LogCat に次のようなエラー メッセージが表示されます。
07-28 18:23:02.489: D/AndroidRuntime(338): Shutting down VM
07-28 18:23:02.489: W/dalvikvm(338): threadid=1: thread exiting with uncaught exception (group=0x40015560)
07-28 18:23:02.639: E/AndroidRuntime(338): FATAL EXCEPTION: main
07-28 18:23:02.639: E/AndroidRuntime(338): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{de.syss.MifareClassicTool/de.syss.MifareClassicTool.Activities.MainActivity}: java.lang.ClassNotFoundException: de.syss.MifareClassicTool.Activities.MainActivity in loader dalvik.system.PathClassLoader[/data/app/de.syss.MifareClassicTool-1.apk]
07-28 18:23:02.639: E/AndroidRuntime(338): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1569)
07-28 18:23:02.639: E/AndroidRuntime(338): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
07-28 18:23:02.639: E/AndroidRuntime(338): at android.app.ActivityThread.access$1500(ActivityThread.java:117)
07-28 18:23:02.639: E/AndroidRuntime(338): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
07-28 18:23:02.639: E/AndroidRuntime(338): at android.os.Handler.dispatchMessage(Handler.java:99)
07-28 18:23:02.639: E/AndroidRuntime(338): at android.os.Looper.loop(Looper.java:123)
07-28 18:23:02.639: E/AndroidRuntime(338): at android.app.ActivityThread.main(ActivityThread.java:3683)
07-28 18:23:02.639: E/AndroidRuntime(338): at java.lang.reflect.Method.invokeNative(Native Method)
07-28 18:23:02.639: E/AndroidRuntime(338): at java.lang.reflect.Method.invoke(Method.java:507)
07-28 18:23:02.639: E/AndroidRuntime(338): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
07-28 18:23:02.639: E/AndroidRuntime(338): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
07-28 18:23:02.639: E/AndroidRuntime(338): at dalvik.system.NativeStart.main(Native Method)
07-28 18:23:02.639: E/AndroidRuntime(338): Caused by: java.lang.ClassNotFoundException: de.syss.MifareClassicTool.Activities.MainActivity in loader dalvik.system.PathClassLoader[/data/app/de.syss.MifareClassicTool-1.apk]
07-28 18:23:02.639: E/AndroidRuntime(338): at dalvik.system.PathClassLoader.findClass(PathClassLoader.java:240)
07-28 18:23:02.639: E/AndroidRuntime(338): at java.lang.ClassLoader.loadClass(ClassLoader.java:551)
07-28 18:23:02.639: E/AndroidRuntime(338): at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
07-28 18:23:02.639: E/AndroidRuntime(338): at android.app.Instrumentation.newActivity(Instrumentation.java:1021)
07-28 18:23:02.639: E/AndroidRuntime(338): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1561)
07-28 18:23:02.639: E/AndroidRuntime(338): ... 11 more
07-28 18:28:02.672: I/Process(338): Sending signal. PID: 338 SIG: 9
MainActivity ファイルの私のコードは次のとおりです。
package com.example.mifareclassictool_3;
import java.io.File;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager.NameNotFoundException;
import android.nfc.NfcAdapter;
import android.nfc.tech.MifareClassic;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import de.syss.MifareClassicTool.R;
public class MainActivity extends Activity {
private static final String LOG_TAG =
MainActivity.class.getSimpleName();
private final static int FILE_CHOOSER_DUMP_FILE = 1;
private final static int FILE_CHOOSER_KEY_FILE = 2;
private AlertDialog mEnableNfc;
private Button mReadTag;
private Button mWriteTag;
private boolean mResume = true;
private Intent mOldIntent = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = (TextView) findViewById(R.id.textViewMainFooter);
tv.setMovementMethod(LinkMovementMethod.getInstance());
try {
String appVersion = getPackageManager().getPackageInfo(
getPackageName(), 0).versionName;
tv.setText(TextUtils.concat(getString(R.string.app_version), ": ",
appVersion, " - ", getText(R.string.text_footer)));
} catch (NameNotFoundException e) {
Log.d(LOG_TAG, "Version not found.");
}
Button tools = (Button) findViewById(R.id.buttonMainTools);
registerForContextMenu(tools);
Common.setNfcAdapter(NfcAdapter.getDefaultAdapter(this));
if (Common.getNfcAdapter() == null) {
new AlertDialog.Builder(this)
.setTitle(R.string.dialog_no_nfc_title)
.setMessage(R.string.dialog_no_nfc)
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(R.string.action_exit_app,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
finish();
}
})
.setOnCancelListener(new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
finish();
}
})
.show();
mResume = false;
return;
}
if (Common.isExternalStorageWritableErrorToast(this)) {
// Create keys directory.
File path = new File(Environment.getExternalStoragePublicDirectory(
Common.HOME_DIR) + Common.KEYS_DIR);
if (path.exists() == false && !path.mkdirs()) {
// Could not create directory.
Log.e(LOG_TAG, "Error while crating '" + Common.HOME_DIR
+ Common.KEYS_DIR + "' directory.");
return;
}
path = new File(Environment.getExternalStoragePublicDirectory(
Common.HOME_DIR) + Common.DUMPS_DIR);
if (path.exists() == false && !path.mkdirs()) {
// Could not create directory.
Log.e(LOG_TAG, "Error while crating '" + Common.HOME_DIR
+ Common.DUMPS_DIR + "' directory.");
return;
}
path = new File(Environment.getExternalStoragePublicDirectory(
Common.HOME_DIR) + Common.TMP_DIR);
if (path.exists() == false && !path.mkdirs()) {
// Could not create directory.
Log.e(LOG_TAG, "Error while crating '" + Common.HOME_DIR
+ Common.TMP_DIR + "' directory.");
return;
}
for (File file : path.listFiles()) {
file.delete();
}
if (!hasStdKeysFile()) {
createStdKeysFile();
}
}
mReadTag = (Button) findViewById(R.id.buttonMainReadTag);
mWriteTag = (Button) findViewById(R.id.buttonMainWriteTag);
mEnableNfc = new AlertDialog.Builder(this)
.setTitle(R.string.dialog_nfc_not_enabled_title)
.setMessage(R.string.dialog_nfc_not_enabled)
.setIcon(android.R.drawable.ic_dialog_info)
.setPositiveButton(R.string.action_nfc,
new DialogInterface.OnClickListener() {
@SuppressLint("InlinedApi")
public void onClick(DialogInterface dialog, int which) {
// Goto NFC Settings.
if (Build.VERSION.SDK_INT >= 16) {
startActivity(new Intent(Settings.ACTION_NFC_SETTINGS));
} else {
startActivity(new Intent(
Settings.ACTION_WIRELESS_SETTINGS));
}
}
})
.setNeutralButton(R.string.action_editor_only,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Only use Editor. Do nothing.
}
})
.setNegativeButton(R.string.action_exit_app,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// Exit the App.
finish();
}
}).create();
// Show first usage notice.
SharedPreferences sharedPref = getPreferences(Context.MODE_PRIVATE);
boolean isFirstRun = sharedPref.getBoolean("is_first_run", true);
if (isFirstRun) {
Editor e = sharedPref.edit();
e.putBoolean("is_first_run", false);
e.commit();
new AlertDialog.Builder(this)
.setTitle(R.string.dialog_first_run_title)
.setIcon(android.R.drawable.ic_dialog_alert)
.setMessage(R.string.dialog_first_run)
.setPositiveButton(R.string.action_ok,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
})
.setOnCancelListener(new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
mResume = true;
checkNfc();
}
})
.show();
mResume = false;
}
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
MenuInflater inflater = getMenuInflater();
menu.setHeaderTitle(R.string.dialog_tools_menu_title);
menu.setHeaderIcon(android.R.drawable.ic_menu_preferences);
inflater.inflate(R.menu.tools, menu);
// Enable/Disable tag info tool depending on NFC availability.
menu.findItem(R.id.menuMainTagInfo).setEnabled(
Common.getNfcAdapter() != null
&& Common.getNfcAdapter().isEnabled());
}
* If resuming is allowed because all dependencies from
* {@link #onCreate(Bundle)} are satisfied, call
* {@link #checkNfc()}
* @see #onCreate(Bundle)
* @see #checkNfc()
*/
@Override
public void onResume() {
super.onResume();
if (mResume) {
checkNfc();
}
}
/**
* Check if NFC adapter is enabled. If not, show the user a dialog and let
* him choose between "Goto NFC Setting", "Use Editor Only" and "Exit App".
* Also enable NFC foreground dispatch system.
* @see Common#enableNfcForegroundDispatch(Activity)
*/
private void checkNfc() {
// Check if the NFC hardware is enabled.
if (Common.getNfcAdapter() != null
&& !Common.getNfcAdapter().isEnabled()) {
// NFC is disabled. Show dialog.
mEnableNfc.show();
// Disable read/write tag options.
mReadTag.setEnabled(false);
mWriteTag.setEnabled(false);
return;
} else {
// NFC is enabled. Hide dialog and enable NFC
// foreground dispatch.
if (mOldIntent != getIntent()) {
if (Common.treatAsNewTag(getIntent(), this) == 0) {
// Device or tag does not support Mifare Classic.
// Run the only thing that is possible: The tag info tool.
Intent i = new Intent(this, TagInfoToolActivity.class);
startActivity(i);
}
mOldIntent = getIntent();
}
Common.enableNfcForegroundDispatch(this);
mEnableNfc.hide();
mReadTag.setEnabled(true);
mWriteTag.setEnabled(true);
}
}
* Disable NFC foreground dispatch system.
* @see Common#disableNfcForegroundDispatch(Activity)
*/
@Override
public void onPause() {
super.onPause();
Common.disableNfcForegroundDispatch(this);
}
/**
* Handle new Intent as a new tag Intent and if the tag/device does not
* support Mifare Classic, then run {@link TagInfoToolActivity}.
* @see Common#treatAsNewTag(Intent, android.content.Context)
* @see TagInfoToolActivity
*/
@Override
public void onNewIntent(Intent intent) {
if (Common.treatAsNewTag(intent, this) == 0) {
// Device or tag does not support Mifare Classic.
// Run the only thing that is possible: The tag info tool.
Intent i = new Intent(this, TagInfoToolActivity.class);
startActivity(i);
}
}
/**
* Show the {@link ReadTagActivity}.
* @param view The View object that triggered the method
* (in this case the read tag button).
* @see ReadTagActivity
*/
public void onShowReadTag(View view) {
Intent intent = new Intent(this, ReadTagActivity.class);
startActivity(intent);
}
/**
* Show the {@link WriteTagActivity}.
* @param view The View object that triggered the method
* (in this case the write tag button).
* @see WriteTagActivity
*/
public void onShowWriteTag(View view) {
Intent intent = new Intent(this, WriteTagActivity.class);
startActivity(intent);
}
/**
* Show the help Activity.
* @param view The View object that triggered the method
* (in this case the help/info button).
*/
public void onShowHelp(View view) {
Intent intent = new Intent(this, HelpActivity.class);
startActivity(intent);
}
/**
* Show the tools menu (as context menu).
* @param view The View object that triggered the method
* (in this case the tools button).
*/
public void onShowTools(View view) {
openContextMenu(view);
}
/**
* Open a file chooser ({@link FileChooserActivity}). The
* Activity result will be processed in
* {@link #onActivityResult(int, int, Intent)}.
* If the dump files folder is empty display an additional error
* message.
* @param view The View object that triggered the method
* (in this case the show/edit tag dump button).
* @see FileChooserActivity
* @see #onActivityResult(int, int, Intent)
*/
public void onOpenTagDumpEditor(View view) {
String dumpsDir = Environment.getExternalStoragePublicDirectory(
Common.HOME_DIR) + Common.DUMPS_DIR;
if (Common.isExternalStorageWritableErrorToast(this)) {
File file = new File(dumpsDir);
if (file.isDirectory() && (file.listFiles() == null
|| file.listFiles().length == 0)) {
Toast.makeText(this, R.string.info_no_dumps,
Toast.LENGTH_LONG).show();
}
Intent intent = new Intent(this, FileChooserActivity.class);
intent.putExtra(FileChooserActivity.EXTRA_DIR, dumpsDir);
intent.putExtra(FileChooserActivity.EXTRA_TITLE,
getString(R.string.text_open_dump_title));
intent.putExtra(FileChooserActivity.EXTRA_BUTTON_TEXT,
getString(R.string.action_open_dump_file));
intent.putExtra(FileChooserActivity.EXTRA_ENABLE_DELETE_FILE, true);
startActivityForResult(intent, FILE_CHOOSER_DUMP_FILE);
}
}
/**
* Open a file chooser ({@link FileChooserActivity}). The
* Activity result will be processed in
* {@link #onActivityResult(int, int, Intent)}.
* @param view The View object that triggered the method
* (in this case the show/edit key button).
* @see FileChooserActivity
* @see #onActivityResult(int, int, Intent)
*/
public void onOpenKeyEditor(View view) {
if (Common.isExternalStorageWritableErrorToast(this)) {
Intent intent = new Intent(this, FileChooserActivity.class);
intent.putExtra(FileChooserActivity.EXTRA_DIR,
Environment.getExternalStoragePublicDirectory(
Common.HOME_DIR) + Common.KEYS_DIR);
intent.putExtra(FileChooserActivity.EXTRA_TITLE,
getString(R.string.text_open_key_file_title));
intent.putExtra(FileChooserActivity.EXTRA_BUTTON_TEXT,
getString(R.string.action_open_key_file));
intent.putExtra(FileChooserActivity.EXTRA_ENABLE_NEW_FILE, true);
intent.putExtra(FileChooserActivity.EXTRA_ENABLE_DELETE_FILE, true);
startActivityForResult(intent, FILE_CHOOSER_KEY_FILE);
}
}
/**
* Handle (start) the selected tool from the tools menu.
*/
@Override
public boolean onContextItemSelected(MenuItem item) {
Intent intent = null;
switch (item.getItemId()) {
case R.id.menuMainTagInfo:
intent = new Intent(this, TagInfoToolActivity.class);
startActivity(intent);
return true;
case R.id.menuMainValueBlockCoder:
intent = new Intent(this, ValueBlockToolActivity.class);
startActivity(intent);
return true;
default:
return super.onContextItemSelected(item);
}
}
/**
* Run the {@link DumpEditorActivity} or the {@link KeyEditorActivity}
* if file chooser result is O.K.
* @see DumpEditorActivity
* @see KeyEditorActivity
* @see #onOpenTagDumpEditor(View)
* @see #onOpenKeyEditor(View)
*/
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode) {
case FILE_CHOOSER_DUMP_FILE:
if (resultCode == Activity.RESULT_OK) {
Intent intent = new Intent(this, DumpEditorActivity.class);
intent.putExtra(FileChooserActivity.EXTRA_CHOSEN_FILE,
data.getStringExtra(
FileChooserActivity.EXTRA_CHOSEN_FILE));
startActivity(intent);
}
break;
case FILE_CHOOSER_KEY_FILE:
if (resultCode == Activity.RESULT_OK) {
Intent intent = new Intent(this, KeyEditorActivity.class);
intent.putExtra(FileChooserActivity.EXTRA_CHOSEN_FILE,
data.getStringExtra(
FileChooserActivity.EXTRA_CHOSEN_FILE));
startActivity(intent);
}
break;
}
}
/**
* Create a standard key file ({@link Common#STD_KEYS}) in
* {@link Common#KEYS_DIR}. This file contains some std. Mifare keys:
* <ul>
* <li>0xFFFFFFFFFFFF - Unformatted, factory fresh tags.</li>
* <li>0xA0A1A2A3A4A5 - First sector of the tag (Mifare MAD).</li>
* <li>0xD3F7D3F7D3F7 - All other sectors.</li>
* <li>Others from {@link Common#SOME_CLASSICAL_KNOWN_KEYS}.</li>
* </ul>
* The file is a simple text file, any plain text editor will do the trick.
* Data from this App are stored in
* getExternalStoragePublicDirectory(Common.HOME_DIR) to remain
* there after App uninstallation.
* @see Common#SOME_CLASSICAL_KNOWN_KEYS
* @see Common#KEYS_DIR
* @see Common#HOME_DIR
*/
private void createStdKeysFile() {
// Create std. keys file.
File file = new File(Environment.getExternalStoragePublicDirectory(
Common.HOME_DIR) + Common.KEYS_DIR, Common.STD_KEYS);
String[] lines = new String[Common.SOME_CLASSICAL_KNOWN_KEYS.length+4];
lines[0] = "# " + getString(R.string.text_std_keys_comment);
lines[1] = Common.byte2HexString(MifareClassic.KEY_DEFAULT);
lines[2] = Common.byte2HexString(
MifareClassic.KEY_MIFARE_APPLICATION_DIRECTORY);
lines[3] = Common.byte2HexString(MifareClassic.KEY_NFC_FORUM);
System.arraycopy(Common.SOME_CLASSICAL_KNOWN_KEYS, 0,
lines, 4, Common.SOME_CLASSICAL_KNOWN_KEYS.length);
Common.saveFile(file, lines);
}
/**
* Check if there is a {@link Common#STD_KEYS} file
* in {@link Common#HOME_DIR}/{@link Common#KEYS_DIR}.
* @return True if there is such a file, False otherwise.
*/
private boolean hasStdKeysFile() {
File file = new File(Environment.getExternalStoragePublicDirectory(
Common.HOME_DIR) + Common.KEYS_DIR, Common.STD_KEYS);
return file.exists();
}
}
マニフェスト ファイルは次のとおりです。
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.syss.MifareClassicTool"
android:versionCode="13"
android:versionName="1.4.2" >
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="17" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature
android:name="android.hardware.nfc"
android:required="true" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:name="de.syss.MifareClassicTool.Activities.MainActivity"
android:configChanges="orientation|screenSize"
android:label="@string/title_activity_main"
android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- NFC Tech Filter -->
<intent-filter>
<action android:name="android.nfc.action.TECH_DISCOVERED" />
</intent-filter>
<meta-data
android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="@xml/nfc_tech_filter" />
</activity>
<activity
android:name="de.syss.MifareClassicTool.Activities.CreateKeyMapActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:icon="@drawable/map_keys_to_sector"
android:label="@string/title_activity_create_key_map"
android:launchMode="singleTop" >
</activity>
<activity
android:name="de.syss.MifareClassicTool.Activities.DumpEditorActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:icon="@drawable/edit_dump"
android:label="@string/title_activity_dump_editor" >
</activity>
<activity
android:name="de.syss.MifareClassicTool.Activities.FileChooserActivity"
android:icon="@drawable/open"
android:label="@string/title_activity_file_chooser"
android:launchMode="singleTop" >
</activity>
<activity
android:name="de.syss.MifareClassicTool.Activities.AccessConditionDecoderActivity"
android:configChanges="orientation|screenSize"
android:icon="@drawable/access_conditions"
android:label="@string/title_activity_access_conditions"
android:launchMode="singleTop" >
</activity>
<activity
android:name="de.syss.MifareClassicTool.Activities.ValueBlocksToIntActivity"
android:configChanges="orientation|screenSize"
android:icon="@drawable/value_block_to_int"
android:label="@string/title_activity_value_blocks"
android:launchMode="singleTop" >
</activity>
<activity
android:name="de.syss.MifareClassicTool.Activities.WriteTagActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:icon="@drawable/write_tag"
android:label="@string/title_activity_write_tag"
android:launchMode="singleTop" >
</activity>
<activity
android:name="de.syss.MifareClassicTool.Activities.ReadTagActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:icon="@drawable/read_tag"
android:label="@string/title_activity_read_tag"
android:launchMode="singleTop" >
</activity>
<activity
android:name="de.syss.MifareClassicTool.Activities.KeyEditorActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:icon="@drawable/edit_keys"
android:label="@string/title_activity_key_editor"
android:launchMode="singleTop" >
</activity>
<activity
android:name="de.syss.MifareClassicTool.Activities.HelpActivity"
android:configChanges="orientation|screenSize"
android:icon="@drawable/help_and_info"
android:label="@string/title_activity_help"
android:launchMode="singleTop" >
</activity>
<activity
android:name="de.syss.MifareClassicTool.Activities.HexToAsciiActivity"
android:configChanges="orientation|screenSize"
android:icon="@drawable/hex_to_ascii"
android:label="@string/title_activity_hex_to_ascii"
android:launchMode="singleTop" >
</activity>
<activity
android:name="de.syss.MifareClassicTool.Activities.TagInfoToolActivity"
android:configChanges="orientation|screenSize"
android:icon="@drawable/tag_info"
android:label="@string/title_activity_tag_info"
android:launchMode="singleTop" >
</activity>
<activity
android:name="de.syss.MifareClassicTool.Activities.ValueBlockToolActivity"
android:configChanges="orientation|screenSize"
android:icon="@drawable/value_block_tool"
android:label="@string/title_activity_value_block_tool"
android:launchMode="singleTop" >
</activity>
</application>
</manifest>