| /* |
| * Copyright 2014, The Android Open Source Project |
| * |
| * 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.android.managedprovisioning; |
| |
| import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE; |
| import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME; |
| |
| import android.accounts.Account; |
| import android.accounts.AccountManager; |
| import android.accounts.AccountManagerFuture; |
| import android.accounts.AuthenticatorException; |
| import android.accounts.OperationCanceledException; |
| import android.app.Activity; |
| import android.app.AlertDialog; |
| import android.app.ProgressDialog; |
| import android.app.admin.DevicePolicyManager; |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.DialogInterface; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.os.AsyncTask; |
| import android.os.Bundle; |
| import android.os.ConditionVariable; |
| import android.os.Handler; |
| import android.os.UserHandle; |
| import android.os.UserManager; |
| import android.provider.Settings; |
| import android.support.v4.content.LocalBroadcastManager; |
| import android.view.View; |
| import android.widget.TextView; |
| |
| import com.android.managedprovisioning.model.ProvisioningParams; |
| |
| import java.io.IOException; |
| import java.util.concurrent.ExecutionException; |
| |
| /** |
| * Profile owner provisioning sets up a separate profile on a device whose primary user is already |
| * set up or being set up. |
| * |
| * <p> |
| * The typical example is setting up a corporate profile that is controlled by their employer on a |
| * users personal device to keep personal and work data separate. |
| * |
| * <p> |
| * The activity handles the UI for managed profile provisioning and starts the |
| * {@link ProfileOwnerProvisioningService}, which runs through the setup steps in an |
| * async task. |
| */ |
| public class ProfileOwnerProvisioningActivity extends SetupLayoutActivity { |
| protected static final String ACTION_CANCEL_PROVISIONING = |
| "com.android.managedprovisioning.CANCEL_PROVISIONING"; |
| |
| private BroadcastReceiver mServiceMessageReceiver; |
| |
| private static final int BROADCAST_TIMEOUT = 2 * 60 * 1000; |
| |
| // Provisioning service started |
| private static final int STATUS_PROVISIONING = 1; |
| // Back button pressed during provisioning, confirm dialog showing. |
| private static final int STATUS_CANCEL_CONFIRMING = 2; |
| // Cancel confirmed, waiting for the provisioning service to complete. |
| private static final int STATUS_CANCELLING = 3; |
| // Cancelling not possible anymore, provisioning already finished successfully. |
| private static final int STATUS_FINALIZING = 4; |
| |
| private static final String KEY_STATUS= "status"; |
| private static final String KEY_PENDING_INTENT = "pending_intent"; |
| |
| private int mCancelStatus = STATUS_PROVISIONING; |
| private Intent mPendingProvisioningResult = null; |
| private ProgressDialog mCancelProgressDialog = null; |
| private AccountManager mAccountManager; |
| |
| private ProvisioningParams mParams; |
| |
| @Override |
| protected void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| ProvisionLogger.logd("Profile owner provisioning activity ONCREATE"); |
| mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE); |
| |
| if (savedInstanceState != null) { |
| mCancelStatus = savedInstanceState.getInt(KEY_STATUS, STATUS_PROVISIONING); |
| mPendingProvisioningResult = savedInstanceState.getParcelable(KEY_PENDING_INTENT); |
| } |
| |
| initializeLayoutParams(R.layout.progress, R.string.setting_up_workspace, true); |
| setTitle(R.string.setup_profile_progress); |
| |
| if (mCancelStatus == STATUS_CANCEL_CONFIRMING) { |
| showCancelProvisioningDialog(); |
| } else if (mCancelStatus == STATUS_CANCELLING) { |
| showCancelProgressDialog(); |
| } |
| mParams = (ProvisioningParams) getIntent().getParcelableExtra( |
| ProvisioningParams.EXTRA_PROVISIONING_PARAMS); |
| if (mParams != null) { |
| maybeSetLogoAndMainColor(mParams.mainColor); |
| } |
| } |
| |
| @Override |
| protected void onResume() { |
| super.onResume(); |
| |
| // Setup broadcast receiver for feedback from service. |
| mServiceMessageReceiver = new ServiceMessageReceiver(); |
| IntentFilter filter = new IntentFilter(); |
| filter.addAction(ProfileOwnerProvisioningService.ACTION_PROVISIONING_SUCCESS); |
| filter.addAction(ProfileOwnerProvisioningService.ACTION_PROVISIONING_ERROR); |
| filter.addAction(ProfileOwnerProvisioningService.ACTION_PROVISIONING_CANCELLED); |
| LocalBroadcastManager.getInstance(this).registerReceiver(mServiceMessageReceiver, filter); |
| |
| // Start service async to make sure the UI is loaded first. |
| final Handler handler = new Handler(getMainLooper()); |
| handler.post(new Runnable() { |
| @Override |
| public void run() { |
| Intent intent = new Intent(ProfileOwnerProvisioningActivity.this, |
| ProfileOwnerProvisioningService.class); |
| intent.putExtras(getIntent()); |
| startService(intent); |
| } |
| }); |
| } |
| |
| class ServiceMessageReceiver extends BroadcastReceiver { |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| if (mCancelStatus == STATUS_CANCEL_CONFIRMING) { |
| // Store the incoming intent and only process it after the user has responded to |
| // the cancel dialog |
| mPendingProvisioningResult = intent; |
| return; |
| } |
| handleProvisioningResult(intent); |
| } |
| } |
| |
| private void handleProvisioningResult(Intent intent) { |
| String action = intent.getAction(); |
| if (ProfileOwnerProvisioningService.ACTION_PROVISIONING_SUCCESS.equals(action)) { |
| if (mCancelStatus == STATUS_CANCELLING) { |
| return; |
| } |
| |
| ProvisionLogger.logd("Successfully provisioned." |
| + "Finishing ProfileOwnerProvisioningActivity"); |
| |
| onProvisioningSuccess(); |
| } else if (ProfileOwnerProvisioningService.ACTION_PROVISIONING_ERROR.equals(action)) { |
| if (mCancelStatus == STATUS_CANCELLING){ |
| return; |
| } |
| String errorLogMessage = intent.getStringExtra( |
| ProfileOwnerProvisioningService.EXTRA_LOG_MESSAGE_KEY); |
| ProvisionLogger.logd("Error reported: " + errorLogMessage); |
| error(R.string.managed_provisioning_error_text, errorLogMessage); |
| // Note that this will be reported as a canceled action |
| mCancelStatus = STATUS_FINALIZING; |
| } else if (ProfileOwnerProvisioningService.ACTION_PROVISIONING_CANCELLED.equals(action)) { |
| if (mCancelStatus != STATUS_CANCELLING) { |
| return; |
| } |
| mCancelProgressDialog.dismiss(); |
| onProvisioningAborted(); |
| } |
| } |
| |
| private void onProvisioningAborted() { |
| stopService(new Intent(this, ProfileOwnerProvisioningService.class)); |
| setResult(Activity.RESULT_CANCELED); |
| finish(); |
| } |
| |
| @Override |
| public void onBackPressed() { |
| if (mCancelStatus == STATUS_PROVISIONING) { |
| mCancelStatus = STATUS_CANCEL_CONFIRMING; |
| showCancelProvisioningDialog(); |
| } else { |
| super.onBackPressed(); |
| } |
| } |
| |
| private void showCancelProvisioningDialog() { |
| AlertDialog alertDialog = new AlertDialog.Builder(this) |
| .setCancelable(false) |
| .setMessage(R.string.profile_owner_cancel_message) |
| .setNegativeButton(R.string.profile_owner_cancel_cancel, |
| new DialogInterface.OnClickListener() { |
| @Override |
| public void onClick(DialogInterface dialog,int id) { |
| mCancelStatus = STATUS_PROVISIONING; |
| if (mPendingProvisioningResult != null) { |
| handleProvisioningResult(mPendingProvisioningResult); |
| } |
| } |
| }) |
| .setPositiveButton(R.string.profile_owner_cancel_ok, |
| new DialogInterface.OnClickListener() { |
| @Override |
| public void onClick(DialogInterface dialog,int id) { |
| confirmCancel(); |
| } |
| }) |
| .create(); |
| alertDialog.show(); |
| } |
| |
| protected void showCancelProgressDialog() { |
| mCancelProgressDialog = new ProgressDialog(this); |
| mCancelProgressDialog.setMessage(getText(R.string.profile_owner_cancelling)); |
| mCancelProgressDialog.setCancelable(false); |
| mCancelProgressDialog.setCanceledOnTouchOutside(false); |
| mCancelProgressDialog.show(); |
| } |
| |
| public void error(int resourceId, String logText) { |
| ProvisionLogger.loge(logText); |
| new AlertDialog.Builder(this) |
| .setTitle(R.string.provisioning_error_title) |
| .setMessage(resourceId) |
| .setCancelable(false) |
| .setPositiveButton(R.string.device_owner_error_ok, |
| new DialogInterface.OnClickListener() { |
| @Override |
| public void onClick(DialogInterface dialog,int id) { |
| onProvisioningAborted(); |
| } |
| }) |
| .show(); |
| } |
| |
| private void confirmCancel() { |
| if (mCancelStatus != STATUS_CANCEL_CONFIRMING) { |
| // Can only cancel if provisioning hasn't finished at this point. |
| return; |
| } |
| mCancelStatus = STATUS_CANCELLING; |
| Intent intent = new Intent(ProfileOwnerProvisioningActivity.this, |
| ProfileOwnerProvisioningService.class); |
| intent.setAction(ACTION_CANCEL_PROVISIONING); |
| startService(intent); |
| showCancelProgressDialog(); |
| } |
| |
| /** |
| * Finish activity and stop service. |
| */ |
| private void onProvisioningSuccess() { |
| mCancelStatus = STATUS_FINALIZING; |
| stopService(new Intent(this, ProfileOwnerProvisioningService.class)); |
| setResult(Activity.RESULT_OK); |
| finish(); |
| } |
| |
| @Override |
| protected void onSaveInstanceState(Bundle outState) { |
| outState.putInt(KEY_STATUS, mCancelStatus); |
| outState.putParcelable(KEY_PENDING_INTENT, mPendingProvisioningResult); |
| } |
| |
| @Override |
| public void onPause() { |
| LocalBroadcastManager.getInstance(this).unregisterReceiver(mServiceMessageReceiver); |
| super.onPause(); |
| } |
| } |