diff --git a/MyTracks/src/com/google/android/apps/mytracks/AbstractSendToGoogleActivity.java b/MyTracks/src/com/google/android/apps/mytracks/AbstractSendToGoogleActivity.java index 6ef5c2645..928de9fd8 100644 --- a/MyTracks/src/com/google/android/apps/mytracks/AbstractSendToGoogleActivity.java +++ b/MyTracks/src/com/google/android/apps/mytracks/AbstractSendToGoogleActivity.java @@ -16,8 +16,6 @@ package com.google.android.apps.mytracks; -import com.google.android.apps.mytracks.fragments.CheckPermissionFragment; -import com.google.android.apps.mytracks.fragments.CheckPermissionFragment.CheckPermissionCaller; import com.google.android.apps.mytracks.fragments.ChooseAccountDialogFragment; import com.google.android.apps.mytracks.fragments.ChooseAccountDialogFragment.ChooseAccountCaller; import com.google.android.apps.mytracks.fragments.ConfirmDeleteDialogFragment; @@ -40,6 +38,7 @@ import com.google.android.apps.mytracks.io.sendtogoogle.UploadResultActivity; import com.google.android.apps.mytracks.io.spreadsheets.SendSpreadsheetsActivity; import com.google.android.apps.mytracks.io.sync.SyncUtils; import com.google.android.apps.mytracks.services.TrackRecordingServiceConnection; +import com.google.android.apps.mytracks.services.tasks.CheckPermissionAsyncTask; import com.google.android.apps.mytracks.util.AnalyticsUtils; import com.google.android.apps.mytracks.util.GoogleEarthUtils; import com.google.android.apps.mytracks.util.IntentUtils; @@ -58,7 +57,6 @@ import android.content.ContentResolver; import android.content.Intent; import android.os.Bundle; import android.os.Parcelable; -import android.support.v4.app.Fragment; import android.util.Log; import android.widget.Toast; @@ -70,8 +68,8 @@ import java.io.IOException; * @author Jimmy Shih */ public abstract class AbstractSendToGoogleActivity extends AbstractMyTracksActivity implements - ChooseAccountCaller, ConfirmSyncCaller, CheckPermissionCaller, ShareTrackCaller, - ConfirmDeleteCaller, PlayMultipleCaller { + ChooseAccountCaller, ConfirmSyncCaller, ShareTrackCaller, ConfirmDeleteCaller, + PlayMultipleCaller { private static final String TAG = AbstractMyTracksActivity.class.getSimpleName(); private static final String SEND_REQUEST_KEY = "send_request_key"; @@ -83,6 +81,7 @@ public abstract class AbstractSendToGoogleActivity extends AbstractMyTracksActiv protected static final int CAMERA_REQUEST_CODE = 5; private SendRequest sendRequest; + private CheckPermissionAsyncTask asyncTask; @Override protected void onCreate(Bundle savedInstanceState) { @@ -90,6 +89,19 @@ public abstract class AbstractSendToGoogleActivity extends AbstractMyTracksActiv if (savedInstanceState != null) { sendRequest = savedInstanceState.getParcelable(SEND_REQUEST_KEY); } + Object retained = getLastCustomNonConfigurationInstance(); + if (retained instanceof CheckPermissionAsyncTask) { + asyncTask = (CheckPermissionAsyncTask) retained; + asyncTask.setActivity(this); + } + } + + @Override + public Object onRetainCustomNonConfigurationInstance() { + if (asyncTask != null) { + asyncTask.setActivity(null); + } + return asyncTask; } @Override @@ -191,18 +203,20 @@ public abstract class AbstractSendToGoogleActivity extends AbstractMyTracksActiv } if (needDrivePermission) { - Fragment fragment = CheckPermissionFragment.newInstance( - sendRequest.getAccount().name, SendToGoogleUtils.DRIVE_SCOPE); - getSupportFragmentManager().beginTransaction() - .add(fragment, CheckPermissionFragment.CHECK_PERMISSION_TAG).commit(); + startCheckPermission(SendToGoogleUtils.DRIVE_SCOPE); } else { onDrivePermissionSuccess(); } } } - @Override - public void onCheckPermissionDone(String scope, boolean success, Intent intent) { + private void startCheckPermission(String scope) { + asyncTask = new CheckPermissionAsyncTask(this, sendRequest.getAccount().name, scope); + asyncTask.execute(); + } + + public void onCheckPermissionDone(String scope, boolean success, Intent userRecoverableIntent) { + asyncTask = null; if (success) { if (scope.equals(SendToGoogleUtils.DRIVE_SCOPE)) { onDrivePermissionSuccess(); @@ -212,7 +226,7 @@ public abstract class AbstractSendToGoogleActivity extends AbstractMyTracksActiv onSpreadsheetsPermissionSuccess(); } } else { - if (intent != null) { + if (userRecoverableIntent != null) { int requestCode; if (scope.equals(SendToGoogleUtils.DRIVE_SCOPE)) { requestCode = DRIVE_REQUEST_CODE; @@ -221,7 +235,7 @@ public abstract class AbstractSendToGoogleActivity extends AbstractMyTracksActiv } else { requestCode = SPREADSHEETS_REQUEST_CODE; } - startActivityForResult(intent, requestCode); + startActivityForResult(userRecoverableIntent, requestCode); } else { onPermissionFailure(); } @@ -271,10 +285,7 @@ public abstract class AbstractSendToGoogleActivity extends AbstractMyTracksActiv private void onMapsPermissionSuccess() { // Check Fusion Tables permission if (sendRequest.isSendFusionTables()) { - Fragment fragment = CheckPermissionFragment.newInstance( - sendRequest.getAccount().name, SendToGoogleUtils.FUSION_TABLES_SCOPE); - getSupportFragmentManager() - .beginTransaction().add(fragment, CheckPermissionFragment.CHECK_PERMISSION_TAG).commit(); + startCheckPermission(SendToGoogleUtils.FUSION_TABLES_SCOPE); } else { onFusionTablesSuccess(); } @@ -283,10 +294,7 @@ public abstract class AbstractSendToGoogleActivity extends AbstractMyTracksActiv private void onFusionTablesSuccess() { // Check Spreadsheets permission if (sendRequest.isSendSpreadsheets()) { - Fragment fragment = CheckPermissionFragment.newInstance( - sendRequest.getAccount().name, SendToGoogleUtils.SPREADSHEETS_SCOPE); - getSupportFragmentManager() - .beginTransaction().add(fragment, CheckPermissionFragment.CHECK_PERMISSION_TAG).commit(); + startCheckPermission(SendToGoogleUtils.SPREADSHEETS_SCOPE); } else { onSpreadsheetsPermissionSuccess(); } diff --git a/MyTracks/src/com/google/android/apps/mytracks/fragments/CheckPermissionFragment.java b/MyTracks/src/com/google/android/apps/mytracks/fragments/CheckPermissionFragment.java deleted file mode 100644 index 7200c5b21..000000000 --- a/MyTracks/src/com/google/android/apps/mytracks/fragments/CheckPermissionFragment.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ - -package com.google.android.apps.mytracks.fragments; - -import com.google.android.apps.mytracks.io.sendtogoogle.SendToGoogleUtils; -import com.google.android.gms.auth.GoogleAuthException; -import com.google.android.gms.auth.UserRecoverableAuthException; -import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.util.Log; - -import java.io.IOException; - -/** - * A non UI fragment to check permission. - * - * @author Jimmy Shih - */ -public class CheckPermissionFragment extends Fragment { - - /** - * Interface for caller of this fragment. - * - * @author Jimmy Shih - */ - public interface CheckPermissionCaller { - - /** - * Called when check permission is done. - * - * @param scope the permission scope - * @param success true if success - * @param intent if not success, intent to prompt for permission - */ - public void onCheckPermissionDone(String scope, boolean success, Intent intent); - } - - public static final String CHECK_PERMISSION_TAG = "checkPermission"; - - private static final String TAG = CheckPermissionFragment.class.getSimpleName(); - private static final String KEY_ACCOUNT_NAME = "accountName"; - private static final String KEY_SCOPE = "scope"; - - private CheckPermissionCaller caller; - - public static CheckPermissionFragment newInstance(String accountName, String scope) { - Bundle bundle = new Bundle(); - bundle.putString(KEY_ACCOUNT_NAME, accountName); - bundle.putString(KEY_SCOPE, scope); - - CheckPermissionFragment checkPermissionFragment = new CheckPermissionFragment(); - checkPermissionFragment.setArguments(bundle); - return checkPermissionFragment; - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - try { - caller = (CheckPermissionCaller) activity; - } catch (ClassCastException e) { - throw new ClassCastException( - activity.toString() + " must implement " + CheckPermissionCaller.class.getSimpleName()); - } - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // Only want one instance - setRetainInstance(true); - - Thread thread = new Thread(new Runnable() { - @Override - public void run() { - String accountName = getArguments().getString(KEY_ACCOUNT_NAME); - String scope = getArguments().getString(KEY_SCOPE); - try { - SendToGoogleUtils.getGoogleAccountCredential(getActivity(), accountName, scope); - finish(scope, true, null); - } catch (UserRecoverableAuthException e) { - Intent intent = null; - try { - // HACK: UserRecoverableAuthException.getIntent can throw a null pointer exception. - intent = e.getIntent(); - } catch (Exception e1) { - Log.e(TAG, "Exception in getIntent", e1); - } - finish(scope, false, intent); - } catch (GoogleAuthException e) { - Log.e(TAG, "GoogleAuthException", e); - finish(scope, false, null); - } catch (UserRecoverableAuthIOException e) { - finish(scope, false, e.getIntent()); - } catch (IOException e) { - Log.e(TAG, "IOException", e); - finish(scope, false, null); - } - } - }); - thread.start(); - } - - private void finish(final String scope, final boolean success, final Intent intent) { - getFragmentManager().popBackStack(); - getActivity().runOnUiThread(new Runnable() { - - @Override - public void run() { - caller.onCheckPermissionDone(scope, success, intent); - } - }); - } -} \ No newline at end of file diff --git a/MyTracks/src/com/google/android/apps/mytracks/services/tasks/CheckPermissionAsyncTask.java b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/CheckPermissionAsyncTask.java new file mode 100644 index 000000000..f27129fc6 --- /dev/null +++ b/MyTracks/src/com/google/android/apps/mytracks/services/tasks/CheckPermissionAsyncTask.java @@ -0,0 +1,134 @@ +/* + * Copyright 2013 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.google.android.apps.mytracks.services.tasks; + +import com.google.android.apps.mytracks.AbstractSendToGoogleActivity; +import com.google.android.apps.mytracks.io.sendtogoogle.SendToGoogleUtils; +import com.google.android.gms.auth.GoogleAuthException; +import com.google.android.gms.auth.UserRecoverableAuthException; +import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException; + +import android.content.Intent; +import android.os.AsyncTask; +import android.util.Log; + +import java.io.IOException; + +/** + * An async task to check permission. + * + * @author Jimmy Shih + */ +public class CheckPermissionAsyncTask extends AsyncTask { + + private static final String TAG = CheckPermissionAsyncTask.class.getSimpleName(); + + private AbstractSendToGoogleActivity activity; + private final String accountName; + private final String scope; + + /** + * True if the AsyncTask result is success. + */ + private boolean success; + + /** + * User recoverable intent if failed. + */ + private Intent userRecoverableIntent; + + /** + * True if the AsyncTask has completed. + */ + private boolean completed; + + /** + * True if can retry the AsyncTask. + */ + private boolean canRetry; + + public CheckPermissionAsyncTask( + AbstractSendToGoogleActivity activity, String accountName, String scope) { + this.activity = activity; + this.accountName = accountName; + this.scope = scope; + success = false; + userRecoverableIntent = null; + completed = false; + canRetry = true; + } + + public void setActivity(AbstractSendToGoogleActivity activity) { + this.activity = activity; + if (completed && activity != null) { + activity.onCheckPermissionDone(scope, success, userRecoverableIntent); + } + } + + @Override + protected Boolean doInBackground(Void... params) { + return performTask(); + } + + @Override + protected void onPostExecute(Boolean result) { + success = result; + completed = true; + if (activity != null) { + activity.onCheckPermissionDone(scope, success, userRecoverableIntent); + } + } + + private boolean performTask() { + try { + SendToGoogleUtils.getGoogleAccountCredential(activity, accountName, scope); + return true; + } catch (UserRecoverableAuthException e) { + try { + // HACK: UserRecoverableAuthException.getIntent can throw a null pointer + // exception. + userRecoverableIntent = e.getIntent(); + return false; + } catch (Exception e1) { + Log.e(TAG, "Exception in getIntent", e1); + userRecoverableIntent = null; + return retryTask(); + } + } catch (GoogleAuthException e) { + Log.e(TAG, "GoogleAuthException", e); + return retryTask(); + } catch (UserRecoverableAuthIOException e) { + userRecoverableIntent = e.getIntent(); + return false; + } catch (IOException e) { + Log.e(TAG, "IOException", e); + return retryTask(); + } + } + + private boolean retryTask() { + if (isCancelled()) { + return false; + } + + if (canRetry) { + canRetry = false; + return performTask(); + } + return false; + } +} \ No newline at end of file