Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2d8eb4ab authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Refactor UI code in Uninstall activities"

parents 53a08fc4 abf56631
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -17,7 +17,9 @@

package com.android.packageinstaller;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -38,6 +40,7 @@ import java.util.List;
 * This is a utility class for defining some utility methods and constants
 * used in the package installer application.
 */
@SuppressLint("NewApi")
public class PackageUtil {
    public static final String PREFIX="com.android.packageinstaller.";
    public static final String INTENT_ATTR_INSTALL_STATUS = PREFIX+"installStatus";
@@ -74,7 +77,7 @@ public class PackageUtil {
     * @param componentInfo ComponentInfo object whose resources are to be loaded
     * @param snippetView the snippet view
     */
    public static View initSnippetForInstalledApp(Activity pContext,
    public static View initSnippetForInstalledApp(Context pContext,
            ApplicationInfo appInfo, View snippetView) {
        return initSnippetForInstalledApp(pContext, appInfo, snippetView, null);
    }
@@ -90,7 +93,7 @@ public class PackageUtil {
     * @param snippetView the snippet view
     * @param UserHandle user that the app si installed for.
     */
    public static View initSnippetForInstalledApp(Activity pContext,
    public static View initSnippetForInstalledApp(Context pContext,
            ApplicationInfo appInfo, View snippetView, UserHandle user) {
        final PackageManager pm = pContext.getPackageManager();
        Drawable icon = appInfo.loadIcon(pm);
+188 −200
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
*/
package com.android.packageinstaller;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.admin.IDevicePolicyManager;
import android.content.Context;
@@ -27,7 +28,6 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
@@ -38,17 +38,14 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.util.Log;
import android.util.TypedValue;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.android.packageinstaller.handheld.UninstallAppProgressFragment;

import java.lang.ref.WeakReference;
import java.util.List;

/**
@@ -58,17 +55,16 @@ import java.util.List;
 * by an intent with the intent's class name explicitly set to UninstallAppProgress and expects
 * the application object of the application to uninstall.
 */
public class UninstallAppProgress extends Activity implements OnClickListener {
    private final String TAG="UninstallAppProgress";
@SuppressLint("NewApi")
public class UninstallAppProgress extends Activity {
    private static final String TAG = "UninstallAppProgress";

    private static final String FRAGMENT_TAG = "progress_fragment";

    private ApplicationInfo mAppInfo;
    private boolean mAllUsers;
    private UserHandle mUser;
    private IBinder mCallback;

    private Button mOkButton;
    private Button mDeviceManagerButton;
    private Button mUsersButton;
    private volatile int mResultCode = -1;

    /**
@@ -83,16 +79,25 @@ public class UninstallAppProgress extends Activity implements OnClickListener {
    private static final int UNINSTALL_COMPLETE = 1;
    private static final int UNINSTALL_IS_SLOW = 2;

    private boolean isProfileOfOrSame(UserManager userManager, int userId, int profileId) {
        if (userId == profileId) {
            return true;
        }
        UserInfo parentUser = userManager.getProfileParent(profileId);
        return parentUser != null && parentUser.id == userId;
    private Handler mHandler = new MessageHandler(this);

    private static class MessageHandler extends Handler {
        private final WeakReference<UninstallAppProgress> mActivity;

        public MessageHandler(UninstallAppProgress activity) {
            mActivity = new WeakReference<>(activity);
        }

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            UninstallAppProgress activity = mActivity.get();
            if (activity != null) {
                activity.handleMessage(msg);
            }
        }
    }

    private void handleMessage(Message msg) {
        if (isFinishing() || isDestroyed()) {
            return;
        }
@@ -141,7 +146,7 @@ public class UninstallAppProgress extends Activity implements OnClickListener {
                        // Show a Toast and finish the activity
                        Context ctx = getBaseContext();
                        Toast.makeText(ctx, statusText, Toast.LENGTH_LONG).show();
                            setResultAndFinish(mResultCode);
                        setResultAndFinish();
                        return;
                    case PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER: {
                        UserManager userManager =
@@ -168,13 +173,13 @@ public class UninstallAppProgress extends Activity implements OnClickListener {
                        if (otherBlockingUser == null) {
                            Log.d(TAG, "Uninstall failed because " + packageName
                                    + " is a device admin");
                                mDeviceManagerButton.setVisibility(View.VISIBLE);
                            getProgressFragment().setDeviceManagerButtonVisible(true);
                            statusText = getString(
                                    R.string.uninstall_failed_device_policy_manager);
                        } else {
                            Log.d(TAG, "Uninstall failed because " + packageName
                                    + " is a device admin of user " + otherBlockingUser);
                                mDeviceManagerButton.setVisibility(View.GONE);
                            getProgressFragment().setDeviceManagerButtonVisible(false);
                            statusText = String.format(
                                    getString(R.string.uninstall_failed_device_policy_manager_of_user),
                                    otherBlockingUser.name);
@@ -203,10 +208,10 @@ public class UninstallAppProgress extends Activity implements OnClickListener {
                        }
                        int myUserId = UserHandle.myUserId();
                        if (isProfileOfOrSame(userManager, myUserId, blockingUserId)) {
                                mDeviceManagerButton.setVisibility(View.VISIBLE);
                            getProgressFragment().setDeviceManagerButtonVisible(true);
                        } else {
                                mDeviceManagerButton.setVisibility(View.GONE);
                                mUsersButton.setVisibility(View.VISIBLE);
                            getProgressFragment().setDeviceManagerButtonVisible(false);
                            getProgressFragment().setUsersButtonVisible(true);
                        }
                        // TODO: b/25442806
                        if (blockingUserId == UserHandle.USER_SYSTEM) {
@@ -228,16 +233,20 @@ public class UninstallAppProgress extends Activity implements OnClickListener {
                        statusText = getString(R.string.uninstall_failed);
                        break;
                }
                    findViewById(R.id.progress_view).setVisibility(View.GONE);
                    findViewById(R.id.status_view).setVisibility(View.VISIBLE);
                    ((TextView)findViewById(R.id.status_text)).setText(statusText);
                    findViewById(R.id.ok_panel).setVisibility(View.VISIBLE);
                getProgressFragment().showCompletion(statusText);
                break;
            default:
                break;
        }
    }
    };

    private boolean isProfileOfOrSame(UserManager userManager, int userId, int profileId) {
        if (userId == profileId) {
            return true;
        }
        UserInfo parentUser = userManager.getProfileParent(profileId);
        return parentUser != null && parentUser.id == userId;
    }

    @Override
    public void onCreate(Bundle icicle) {
@@ -261,7 +270,7 @@ public class UninstallAppProgress extends Activity implements OnClickListener {
                }
                finish();
            } else {
                setResultAndFinish(mResultCode);
                setResultAndFinish();
            }

            return;
@@ -271,15 +280,15 @@ public class UninstallAppProgress extends Activity implements OnClickListener {
        if (mAllUsers && !UserManager.get(this).isAdminUser()) {
            throw new SecurityException("Only admin user can request uninstall for all users");
        }
        mUser = intent.getParcelableExtra(Intent.EXTRA_USER);
        if (mUser == null) {
            mUser = android.os.Process.myUserHandle();
        UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
        if (user == null) {
            user = android.os.Process.myUserHandle();
        } else {
            UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
            List<UserHandle> profiles = userManager.getUserProfiles();
            if (!profiles.contains(mUser)) {
            if (!profiles.contains(user)) {
                throw new SecurityException("User " + android.os.Process.myUserHandle() + " can't "
                        + "request uninstall for user " + mUser);
                        + "request uninstall for user " + user);
            }
        }

@@ -293,13 +302,17 @@ public class UninstallAppProgress extends Activity implements OnClickListener {
        getWindow().setNavigationBarColor(Color.TRANSPARENT);

        getPackageManager().deletePackageAsUser(mAppInfo.packageName, observer,
                mAllUsers ? PackageManager.DELETE_ALL_USERS : 0, mUser.getIdentifier());
                mAllUsers ? PackageManager.DELETE_ALL_USERS : 0, user.getIdentifier());

        mHandler.sendMessageDelayed(mHandler.obtainMessage(UNINSTALL_IS_SLOW),
                QUICK_INSTALL_DELAY_MILLIS);
    }

    class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
    public ApplicationInfo getAppInfo() {
        return mAppInfo;
    }

    private class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
        public void packageDeleted(String packageName, int returnCode) {
            Message msg = mHandler.obtainMessage(UNINSTALL_COMPLETE);
            msg.arg1 = returnCode;
@@ -308,12 +321,12 @@ public class UninstallAppProgress extends Activity implements OnClickListener {
        }
    }

    void setResultAndFinish(int retCode) {
        setResult(retCode);
    public void setResultAndFinish() {
        setResult(mResultCode);
        finish();
    }

    public void initView() {
    private void initView() {
        if (mIsViewInitialized) {
            return;
        }
@@ -339,44 +352,9 @@ public class UninstallAppProgress extends Activity implements OnClickListener {
        boolean isUpdate = ((mAppInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
        setTitle(isUpdate ? R.string.uninstall_update_title : R.string.uninstall_application_title);

        setContentView(R.layout.uninstall_progress);
        // Initialize views
        View snippetView = findViewById(R.id.app_snippet);
        PackageUtil.initSnippetForInstalledApp(this, mAppInfo, snippetView);
        mDeviceManagerButton = (Button) findViewById(R.id.device_manager_button);
        mUsersButton = (Button) findViewById(R.id.users_button);
        mDeviceManagerButton.setVisibility(View.GONE);
        mDeviceManagerButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setClassName("com.android.settings",
                        "com.android.settings.Settings$DeviceAdminSettingsActivity");
                intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(intent);
                finish();
            }
        });
        mUsersButton.setVisibility(View.GONE);
        mUsersButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(Settings.ACTION_USER_SETTINGS);
                intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(intent);
                finish();
            }
        });
        // Hide button till progress is being displayed
        mOkButton = (Button) findViewById(R.id.ok_button);
        mOkButton.setOnClickListener(this);
    }

    public void onClick(View v) {
        if(v == mOkButton) {
            Log.i(TAG, "Finished uninstalling pkg: " + mAppInfo.packageName);
            setResultAndFinish(mResultCode);
        }
        getFragmentManager().beginTransaction()
                .add(android.R.id.content, new UninstallAppProgressFragment(), FRAGMENT_TAG)
                .commitNowAllowingStateLoss();
    }

    @Override
@@ -392,4 +370,14 @@ public class UninstallAppProgress extends Activity implements OnClickListener {
        }
        return super.dispatchKeyEvent(ev);
    }

    private ProgressFragment getProgressFragment() {
        return (ProgressFragment) getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
    }

    public interface ProgressFragment {
        void setUsersButtonVisible(boolean visible);
        void setDeviceManagerButtonVisible(boolean visible);
        void showCompletion(CharSequence statusText);
    }
}
+19 −117
Original line number Diff line number Diff line
@@ -16,14 +16,12 @@
*/
package com.android.packageinstaller;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.ComponentName;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
@@ -31,132 +29,32 @@ import android.content.pm.IPackageDeleteObserver2;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;

import com.android.packageinstaller.handheld.AppNotFoundDialogFragment;
import com.android.packageinstaller.handheld.UninstallAlertDialogFragment;

/*
 * This activity presents UI to uninstall an application. Usually launched with intent
 * Intent.ACTION_UNINSTALL_PKG_COMMAND and attribute
 * com.android.packageinstaller.PackageName set to the application package name
 */
@SuppressLint("NewApi")
public class UninstallerActivity extends Activity {
    private static final String TAG = "UninstallerActivity";

    public static class UninstallAlertDialogFragment extends DialogFragment implements
            DialogInterface.OnClickListener {

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            final PackageManager pm = getActivity().getPackageManager();
            final DialogInfo dialogInfo = ((UninstallerActivity) getActivity()).mDialogInfo;
            final CharSequence appLabel = dialogInfo.appInfo.loadLabel(pm);

            AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getActivity());
            StringBuilder messageBuilder = new StringBuilder();

            // If the Activity label differs from the App label, then make sure the user
            // knows the Activity belongs to the App being uninstalled.
            if (dialogInfo.activityInfo != null) {
                final CharSequence activityLabel = dialogInfo.activityInfo.loadLabel(pm);
                if (!activityLabel.equals(appLabel)) {
                    messageBuilder.append(
                            getString(R.string.uninstall_activity_text, activityLabel));
                    messageBuilder.append(" ").append(appLabel).append(".\n\n");
                }
            }

            final boolean isUpdate =
                    ((dialogInfo.appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
            UserManager userManager = UserManager.get(getActivity());
            if (isUpdate) {
                if (isSingleUser(userManager)) {
                    messageBuilder.append(getString(R.string.uninstall_update_text));
                } else {
                    messageBuilder.append(getString(R.string.uninstall_update_text_multiuser));
                }
            } else {
                if (dialogInfo.allUsers && !isSingleUser(userManager)) {
                    messageBuilder.append(getString(R.string.uninstall_application_text_all_users));
                } else if (!dialogInfo.user.equals(android.os.Process.myUserHandle())) {
                    UserInfo userInfo = userManager.getUserInfo(dialogInfo.user.getIdentifier());
                    messageBuilder.append(
                            getString(R.string.uninstall_application_text_user, userInfo.name));
                } else {
                    messageBuilder.append(getString(R.string.uninstall_application_text));
                }
            }

            dialogBuilder.setTitle(appLabel);
            dialogBuilder.setIcon(dialogInfo.appInfo.loadIcon(pm));
            dialogBuilder.setPositiveButton(android.R.string.ok, this);
            dialogBuilder.setNegativeButton(android.R.string.cancel, this);
            dialogBuilder.setMessage(messageBuilder.toString());
            return dialogBuilder.create();
        }

        @Override
        public void onClick(DialogInterface dialog, int which) {
            if (which == Dialog.BUTTON_POSITIVE) {
                ((UninstallerActivity) getActivity()).startUninstallProgress();
            } else {
                ((UninstallerActivity) getActivity()).dispatchAborted();
            }
        }

        @Override
        public void onDismiss(DialogInterface dialog) {
            super.onDismiss(dialog);
            if (isAdded()) {
                getActivity().finish();
            }
        }

        /**
         * Returns whether there is only one user on this device, not including
         * the system-only user.
         */
        private boolean isSingleUser(UserManager userManager) {
            final int userCount = userManager.getUserCount();
            return userCount == 1
                    || (UserManager.isSplitSystemUser() && userCount == 2);
        }
    }

    public static class AppNotFoundDialogFragment extends DialogFragment {

        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            return new AlertDialog.Builder(getActivity())
                    .setTitle(R.string.app_not_found_dlg_title)
                    .setMessage(R.string.app_not_found_dlg_text)
                    .setNeutralButton(android.R.string.ok, null)
                    .create();
        }

        @Override
        public void onDismiss(DialogInterface dialog) {
            super.onDismiss(dialog);
            if (isAdded()) {
                ((UninstallerActivity) getActivity()).dispatchAborted();
                getActivity().setResult(Activity.RESULT_FIRST_USER);
                getActivity().finish();
            }
        }
    }

    static class DialogInfo {
        ApplicationInfo appInfo;
        ActivityInfo activityInfo;
        boolean allUsers;
        UserHandle user;
        IBinder callback;
    public static class DialogInfo {
        public ApplicationInfo appInfo;
        public ActivityInfo activityInfo;
        public boolean allUsers;
        public UserHandle user;
        public IBinder callback;
    }

    private String mPackageName;
@@ -197,7 +95,7 @@ public class UninstallerActivity extends Activity {

        try {
            mDialogInfo.appInfo = pm.getApplicationInfo(mPackageName,
                    PackageManager.GET_UNINSTALLED_PACKAGES, mDialogInfo.user.getIdentifier());
                    PackageManager.MATCH_UNINSTALLED_PACKAGES, mDialogInfo.user.getIdentifier());
        } catch (RemoteException e) {
            Log.e(TAG, "Unable to get packageName. Package manager is dead?");
        }
@@ -224,6 +122,10 @@ public class UninstallerActivity extends Activity {
        showConfirmationDialog();
    }

    public DialogInfo getDialogInfo() {
        return mDialogInfo;
    }

    private void showConfirmationDialog() {
        showDialogFragment(new UninstallAlertDialogFragment());
    }
@@ -241,7 +143,7 @@ public class UninstallerActivity extends Activity {
        fragment.show(ft, "dialog");
    }

    void startUninstallProgress() {
    public void startUninstallProgress() {
        Intent newIntent = new Intent(Intent.ACTION_VIEW);
        newIntent.putExtra(Intent.EXTRA_USER, mDialogInfo.user);
        newIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, mDialogInfo.allUsers);
@@ -255,7 +157,7 @@ public class UninstallerActivity extends Activity {
        startActivity(newIntent);
    }

    void dispatchAborted() {
    public void dispatchAborted() {
        if (mDialogInfo != null && mDialogInfo.callback != null) {
            final IPackageDeleteObserver2 observer = IPackageDeleteObserver2.Stub.asInterface(
                    mDialogInfo.callback);
+51 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 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.packageinstaller.handheld;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
import android.os.Bundle;

import com.android.packageinstaller.R;
import com.android.packageinstaller.UninstallerActivity;

@SuppressLint("NewApi")
public class AppNotFoundDialogFragment extends DialogFragment {

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        return new AlertDialog.Builder(getActivity())
                .setTitle(R.string.app_not_found_dlg_title)
                .setMessage(R.string.app_not_found_dlg_text)
                .setNeutralButton(android.R.string.ok, null)
                .create();
    }

    @Override
    public void onDismiss(DialogInterface dialog) {
        super.onDismiss(dialog);
        if (isAdded()) {
            ((UninstallerActivity) getActivity()).dispatchAborted();
            getActivity().setResult(Activity.RESULT_FIRST_USER);
            getActivity().finish();
        }
    }
}
+113 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading