Home | History | Annotate | Download | only in packageinstaller
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.packageinstaller;
     18 
     19 import android.app.Activity;
     20 import android.app.ActivityThread;
     21 import android.app.AlertDialog;
     22 import android.app.Dialog;
     23 import android.app.DialogFragment;
     24 import android.app.Fragment;
     25 import android.app.FragmentTransaction;
     26 import android.app.PendingIntent;
     27 import android.content.Intent;
     28 import android.content.pm.ApplicationInfo;
     29 import android.content.pm.IPackageDeleteObserver2;
     30 import android.content.pm.PackageInstaller;
     31 import android.content.pm.PackageManager;
     32 import android.content.pm.VersionedPackage;
     33 import android.os.Bundle;
     34 import android.os.IBinder;
     35 import android.os.RemoteException;
     36 import android.os.UserHandle;
     37 import android.support.annotation.Nullable;
     38 import android.widget.Toast;
     39 
     40 /**
     41  * Start an uninstallation, show a dialog while uninstalling and return result to the caller.
     42  */
     43 public class UninstallUninstalling extends Activity implements
     44         EventResultPersister.EventResultObserver {
     45     private static final String UNINSTALL_ID = "com.android.packageinstaller.UNINSTALL_ID";
     46     private static final String BROADCAST_ACTION =
     47             "com.android.packageinstaller.ACTION_UNINSTALL_COMMIT";
     48 
     49     static final String EXTRA_APP_LABEL = "com.android.packageinstaller.extra.APP_LABEL";
     50 
     51     private int mUninstallId;
     52     private ApplicationInfo mAppInfo;
     53     private IBinder mCallback;
     54     private boolean mReturnResult;
     55     private String mLabel;
     56 
     57     @Override
     58     protected void onCreate(@Nullable Bundle savedInstanceState) {
     59         super.onCreate(savedInstanceState);
     60 
     61         setFinishOnTouchOutside(false);
     62 
     63         mAppInfo = getIntent().getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
     64         mCallback = getIntent().getIBinderExtra(PackageInstaller.EXTRA_CALLBACK);
     65         mReturnResult = getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false);
     66         mLabel = getIntent().getStringExtra(EXTRA_APP_LABEL);
     67 
     68         try {
     69             if (savedInstanceState == null) {
     70                 boolean allUsers = getIntent().getBooleanExtra(Intent.EXTRA_UNINSTALL_ALL_USERS,
     71                         false);
     72                 UserHandle user = getIntent().getParcelableExtra(Intent.EXTRA_USER);
     73 
     74                 // Show dialog, which is the whole UI
     75                 FragmentTransaction transaction = getFragmentManager().beginTransaction();
     76                 Fragment prev = getFragmentManager().findFragmentByTag("dialog");
     77                 if (prev != null) {
     78                     transaction.remove(prev);
     79                 }
     80                 DialogFragment dialog = new UninstallUninstallingFragment();
     81                 dialog.setCancelable(false);
     82                 dialog.show(transaction, "dialog");
     83 
     84                 mUninstallId = UninstallEventReceiver.addObserver(this,
     85                         EventResultPersister.GENERATE_NEW_ID, this);
     86 
     87                 Intent broadcastIntent = new Intent(BROADCAST_ACTION);
     88                 broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
     89                 broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mUninstallId);
     90                 broadcastIntent.setPackage(getPackageName());
     91 
     92                 PendingIntent pendingIntent = PendingIntent.getBroadcast(this, mUninstallId,
     93                         broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);
     94 
     95                 try {
     96                     ActivityThread.getPackageManager().getPackageInstaller().uninstall(
     97                             new VersionedPackage(mAppInfo.packageName,
     98                                     PackageManager.VERSION_CODE_HIGHEST),
     99                             getPackageName(), allUsers ? PackageManager.DELETE_ALL_USERS : 0,
    100                             pendingIntent.getIntentSender(), user.getIdentifier());
    101                 } catch (RemoteException e) {
    102                     e.rethrowFromSystemServer();
    103                 }
    104             } else {
    105                 mUninstallId = savedInstanceState.getInt(UNINSTALL_ID);
    106                 UninstallEventReceiver.addObserver(this, mUninstallId, this);
    107             }
    108         } catch (EventResultPersister.OutOfIdsException e) {
    109             onResult(PackageInstaller.STATUS_FAILURE, PackageManager.DELETE_FAILED_INTERNAL_ERROR,
    110                     null);
    111         }
    112     }
    113 
    114     @Override
    115     protected void onSaveInstanceState(Bundle outState) {
    116         super.onSaveInstanceState(outState);
    117 
    118         outState.putInt(UNINSTALL_ID, mUninstallId);
    119     }
    120 
    121     @Override
    122     public void onBackPressed() {
    123         // do nothing
    124     }
    125 
    126     @Override
    127     public void onResult(int status, int legacyStatus, @Nullable String message) {
    128         if (mCallback != null) {
    129             // The caller will be informed about the result via a callback
    130             final IPackageDeleteObserver2 observer = IPackageDeleteObserver2.Stub
    131                     .asInterface(mCallback);
    132             try {
    133                 observer.onPackageDeleted(mAppInfo.packageName, legacyStatus, message);
    134             } catch (RemoteException ignored) {
    135             }
    136         } else if (mReturnResult) {
    137             // The caller will be informed about the result and might decide to display it
    138             Intent result = new Intent();
    139 
    140             result.putExtra(Intent.EXTRA_INSTALL_RESULT, legacyStatus);
    141             setResult(status == PackageInstaller.STATUS_SUCCESS ? Activity.RESULT_OK
    142                     : Activity.RESULT_FIRST_USER, result);
    143         } else {
    144             // This is the rare case that the caller did not ask for the result, but wanted to be
    145             // notified via onActivityResult when the installation finishes
    146             if (status != PackageInstaller.STATUS_SUCCESS) {
    147                 Toast.makeText(this, getString(R.string.uninstall_failed_app, mLabel),
    148                         Toast.LENGTH_LONG).show();
    149             }
    150         }
    151         finish();
    152     }
    153 
    154     @Override
    155     protected void onDestroy() {
    156         UninstallEventReceiver.removeObserver(this, mUninstallId);
    157 
    158         super.onDestroy();
    159     }
    160 
    161     /**
    162      * Dialog that shows that the app is uninstalling.
    163      */
    164     public static class UninstallUninstallingFragment extends DialogFragment {
    165         @Override
    166         public Dialog onCreateDialog(Bundle savedInstanceState) {
    167             AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getActivity());
    168 
    169             dialogBuilder.setCancelable(false);
    170             dialogBuilder.setMessage(getActivity().getString(R.string.uninstalling_app,
    171                     ((UninstallUninstalling) getActivity()).mLabel));
    172 
    173             Dialog dialog = dialogBuilder.create();
    174             dialog.setCanceledOnTouchOutside(false);
    175 
    176             return dialog;
    177         }
    178     }
    179 }
    180