0
0
mirror of https://github.com/ankidroid/Anki-Android.git synced 2024-09-20 20:03:05 +02:00

Complete handling of the events of sd card implemented. There is still some bugs regarding with using the app with any deck selected and the "Deck sample" option off.

This commit is contained in:
edu-zamora 2009-11-05 19:04:20 +08:00 committed by Nicolas Raoul
parent c46bc02af7
commit b99052bc39
5 changed files with 185 additions and 37 deletions

View File

@ -5,6 +5,9 @@
android:layout_width="fill_parent"
android:orientation="vertical">
<include layout="@layout/sdcard_error" />
<TextView
android:id="@+id/DeckPickerName"
android:layout_height="wrap_content"

View File

@ -5,6 +5,9 @@
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<include layout="@layout/sdcard_error" />
<FrameLayout
android:id="@+id/card_whiteboard_layout"
android:layout_width="fill_parent"

View File

@ -18,4 +18,6 @@
<string name="deckpicker_new">%d new today</string>
<string name="deckpicker_loaddeck">Loading deck...</string>
<string name="deckpicker_nodeck">No decks found.</string>
<string name="sdcard_missing_message">SD card is unavailable because it is being used as USB storage. Disconnect USB to access your decks.</string>
</resources>

View File

@ -5,7 +5,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Hashtable;
import android.app.Activity;
import android.app.AlertDialog;
@ -36,9 +35,9 @@ import android.webkit.WebView;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.CompoundButton;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
import android.widget.TextView;
import android.widget.ToggleButton;
/**
@ -119,6 +118,7 @@ public class Ankidroid extends Activity implements Runnable
private Whiteboard mWhiteboard;
//private Hashtable<Integer,String> viewNames = new Hashtable<Integer,String>();
//private LinearLayout mMainLayout, mRememberedLayout, mChronoButtonsLayout;
@ -281,6 +281,7 @@ public class Ankidroid extends Activity implements Runnable
public void loadDeck(String deckFilename)
{
Log.i(TAG, "loadDeck - deckFilename = " + deckFilename);
this.deckFilename = deckFilename;
//If I'm not mistaken, the only possibility for deckFilename to be null here is if never existed a deck before
@ -295,13 +296,20 @@ public class Ankidroid extends Activity implements Runnable
}
Log.i(TAG, "loadDeck - SD card mounted and existent file -> Loading deck...");
// Open the right deck.
AnkiDb.openDatabase(deckFilename);
Log.i(TAG, "Deck loaded!");
try
{
AnkiDb.openDatabase(deckFilename);
Log.i(TAG, "Deck loaded!");
// Don't open database in onResume(). Is already opening elsewhere.
deckSelected = true;
// Start by getting the first card and displaying it.
nextCard();
} catch (SQLException e)
{
Log.i(TAG, "The database " + deckFilename + " could not be opened = " + e.getMessage());
}
// Don't open database in onResume(). Is already opening elsewhere.
deckSelected = true;
// Start by getting the first card and displaying it.
nextCard();
}
}
@ -418,11 +426,13 @@ public class Ankidroid extends Activity implements Runnable
public void openDeckPicker()
{
Log.i(TAG, "openDeckPicker");
deckSelected = false; // Make sure we open the database again in
// onResume() if user pressed "back".
Intent decksPicker = new Intent(this, DeckPicker.class);
decksPicker.putExtra("com.ichi2.anki.Ankidroid.DeckPath", deckPath);
startActivityForResult(decksPicker, PICK_DECK_REQUEST);
Log.i(TAG, "openDeckPicker - Ending");
}
@Override
@ -453,14 +463,21 @@ public class Ankidroid extends Activity implements Runnable
{
Log.i(TAG, "onResume() - deckFilename = " + deckFilename + ", deckSelected = " + deckSelected);
super.onResume();
if (!deckSelected && isSdCardMounted())
if(isSdCardMounted())
{
Log.i(TAG, "onResume() - No deck selected before");
//AnkiDb.openDatabase(deckFilename);
//loadDeck(deckFilename);
//deckSelected = true;
displayProgressDialogAndLoadDeck();
if (!deckSelected)
{
Log.i(TAG, "onResume() - No deck selected before");
//AnkiDb.openDatabase(deckFilename);
//loadDeck(deckFilename);
//deckSelected = true;
displayProgressDialogAndLoadDeck();
}
} else
{
deckSelected = false;
}
Log.i(TAG, "onResume() - Ending");
}
@ -495,7 +512,7 @@ public class Ankidroid extends Activity implements Runnable
restorePreferences();
//If any deck has been selected (usually because there was no sd card attached, and therefore was impossible to select one)
//the controls have not been initialized, so we don't have to try to show or hide them
if(deckSelected)
if(deckSelected && isSdCardMounted())
showOrHideControls();
}
}
@ -532,23 +549,27 @@ public class Ankidroid extends Activity implements Runnable
private void showControls(boolean show)
{
if (show)
if(layoutInitialized)
{
mCard.setVisibility(View.VISIBLE);
mSelectRemembered.setVisibility(View.VISIBLE);
mSelectNotRemembered.setVisibility(View.VISIBLE);
mFlipCard.setVisibility(View.VISIBLE);
showOrHideControls();
} else
{
mCard.setVisibility(View.GONE);
mSelectRemembered.setVisibility(View.GONE);
mSelectNotRemembered.setVisibility(View.GONE);
mFlipCard.setVisibility(View.GONE);
mTimer.setVisibility(View.GONE);
mToggleWhiteboard.setVisibility(View.GONE);
mWhiteboard.setVisibility(View.GONE);
if (show)
{
mCard.setVisibility(View.VISIBLE);
mSelectRemembered.setVisibility(View.VISIBLE);
mSelectNotRemembered.setVisibility(View.VISIBLE);
mFlipCard.setVisibility(View.VISIBLE);
showOrHideControls();
} else
{
mCard.setVisibility(View.GONE);
mSelectRemembered.setVisibility(View.GONE);
mSelectNotRemembered.setVisibility(View.GONE);
mFlipCard.setVisibility(View.GONE);
mTimer.setVisibility(View.GONE);
mToggleWhiteboard.setVisibility(View.GONE);
mWhiteboard.setVisibility(View.GONE);
}
}
}
/**
@ -692,8 +713,16 @@ public class Ankidroid extends Activity implements Runnable
public void run()
{
Log.i(TAG, "Ankidroid loader thread - run");
loadDeck(deckFilename);
handler.sendEmptyMessage(0);
//if(deckSelected)
//{
handler.sendEmptyMessage(0);
//} else
//{
//Dismiss dialog and show something to indicate to the user that a deck has not been loaded
//dialog.dismiss();
//}
}
private Handler handler = new Handler()
@ -703,7 +732,6 @@ public class Ankidroid extends Activity implements Runnable
dialog.dismiss();
showControls(true);
displayCardQuestion();
}
};
@ -717,7 +745,7 @@ public class Ankidroid extends Activity implements Runnable
* is going to be ejected, so applications can clean up any files they have open.
*/
public void registerExternalStorageListener() {
/*if (mUnmountReceiver == null) {
if (mUnmountReceiver == null) {
mUnmountReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@ -728,12 +756,17 @@ public class Ankidroid extends Activity implements Runnable
// which would be wrong because the song ids and
// card id might not match.
//closeExternalStorageFiles(intent.getData().getPath());
Log.i(TAG, "mUnmountReceiver - Action = Media Eject");
closeExternalStorageFiles();
} else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
///mMediaMountedCount++;
//mCardId = FileUtils.getFatVolumeId(intent.getData().getPath());
//reloadQueue();
//notifyChange(QUEUE_CHANGED);
//notifyChange(META_CHANGED);
Log.i(TAG, "mUnmountReceiver - Action = Media Mounted");
hideSdError();
onResume();
}
}
};
@ -742,6 +775,46 @@ public class Ankidroid extends Activity implements Runnable
iFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
iFilter.addDataScheme("file");
registerReceiver(mUnmountReceiver, iFilter);
}*/
}
}
private void closeExternalStorageFiles()
{
AnkiDb.closeDatabase();
displaySdError();
}
private void displaySdError()
{
showControls(false);
showSdCardElements(true);
}
private void hideSdError()
{
showControls(true);
showSdCardElements(false);
}
private void showSdCardElements(boolean show)
{
if(layoutInitialized)
{
LinearLayout layout = (LinearLayout) findViewById(R.id.sd_layout);
TextView tv = (TextView) findViewById(R.id.sd_message);
ImageView image = (ImageView) findViewById(R.id.sd_icon);
if(show)
{
layout.setVisibility(View.VISIBLE);
tv.setVisibility(View.VISIBLE);
image.setVisibility(View.VISIBLE);
} else
{
layout.setVisibility(View.GONE);
tv.setVisibility(View.GONE);
image.setVisibility(View.GONE);
}
}
}
}

View File

@ -5,20 +5,24 @@ import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.TreeSet;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.SQLException;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
@ -54,6 +58,8 @@ public class DeckPicker extends Activity implements Runnable
private boolean mIsFinished = true;
private boolean mDeckIsSelected = false;
private BroadcastReceiver mUnmountReceiver = null;
AdapterView.OnItemClickListener mDeckSelHandler = new AdapterView.OnItemClickListener()
{
@ -69,8 +75,12 @@ public class DeckPicker extends Activity implements Runnable
{
Log.i(TAG, "DeckPicker - onCreate");
super.onCreate(savedInstanceState);
registerExternalStorageListener();
mSelf = this;
String deckPath = getIntent().getStringExtra("com.ichi2.anki.Ankidroid.DeckPath");
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
String deckPath = preferences.getString("deckPath", "/sdcard");
setContentView(R.layout.main);
mDeckList = new ArrayList<HashMap<String, String>>();
@ -160,10 +170,13 @@ public class DeckPicker extends Activity implements Runnable
thread.start();
} else
{
Log.i(TAG, "populateDeckList - No decks found.");
//There is no sd card attached (wrap this code in a function called something like isSdMounted()
//and place it in a utils class
if(!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
{
Log.i(TAG, "populateDeckList - No sd card.");
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("The SD card could not be read. Please, turn off USB storage.");
builder.setPositiveButton("OK", null);
@ -184,6 +197,7 @@ public class DeckPicker extends Activity implements Runnable
mDeckList.clear();
mDeckList.addAll(tree);
mDeckListView.clearChoices();
mDeckListAdapter.notifyDataSetChanged();
Log.i(TAG, "DeckPicker - populateDeckList, Ending");
}
@ -235,6 +249,7 @@ public class DeckPicker extends Activity implements Runnable
private void waitForDeckLoaderThread()
{
mDeckIsSelected = true;
Log.i(TAG, "DeckPicker - waitForDeckLoaderThread(), mDeckIsSelected set to true");
mLock.lock();
try
{
@ -251,6 +266,7 @@ public class DeckPicker extends Activity implements Runnable
public void run()
{
Log.i(TAG, "Thread run - Beginning");
int len = 0;
if (mFileList != null)
len = mFileList.length;
@ -260,14 +276,18 @@ public class DeckPicker extends Activity implements Runnable
mLock.lock();
try
{
Log.i(TAG, "Thread run - Inside lock");
mIsFinished = false;
for (int i = 0; i < len; i++)
{
// Don't load any more decks if one has already been
// selected.
Log.i(TAG, "Thread run - Before break mDeckIsSelected = " + mDeckIsSelected);
if (mDeckIsSelected)
break;
String path = mFileList[i].getAbsolutePath();
Deck deck;
@ -330,9 +350,56 @@ public class DeckPicker extends Activity implements Runnable
}
mDeckListAdapter.notifyDataSetChanged();
Log.i(TAG, "DeckPicker - mDeckList notified of changes");
}
};
/**
* Registers an intent to listen for ACTION_MEDIA_EJECT notifications.
* The intent will call closeExternalStorageFiles() if the external media
* is going to be ejected, so applications can clean up any files they have open.
*/
public void registerExternalStorageListener() {
if (mUnmountReceiver == null) {
mUnmountReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_MEDIA_UNMOUNTED)) {
//saveQueue(true);
//mOneShot = true; // This makes us not save the state again later,
// which would be wrong because the song ids and
// card id might not match.
//closeExternalStorageFiles(intent.getData().getPath());
Log.i(TAG, "DeckPicker - mUnmountReceiver, Action = Media Unmounted");
//closeExternalStorageFiles();
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
String deckPath = preferences.getString("deckPath", "/sdcard");
populateDeckList(deckPath);
} else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
///mMediaMountedCount++;
//mCardId = FileUtils.getFatVolumeId(intent.getData().getPath());
//reloadQueue();
//notifyChange(QUEUE_CHANGED);
//notifyChange(META_CHANGED);
Log.i(TAG, "DeckPicker - mUnmountReceiver, Action = Media Mounted");
//hideSdError();
//onResume();
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
String deckPath = preferences.getString("deckPath", "/sdcard");
mDeckIsSelected = false;
populateDeckList(deckPath);
}
}
};
IntentFilter iFilter = new IntentFilter();
iFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
iFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
iFilter.addDataScheme("file");
registerReceiver(mUnmountReceiver, iFilter);
}
}
/*private void logTree(TreeSet<HashMap<String, String>> tree)
{
Iterator<HashMap<String, String>> it = tree.iterator();