Make ImportVCardActivity tolerate screen orientation during caching
vCard to be imported.
Bug: 2450447
Change-Id: Iaa24209f920a257b8d9289ae358f8d8b9b33ba73
diff --git a/src/com/android/contacts/vcard/ImportVCardActivity.java b/src/com/android/contacts/vcard/ImportVCardActivity.java
index ec63a96..b2c8d1a 100644
--- a/src/com/android/contacts/vcard/ImportVCardActivity.java
+++ b/src/com/android/contacts/vcard/ImportVCardActivity.java
@@ -99,6 +99,8 @@
/* package */ final static int VCARD_VERSION_V21 = 1;
/* package */ final static int VCARD_VERSION_V30 = 2;
+ final static String CACHED_URIS = "cached_uris";
+
private AccountSelectionUtil.AccountSelectedListener mAccountSelectionListener;
private Account mAccount;
@@ -125,28 +127,41 @@
new LinkedList<ImportRequest>();
private boolean mConnected = false;
- private boolean mNeedFinish = false;
+ private boolean mNeedToCallFinish = false;
+ private boolean mDisconnectAndFinishDone = false;
public void doBindService() {
bindService(new Intent(ImportVCardActivity.this,
VCardService.class), this, Context.BIND_AUTO_CREATE);
}
- public void setNeedFinish() {
+ /**
+ * Tries to unbind this connection and call {@link ImportVCardActivity#finish()}.
+ * When timing is not appropriate, this object remembers this call and
+ * call {@link ImportVCardActivity#unbindService(ServiceConnection)} and
+ * {@link ImportVCardActivity#finish()} afterwards.
+ */
+ public void tryDisconnectAndFinish() {
synchronized (this) {
- mNeedFinish = true;
- if (mConnected) {
- unbindService(this);
- finish();
+ if (!mDisconnectAndFinishDone) {
+ mNeedToCallFinish = true;
+ if (mConnected) {
+ // onServiceConnected() is already finished and we need to
+ // "manually" call unbindService() here.
+ unbindService(this);
+ mDisconnectAndFinishDone = true;
+ }
}
}
}
- public synchronized void requestSend(final ImportRequest parameter) {
- if (mMessenger != null) {
- sendMessage(parameter);
- } else {
- mPendingRequests.add(parameter);
+ public void requestSend(final ImportRequest parameter) {
+ synchronized (mPendingRequests) {
+ if (mMessenger != null) {
+ sendMessage(parameter);
+ } else {
+ mPendingRequests.add(parameter);
+ }
}
}
@@ -163,8 +178,9 @@
}
public void onServiceConnected(ComponentName name, IBinder service) {
- synchronized (this) {
+ synchronized (mPendingRequests) {
mMessenger = new Messenger(service);
+
// Send pending requests thrown from this Activity before an actual connection
// is established.
while (!mPendingRequests.isEmpty()) {
@@ -174,24 +190,30 @@
}
sendMessage(parameter);
}
- mConnected = true;
- if (mNeedFinish) {
- unbindService(this);
- finish();
+ }
+
+ synchronized (this) {
+ if (!mDisconnectAndFinishDone) {
+ mConnected = true;
+ if (mNeedToCallFinish) {
+ mDisconnectAndFinishDone = true;
+ finish();
+ }
}
}
}
public void onServiceDisconnected(ComponentName name) {
- synchronized (this) {
+ synchronized (mPendingRequests) {
if (!mPendingRequests.isEmpty()) {
Log.w(LOG_TAG, "Some request(s) are dropped.");
}
- // Set to null so that we can detect inappropriate re-connection toward
- // the Service via NullPointerException;
- mPendingRequests = null;
- mMessenger = null;
}
+
+ // Set to null so that we can detect inappropriate re-connection toward
+ // the Service via NullPointerException;
+ mPendingRequests = null;
+ mMessenger = null;
}
}
@@ -290,7 +312,6 @@
final ContentResolver resolver = context.getContentResolver();
String errorMessage = null;
mWakeLock.acquire();
- boolean needFinish = true;
try {
clearOldCache();
mConnection.doBindService();
@@ -328,24 +349,16 @@
// We should take care of this case since Android devices may have
// smaller memory than we usually expect.
System.gc();
- needFinish = false;
-
- // TODO: call this from connection object.
- unbindService(mConnection);
runOnUiThread(new DialogDisplayer(
getString(R.string.fail_reason_low_memory_during_import)));
} catch (IOException e) {
Log.e(LOG_TAG, e.getMessage());
- needFinish = false;
- unbindService(mConnection);
runOnUiThread(new DialogDisplayer(
getString(R.string.fail_reason_io_error)));
} finally {
mWakeLock.release();
mProgressDialogForCacheVCard.dismiss();
- if (needFinish) {
- mConnection.setNeedFinish();
- }
+ mConnection.tryDisconnectAndFinish();
}
}
@@ -485,6 +498,10 @@
}
}
+ public Uri[] getSourceUris() {
+ return mSourceUris;
+ }
+
public void cancel() {
mCanceled = true;
if (mVCardParser != null) {
@@ -949,9 +966,40 @@
}
@Override
+ protected void onSaveInstanceState(Bundle outState) {
+ if (mVCardCacheThread != null) {
+ final Uri[] uris = mVCardCacheThread.getSourceUris();
+ final int length = uris.length;
+ final String[] uriStrings = new String[length];
+ for (int i = 0; i < length; i++) {
+ uriStrings[i] = uris[i].toString();
+ }
+ outState.putStringArray(CACHED_URIS, uriStrings);
+
+ mVCardCacheThread.cancel();
+ }
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle inState) {
+ final String[] uriStrings = inState.getStringArray(CACHED_URIS);
+ if (uriStrings != null && uriStrings.length > 0) {
+ final int length = uriStrings.length;
+ final Uri[] uris = new Uri[length];
+ for (int i = 0; i < length; i++) {
+ uris[i] = Uri.parse(uriStrings[i]);
+ }
+
+ mVCardCacheThread = new VCardCacheThread(uris);
+ }
+ }
+
+ @Override
protected void onPause() {
super.onPause();
+ mConnection.tryDisconnectAndFinish();
+
// ImportVCardActivity should not be persistent. In other words, if there's some
// event calling onPause(), this Activity should finish its work and give the main
// screen back to the caller Activity.