Invokes {@link com.android.packageinstaller.UninstallerActivity} which then displays the + * dialog to the user and handles actual uninstall. + */ + void uninstallClonedApp(String packageName, boolean allUsers, FragmentActivity activity) { + // Create new intent to launch Uninstaller activity + Uri packageUri = Uri.parse("package:" + packageName); + Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri); + uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers); + uninstallIntent.putExtra(Intent.EXTRA_USER, UserHandle.of(mCloneUserId)); + activity.startActivityForResult(uninstallIntent, 0); + } + + /** + * Installs another instance of given package in clone user. + * + *
Creates clone user if doesn't exist and starts the new user before installing app. + * @param packageName + * @return error/success code + */ + int installCloneApp(String packageName) { + String userName = "cloneUser"; + UserHandle cloneUserHandle = null; + boolean newlyCreated = false; + + // Create clone user if not already exists. + if (mCloneUserId == -1) { + UserManager um = mContext.getSystemService(UserManager.class); + try { + cloneUserHandle = um.createProfile(userName, USER_TYPE_PROFILE_CLONE, + new HashSet<>()); + } catch (Exception e) { + if (ManageApplications.DEBUG) { + Log.e("ankita", "Error occurred creating clone user" + e.getMessage()); + } + return ERROR_CREATING_CLONE_USER; + } + + if (cloneUserHandle != null) { + mCloneUserId = cloneUserHandle.getIdentifier(); + newlyCreated = true; + if (ManageApplications.DEBUG) { + Log.d(TAG, "Created clone user " + mCloneUserId); + } + } else { + mCloneUserId = -1; + } + } + + if (mCloneUserId > 0) { + // If clone user is newly created for the first time, then start this user. + if (newlyCreated) { + IActivityManager am = ActivityManagerNative.getDefault(); + try { + am.startUserInBackground(mCloneUserId); + } catch (RemoteException e) { + if (ManageApplications.DEBUG) { + Log.e(TAG, "Error starting clone user " + e.getMessage()); + } + return ERROR_STARTING_CLONE_USER; + } + } + + // Install given app in clone user + int res = 0; + try { + res = AppGlobals.getPackageManager().installExistingPackageAsUser( + packageName, mCloneUserId, + INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS, INSTALL_REASON_USER, null); + } catch (RemoteException e) { + if (ManageApplications.DEBUG) { + Log.e(TAG, "Error installing package" + packageName + " in clone user." + + e.getMessage()); + } + return ERROR_CLONING_PACKAGE; + } + + if (res == INSTALL_FAILED_INVALID_URI) { + if (ManageApplications.DEBUG) { + Log.e(TAG, "Package " + packageName + " doesn't exist."); + } + return ERROR_CLONING_PACKAGE; + } + } + + if (ManageApplications.DEBUG) { + Log.i(TAG, "Package " + packageName + " cloned successfully."); + } + return SUCCESS; + } +} diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java index ce92459e977..e6c174c3dba 100644 --- a/src/com/android/settings/applications/manageapplications/ManageApplications.java +++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java @@ -236,6 +236,7 @@ public class ManageApplications extends InstrumentedFragment private Menu mOptionsMenu; + public static final int LIST_TYPE_NONE = -1; public static final int LIST_TYPE_MAIN = 0; public static final int LIST_TYPE_NOTIFICATION = 1; public static final int LIST_TYPE_STORAGE = 3; @@ -1324,7 +1325,8 @@ public class ManageApplications extends InstrumentedFragment view = ApplicationViewHolder.newHeader(parent, R.string.desc_app_locale_selection_supported); } else if (mManageApplications.mListType == LIST_TYPE_NOTIFICATION) { - view = ApplicationViewHolder.newView(parent, true /* twoTarget */); + view = ApplicationViewHolder.newView(parent, true /* twoTarget */, + LIST_TYPE_NOTIFICATION); } else if (mManageApplications.mListType == LIST_TYPE_CLONED_APPS && viewType == VIEW_TYPE_APP_HEADER) { view = ApplicationViewHolder.newHeader(parent, @@ -1332,9 +1334,10 @@ public class ManageApplications extends InstrumentedFragment } else if (mManageApplications.mListType == LIST_TYPE_CLONED_APPS && viewType == VIEW_TYPE_TWO_TARGET) { view = ApplicationViewHolder.newView( - parent, true, LIST_TYPE_CLONED_APPS, mContext); + parent, true, LIST_TYPE_CLONED_APPS); } else { - view = ApplicationViewHolder.newView(parent, false /* twoTarget */); + view = ApplicationViewHolder.newView(parent, false /* twoTarget */, + mManageApplications.mListType); } return new ApplicationViewHolder(view); } @@ -1781,7 +1784,9 @@ public class ManageApplications extends InstrumentedFragment } break; case LIST_TYPE_CLONED_APPS: - //todo(b/259022623): Attach onClick listener here. + holder.updateAppCloneWidget(mContext, + holder.appCloneOnClickListener(entry, this, + mManageApplications.getActivity()), entry); break; } } diff --git a/tests/robotests/src/com/android/settings/applications/manageapplications/ApplicationViewHolderTest.java b/tests/robotests/src/com/android/settings/applications/manageapplications/ApplicationViewHolderTest.java index be01a8acb02..1311fe23a9f 100644 --- a/tests/robotests/src/com/android/settings/applications/manageapplications/ApplicationViewHolderTest.java +++ b/tests/robotests/src/com/android/settings/applications/manageapplications/ApplicationViewHolderTest.java @@ -16,6 +16,8 @@ package com.android.settings.applications.manageapplications; +import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_NONE; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.mock; @@ -117,7 +119,8 @@ public class ApplicationViewHolderTest { @Test public void twoTouchTarget() { - mView = ApplicationViewHolder.newView(new FrameLayout(mContext), true); + mView = ApplicationViewHolder.newView(new FrameLayout(mContext), true, + LIST_TYPE_NONE); mHolder = new ApplicationViewHolder(mView); assertThat(mHolder.mSwitch).isNotNull(); assertThat(mHolder.mWidgetContainer.getChildCount()).isEqualTo(1); @@ -126,7 +129,8 @@ public class ApplicationViewHolderTest { @Test public void updateSwitch() { final CountDownLatch latch = new CountDownLatch(1); - mView = ApplicationViewHolder.newView(new FrameLayout(mContext), true); + mView = ApplicationViewHolder.newView(new FrameLayout(mContext), true, + LIST_TYPE_NONE); mHolder = new ApplicationViewHolder(mView); mHolder.updateSwitch((buttonView, isChecked) -> latch.countDown(), true, true);