1/*
2**
3** Copyright 2007, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17package com.android.packageinstaller;
18
19import android.app.Activity;
20import android.app.AlertDialog;
21import android.app.Dialog;
22import android.content.ComponentName;
23import android.content.DialogInterface;
24import android.content.Intent;
25import android.content.pm.ActivityInfo;
26import android.content.pm.ApplicationInfo;
27import android.content.pm.PackageManager;
28import android.content.pm.PackageManager.NameNotFoundException;
29import android.content.pm.ResolveInfo;
30import android.graphics.drawable.Drawable;
31import android.net.Uri;
32import android.os.Bundle;
33import android.util.Log;
34import android.view.LayoutInflater;
35import android.view.View;
36import android.view.View.OnClickListener;
37import android.view.ViewGroup;
38import android.view.Window;
39import android.widget.Button;
40import android.widget.TextView;
41
42import java.util.List;
43
44/*
45 * This activity presents UI to uninstall an application. Usually launched with intent
46 * Intent.ACTION_UNINSTALL_PKG_COMMAND and attribute
47 * com.android.packageinstaller.PackageName set to the application package name
48 */
49public class UninstallerActivity extends Activity implements OnClickListener,
50        DialogInterface.OnCancelListener {
51    private static final String TAG = "UninstallerActivity";
52    private boolean localLOGV = false;
53    PackageManager mPm;
54    private ApplicationInfo mAppInfo;
55    private Button mOk;
56    private Button mCancel;
57
58    // Dialog identifiers used in showDialog
59    private static final int DLG_BASE = 0;
60    private static final int DLG_APP_NOT_FOUND = DLG_BASE + 1;
61    private static final int DLG_UNINSTALL_FAILED = DLG_BASE + 2;
62
63    @Override
64    public Dialog onCreateDialog(int id) {
65        switch (id) {
66        case DLG_APP_NOT_FOUND :
67            return new AlertDialog.Builder(this)
68                    .setTitle(R.string.app_not_found_dlg_title)
69                    .setIcon(com.android.internal.R.drawable.ic_dialog_alert)
70                    .setMessage(R.string.app_not_found_dlg_text)
71                    .setNeutralButton(getString(R.string.dlg_ok),
72                            new DialogInterface.OnClickListener() {
73                                public void onClick(DialogInterface dialog, int which) {
74                                    setResult(Activity.RESULT_FIRST_USER);
75                                    finish();
76                                }})
77                    .create();
78        case DLG_UNINSTALL_FAILED :
79            // Guaranteed not to be null. will default to package name if not set by app
80           CharSequence appTitle = mPm.getApplicationLabel(mAppInfo);
81           String dlgText = getString(R.string.uninstall_failed_msg,
82                    appTitle.toString());
83            // Display uninstall failed dialog
84            return new AlertDialog.Builder(this)
85                    .setTitle(R.string.uninstall_failed)
86                    .setIcon(com.android.internal.R.drawable.ic_dialog_alert)
87                    .setMessage(dlgText)
88                    .setNeutralButton(getString(R.string.dlg_ok),
89                            new DialogInterface.OnClickListener() {
90                                public void onClick(DialogInterface dialog, int which) {
91                                    setResult(Activity.RESULT_FIRST_USER);
92                                    finish();
93                                }})
94                    .create();
95        }
96        return null;
97    }
98
99    private void startUninstallProgress() {
100        Intent newIntent = new Intent(Intent.ACTION_VIEW);
101        newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
102                                                  mAppInfo);
103        if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
104            newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
105            newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
106        }
107        newIntent.setClass(this, UninstallAppProgress.class);
108        startActivity(newIntent);
109        finish();
110    }
111
112    @Override
113    public void onCreate(Bundle icicle) {
114        super.onCreate(icicle);
115        // Get intent information.
116        // We expect an intent with URI of the form package://<packageName>#<className>
117        // className is optional; if specified, it is the activity the user chose to uninstall
118        final Intent intent = getIntent();
119        Uri packageURI = intent.getData();
120        String packageName = packageURI.getEncodedSchemeSpecificPart();
121        if(packageName == null) {
122            Log.e(TAG, "Invalid package name:" + packageName);
123            showDialog(DLG_APP_NOT_FOUND);
124            return;
125        }
126
127        mPm = getPackageManager();
128        boolean errFlag = false;
129        try {
130            mAppInfo = mPm.getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
131        } catch (NameNotFoundException e) {
132            errFlag = true;
133        }
134
135        // The class name may have been specified (e.g. when deleting an app from all apps)
136        String className = packageURI.getFragment();
137        ActivityInfo activityInfo = null;
138        if (className != null) {
139            try {
140                activityInfo = mPm.getActivityInfo(new ComponentName(packageName, className), 0);
141            } catch (NameNotFoundException e) {
142                errFlag = true;
143            }
144        }
145
146        if(mAppInfo == null || errFlag) {
147            Log.e(TAG, "Invalid packageName or componentName in " + packageURI.toString());
148            showDialog(DLG_APP_NOT_FOUND);
149        } else {
150            boolean isUpdate = ((mAppInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
151
152            setContentView(R.layout.uninstall_confirm);
153
154            TextView confirm = (TextView) findViewById(R.id.uninstall_confirm);
155            if (isUpdate) {
156                setTitle(R.string.uninstall_update_title);
157                confirm.setText(R.string.uninstall_update_text);
158            } else {
159                setTitle(R.string.uninstall_application_title);
160                confirm.setText(R.string.uninstall_application_text);
161            }
162
163            // If an activity was specified (e.g. when dragging from All Apps to trash can),
164            // give a bit more info if the activity label isn't the same as the package label.
165            if (activityInfo != null) {
166                CharSequence activityLabel = activityInfo.loadLabel(mPm);
167                if (!activityLabel.equals(mAppInfo.loadLabel(mPm))) {
168                    TextView activityText = (TextView) findViewById(R.id.activity_text);
169                    CharSequence text = getString(R.string.uninstall_activity_text, activityLabel);
170                    activityText.setText(text);
171                    activityText.setVisibility(View.VISIBLE);
172                }
173            }
174
175            View snippetView = findViewById(R.id.uninstall_activity_snippet);
176            PackageUtil.initSnippetForInstalledApp(this, mAppInfo, snippetView);
177
178            //initialize ui elements
179            mOk = (Button)findViewById(R.id.ok_button);
180            mCancel = (Button)findViewById(R.id.cancel_button);
181            mOk.setOnClickListener(this);
182            mCancel.setOnClickListener(this);
183        }
184    }
185
186    public void onClick(View v) {
187        if(v == mOk) {
188            //initiate next screen
189            startUninstallProgress();
190        } else if(v == mCancel) {
191            finish();
192        }
193    }
194
195    public void onCancel(DialogInterface dialog) {
196        finish();
197    }
198}
199