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.ActivityManagerNative;
21import android.app.AlertDialog;
22import android.app.Dialog;
23import android.content.Context;
24import android.content.DialogInterface;
25import android.content.DialogInterface.OnCancelListener;
26import android.content.Intent;
27import android.content.SharedPreferences;
28import android.content.pm.ApplicationInfo;
29import android.content.pm.ManifestDigest;
30import android.content.pm.PackageInfo;
31import android.content.pm.PackageManager;
32import android.content.pm.PackageManager.NameNotFoundException;
33import android.content.pm.PackageParser;
34import android.content.pm.PackageUserState;
35import android.content.pm.ResolveInfo;
36import android.content.pm.VerificationParams;
37import android.net.Uri;
38import android.os.Bundle;
39import android.os.SystemClock;
40import android.provider.Settings;
41import android.support.v4.view.ViewPager;
42import android.util.EventLog;
43import android.util.Log;
44import android.view.LayoutInflater;
45import android.view.View;
46import android.view.View.OnClickListener;
47import android.view.ViewGroup;
48import android.widget.AppSecurityPermissions;
49import android.widget.Button;
50import android.widget.TabHost;
51import android.widget.TextView;
52
53import java.io.File;
54import java.io.Serializable;
55import java.util.List;
56
57/*
58 * This activity is launched when a new application is installed via side loading
59 * The package is first parsed and the user is notified of parse errors via a dialog.
60 * If the package is successfully parsed, the user is notified to turn on the install unknown
61 * applications setting. A memory check is made at this point and the user is notified of out
62 * of memory conditions if any. If the package is already existing on the device,
63 * a confirmation dialog (to replace the existing package) is presented to the user.
64 * Based on the user response the package is then installed by launching InstallAppConfirm
65 * sub activity. All state transitions are handled in this activity
66 */
67public class PackageInstallerActivity extends Activity implements OnCancelListener, OnClickListener {
68    private static final String TAG = "PackageInstaller";
69    private Uri mPackageURI;
70    private Uri mOriginatingURI;
71    private Uri mReferrerURI;
72    private int mOriginatingUid = VerificationParams.NO_UID;
73    private ManifestDigest mPkgDigest;
74
75    private boolean localLOGV = false;
76    PackageManager mPm;
77    PackageInfo mPkgInfo;
78    ApplicationInfo mSourceInfo;
79
80    // ApplicationInfo object primarily used for already existing applications
81    private ApplicationInfo mAppInfo = null;
82
83    private InstallFlowAnalytics mInstallFlowAnalytics;
84
85    // View for install progress
86    View mInstallConfirm;
87    // Buttons to indicate user acceptance
88    private Button mOk;
89    private Button mCancel;
90    CaffeinatedScrollView mScrollView = null;
91    private boolean mOkCanInstall = false;
92
93    static final String PREFS_ALLOWED_SOURCES = "allowed_sources";
94
95    private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
96
97    private static final String TAB_ID_ALL = "all";
98    private static final String TAB_ID_NEW = "new";
99
100    // Dialog identifiers used in showDialog
101    private static final int DLG_BASE = 0;
102    private static final int DLG_UNKNOWN_APPS = DLG_BASE + 1;
103    private static final int DLG_PACKAGE_ERROR = DLG_BASE + 2;
104    private static final int DLG_OUT_OF_SPACE = DLG_BASE + 3;
105    private static final int DLG_INSTALL_ERROR = DLG_BASE + 4;
106    private static final int DLG_ALLOW_SOURCE = DLG_BASE + 5;
107
108    private void startInstallConfirm() {
109        TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost);
110        tabHost.setup();
111        ViewPager viewPager = (ViewPager)findViewById(R.id.pager);
112        TabsAdapter adapter = new TabsAdapter(this, tabHost, viewPager);
113        adapter.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
114            @Override
115            public void onTabChanged(String tabId) {
116                if (TAB_ID_ALL.equals(tabId)) {
117                    mInstallFlowAnalytics.setAllPermissionsDisplayed(true);
118                } else if (TAB_ID_NEW.equals(tabId)) {
119                    mInstallFlowAnalytics.setNewPermissionsDisplayed(true);
120                }
121            }
122        });
123
124        boolean permVisible = false;
125        mScrollView = null;
126        mOkCanInstall = false;
127        int msg = 0;
128        if (mPkgInfo != null) {
129            AppSecurityPermissions perms = new AppSecurityPermissions(this, mPkgInfo);
130            final int NP = perms.getPermissionCount(AppSecurityPermissions.WHICH_PERSONAL);
131            final int ND = perms.getPermissionCount(AppSecurityPermissions.WHICH_DEVICE);
132            if (mAppInfo != null) {
133                msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
134                        ? R.string.install_confirm_question_update_system
135                        : R.string.install_confirm_question_update;
136                mScrollView = new CaffeinatedScrollView(this);
137                mScrollView.setFillViewport(true);
138                boolean newPermissionsFound =
139                        (perms.getPermissionCount(AppSecurityPermissions.WHICH_NEW) > 0);
140                mInstallFlowAnalytics.setNewPermissionsFound(newPermissionsFound);
141                if (newPermissionsFound) {
142                    permVisible = true;
143                    mScrollView.addView(perms.getPermissionsView(
144                            AppSecurityPermissions.WHICH_NEW));
145                } else {
146                    LayoutInflater inflater = (LayoutInflater)getSystemService(
147                            Context.LAYOUT_INFLATER_SERVICE);
148                    TextView label = (TextView)inflater.inflate(R.layout.label, null);
149                    label.setText(R.string.no_new_perms);
150                    mScrollView.addView(label);
151                }
152                adapter.addTab(tabHost.newTabSpec(TAB_ID_NEW).setIndicator(
153                        getText(R.string.newPerms)), mScrollView);
154            } else  {
155                findViewById(R.id.tabscontainer).setVisibility(View.GONE);
156                findViewById(R.id.divider).setVisibility(View.VISIBLE);
157            }
158            if (NP > 0 || ND > 0) {
159                permVisible = true;
160                LayoutInflater inflater = (LayoutInflater)getSystemService(
161                        Context.LAYOUT_INFLATER_SERVICE);
162                View root = inflater.inflate(R.layout.permissions_list, null);
163                if (mScrollView == null) {
164                    mScrollView = (CaffeinatedScrollView)root.findViewById(R.id.scrollview);
165                }
166                if (NP > 0) {
167                    ((ViewGroup)root.findViewById(R.id.privacylist)).addView(
168                            perms.getPermissionsView(AppSecurityPermissions.WHICH_PERSONAL));
169                } else {
170                    root.findViewById(R.id.privacylist).setVisibility(View.GONE);
171                }
172                if (ND > 0) {
173                    ((ViewGroup)root.findViewById(R.id.devicelist)).addView(
174                            perms.getPermissionsView(AppSecurityPermissions.WHICH_DEVICE));
175                } else {
176                    root.findViewById(R.id.devicelist).setVisibility(View.GONE);
177                }
178                adapter.addTab(tabHost.newTabSpec(TAB_ID_ALL).setIndicator(
179                        getText(R.string.allPerms)), root);
180            }
181        }
182        mInstallFlowAnalytics.setPermissionsDisplayed(permVisible);
183        if (!permVisible) {
184            if (mAppInfo != null) {
185                // This is an update to an application, but there are no
186                // permissions at all.
187                msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
188                        ? R.string.install_confirm_question_update_system_no_perms
189                        : R.string.install_confirm_question_update_no_perms;
190            } else {
191                // This is a new application with no permissions.
192                msg = R.string.install_confirm_question_no_perms;
193            }
194            tabHost.setVisibility(View.GONE);
195            mInstallFlowAnalytics.setAllPermissionsDisplayed(false);
196            mInstallFlowAnalytics.setNewPermissionsDisplayed(false);
197            findViewById(R.id.filler).setVisibility(View.VISIBLE);
198            findViewById(R.id.divider).setVisibility(View.GONE);
199            mScrollView = null;
200        }
201        if (msg != 0) {
202            ((TextView)findViewById(R.id.install_confirm_question)).setText(msg);
203        }
204        mInstallConfirm.setVisibility(View.VISIBLE);
205        mOk = (Button)findViewById(R.id.ok_button);
206        mCancel = (Button)findViewById(R.id.cancel_button);
207        mOk.setOnClickListener(this);
208        mCancel.setOnClickListener(this);
209        if (mScrollView == null) {
210            // There is nothing to scroll view, so the ok button is immediately
211            // set to install.
212            mOk.setText(R.string.install);
213            mOkCanInstall = true;
214        } else {
215            mScrollView.setFullScrollAction(new Runnable() {
216                @Override
217                public void run() {
218                    mOk.setText(R.string.install);
219                    mOkCanInstall = true;
220                }
221            });
222        }
223    }
224
225    private void showDialogInner(int id) {
226        // TODO better fix for this? Remove dialog so that it gets created again
227        removeDialog(id);
228        showDialog(id);
229    }
230
231    @Override
232    public Dialog onCreateDialog(int id, Bundle bundle) {
233        switch (id) {
234        case DLG_UNKNOWN_APPS:
235            return new AlertDialog.Builder(this)
236                    .setTitle(R.string.unknown_apps_dlg_title)
237                    .setMessage(R.string.unknown_apps_dlg_text)
238                    .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
239                        public void onClick(DialogInterface dialog, int which) {
240                            Log.i(TAG, "Finishing off activity so that user can navigate to settings manually");
241                            finish();
242                        }})
243                    .setPositiveButton(R.string.settings, new DialogInterface.OnClickListener() {
244                        public void onClick(DialogInterface dialog, int which) {
245                            Log.i(TAG, "Launching settings");
246                            launchSettingsAppAndFinish();
247                        }
248                    })
249                    .setOnCancelListener(this)
250                    .create();
251        case DLG_PACKAGE_ERROR :
252            return new AlertDialog.Builder(this)
253                    .setTitle(R.string.Parse_error_dlg_title)
254                    .setMessage(R.string.Parse_error_dlg_text)
255                    .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
256                        public void onClick(DialogInterface dialog, int which) {
257                            finish();
258                        }
259                    })
260                    .setOnCancelListener(this)
261                    .create();
262        case DLG_OUT_OF_SPACE:
263            // Guaranteed not to be null. will default to package name if not set by app
264            CharSequence appTitle = mPm.getApplicationLabel(mPkgInfo.applicationInfo);
265            String dlgText = getString(R.string.out_of_space_dlg_text,
266                    appTitle.toString());
267            return new AlertDialog.Builder(this)
268                    .setTitle(R.string.out_of_space_dlg_title)
269                    .setMessage(dlgText)
270                    .setPositiveButton(R.string.manage_applications, new DialogInterface.OnClickListener() {
271                        public void onClick(DialogInterface dialog, int which) {
272                            //launch manage applications
273                            Intent intent = new Intent("android.intent.action.MANAGE_PACKAGE_STORAGE");
274                            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
275                            startActivity(intent);
276                            finish();
277                        }
278                    })
279                    .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
280                        public void onClick(DialogInterface dialog, int which) {
281                            Log.i(TAG, "Canceling installation");
282                            finish();
283                        }
284                  })
285                  .setOnCancelListener(this)
286                  .create();
287        case DLG_INSTALL_ERROR :
288            // Guaranteed not to be null. will default to package name if not set by app
289            CharSequence appTitle1 = mPm.getApplicationLabel(mPkgInfo.applicationInfo);
290            String dlgText1 = getString(R.string.install_failed_msg,
291                    appTitle1.toString());
292            return new AlertDialog.Builder(this)
293                    .setTitle(R.string.install_failed)
294                    .setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() {
295                        public void onClick(DialogInterface dialog, int which) {
296                            finish();
297                        }
298                    })
299                    .setMessage(dlgText1)
300                    .setOnCancelListener(this)
301                    .create();
302        case DLG_ALLOW_SOURCE:
303            CharSequence appTitle2 = mPm.getApplicationLabel(mSourceInfo);
304            String dlgText2 = getString(R.string.allow_source_dlg_text,
305                    appTitle2.toString());
306            return new AlertDialog.Builder(this)
307                    .setTitle(R.string.allow_source_dlg_title)
308                    .setMessage(dlgText2)
309                    .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
310                        public void onClick(DialogInterface dialog, int which) {
311                            setResult(RESULT_CANCELED);
312                            finish();
313                        }})
314                    .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
315                        public void onClick(DialogInterface dialog, int which) {
316                            SharedPreferences prefs = getSharedPreferences(PREFS_ALLOWED_SOURCES,
317                                    Context.MODE_PRIVATE);
318                            prefs.edit().putBoolean(mSourceInfo.packageName, true).apply();
319                            startInstallConfirm();
320                        }
321                    })
322                    .setOnCancelListener(this)
323                    .create();
324       }
325       return null;
326   }
327
328    private void launchSettingsAppAndFinish() {
329        // Create an intent to launch SettingsTwo activity
330        Intent launchSettingsIntent = new Intent(Settings.ACTION_SECURITY_SETTINGS);
331        launchSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
332        startActivity(launchSettingsIntent);
333        finish();
334    }
335
336    private boolean isInstallingUnknownAppsAllowed() {
337        return Settings.Global.getInt(getContentResolver(),
338            Settings.Global.INSTALL_NON_MARKET_APPS, 0) > 0;
339    }
340
341    private boolean isInstallRequestFromUnknownSource(Intent intent) {
342        String callerPackage = getCallingPackage();
343        if (callerPackage != null && intent.getBooleanExtra(
344                Intent.EXTRA_NOT_UNKNOWN_SOURCE, false)) {
345            try {
346                mSourceInfo = mPm.getApplicationInfo(callerPackage, 0);
347                if (mSourceInfo != null) {
348                    if ((mSourceInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
349                        // Privileged apps are not considered an unknown source.
350                        return false;
351                    }
352                }
353            } catch (NameNotFoundException e) {
354            }
355        }
356
357        return true;
358    }
359
360    private boolean isVerifyAppsEnabled() {
361        return Settings.Global.getInt(getContentResolver(),
362                Settings.Global.PACKAGE_VERIFIER_ENABLE, 1) > 0;
363    }
364
365    private boolean isAppVerifierInstalled() {
366        final PackageManager pm = getPackageManager();
367        final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
368        verification.setType(PACKAGE_MIME_TYPE);
369        verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
370        final List<ResolveInfo> receivers = pm.queryBroadcastReceivers(verification, 0);
371        return (receivers.size() > 0) ? true : false;
372    }
373
374    private void initiateInstall() {
375        String pkgName = mPkgInfo.packageName;
376        // Check if there is already a package on the device with this name
377        // but it has been renamed to something else.
378        String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName });
379        if (oldName != null && oldName.length > 0 && oldName[0] != null) {
380            pkgName = oldName[0];
381            mPkgInfo.packageName = pkgName;
382            mPkgInfo.applicationInfo.packageName = pkgName;
383        }
384        // Check if package is already installed. display confirmation dialog if replacing pkg
385        try {
386            // This is a little convoluted because we want to get all uninstalled
387            // apps, but this may include apps with just data, and if it is just
388            // data we still want to count it as "installed".
389            mAppInfo = mPm.getApplicationInfo(pkgName,
390                    PackageManager.GET_UNINSTALLED_PACKAGES);
391            if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
392                mAppInfo = null;
393            }
394        } catch (NameNotFoundException e) {
395            mAppInfo = null;
396        }
397
398        mInstallFlowAnalytics.setReplace(mAppInfo != null);
399        mInstallFlowAnalytics.setSystemApp(
400                (mAppInfo != null) && ((mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0));
401
402        startInstallConfirm();
403    }
404
405    void setPmResult(int pmResult) {
406        Intent result = new Intent();
407        result.putExtra(Intent.EXTRA_INSTALL_RESULT, pmResult);
408        setResult(pmResult == PackageManager.INSTALL_SUCCEEDED
409                ? RESULT_OK : RESULT_FIRST_USER, result);
410    }
411
412    @Override
413    protected void onCreate(Bundle icicle) {
414        super.onCreate(icicle);
415
416        // get intent information
417        final Intent intent = getIntent();
418        mPackageURI = intent.getData();
419        mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
420        mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
421        mPm = getPackageManager();
422
423        boolean requestFromUnknownSource = isInstallRequestFromUnknownSource(intent);
424        mInstallFlowAnalytics = new InstallFlowAnalytics();
425        mInstallFlowAnalytics.setStartTimestampMillis(SystemClock.elapsedRealtime());
426        mInstallFlowAnalytics.setInstallsFromUnknownSourcesPermitted(
427                isInstallingUnknownAppsAllowed());
428        mInstallFlowAnalytics.setInstallRequestFromUnknownSource(requestFromUnknownSource);
429        mInstallFlowAnalytics.setVerifyAppsEnabled(isVerifyAppsEnabled());
430        mInstallFlowAnalytics.setAppVerifierInstalled(isAppVerifierInstalled());
431
432        final String scheme = mPackageURI.getScheme();
433        if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) {
434            Log.w(TAG, "Unsupported scheme " + scheme);
435            setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI);
436            mInstallFlowAnalytics.setFlowFinished(
437                    InstallFlowAnalytics.RESULT_FAILED_UNSUPPORTED_SCHEME);
438            finish();
439            return;
440        }
441
442        final PackageUtil.AppSnippet as;
443        if ("package".equals(mPackageURI.getScheme())) {
444            mInstallFlowAnalytics.setFileUri(false);
445            try {
446                mPkgInfo = mPm.getPackageInfo(mPackageURI.getSchemeSpecificPart(),
447                        PackageManager.GET_PERMISSIONS | PackageManager.GET_UNINSTALLED_PACKAGES);
448            } catch (NameNotFoundException e) {
449            }
450            if (mPkgInfo == null) {
451                Log.w(TAG, "Requested package " + mPackageURI.getScheme()
452                        + " not available. Discontinuing installation");
453                showDialogInner(DLG_PACKAGE_ERROR);
454                setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
455                mInstallFlowAnalytics.setPackageInfoObtained();
456                mInstallFlowAnalytics.setFlowFinished(
457                        InstallFlowAnalytics.RESULT_FAILED_PACKAGE_MISSING);
458                return;
459            }
460            as = new PackageUtil.AppSnippet(mPm.getApplicationLabel(mPkgInfo.applicationInfo),
461                    mPm.getApplicationIcon(mPkgInfo.applicationInfo));
462        } else {
463            mInstallFlowAnalytics.setFileUri(true);
464            final File sourceFile = new File(mPackageURI.getPath());
465            PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile);
466
467            // Check for parse errors
468            if (parsed == null) {
469                Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation");
470                showDialogInner(DLG_PACKAGE_ERROR);
471                setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
472                mInstallFlowAnalytics.setPackageInfoObtained();
473                mInstallFlowAnalytics.setFlowFinished(
474                        InstallFlowAnalytics.RESULT_FAILED_TO_GET_PACKAGE_INFO);
475                return;
476            }
477            mPkgInfo = PackageParser.generatePackageInfo(parsed, null,
478                    PackageManager.GET_PERMISSIONS, 0, 0, null,
479                    new PackageUserState());
480            mPkgDigest = parsed.manifestDigest;
481            as = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile);
482        }
483        mInstallFlowAnalytics.setPackageInfoObtained();
484
485        //set view
486        setContentView(R.layout.install_start);
487        mInstallConfirm = findViewById(R.id.install_confirm_panel);
488        mInstallConfirm.setVisibility(View.INVISIBLE);
489        PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);
490
491        mOriginatingUid = getOriginatingUid(intent);
492
493        // Block the install attempt on the Unknown Sources setting if necessary.
494        if ((requestFromUnknownSource) && (!isInstallingUnknownAppsAllowed())) {
495            //ask user to enable setting first
496            showDialogInner(DLG_UNKNOWN_APPS);
497            mInstallFlowAnalytics.setFlowFinished(
498                    InstallFlowAnalytics.RESULT_BLOCKED_BY_UNKNOWN_SOURCES_SETTING);
499            return;
500        }
501        initiateInstall();
502    }
503
504    /** Get the ApplicationInfo for the calling package, if available */
505    private ApplicationInfo getSourceInfo() {
506        String callingPackage = getCallingPackage();
507        if (callingPackage != null) {
508            try {
509                return mPm.getApplicationInfo(callingPackage, 0);
510            } catch (NameNotFoundException ex) {
511                // ignore
512            }
513        }
514        return null;
515    }
516
517
518    /** Get the originating uid if possible, or VerificationParams.NO_UID if not available */
519    private int getOriginatingUid(Intent intent) {
520        // The originating uid from the intent. We only trust/use this if it comes from a
521        // system application
522        int uidFromIntent = intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID,
523                VerificationParams.NO_UID);
524
525        // Get the source info from the calling package, if available. This will be the
526        // definitive calling package, but it only works if the intent was started using
527        // startActivityForResult,
528        ApplicationInfo sourceInfo = getSourceInfo();
529        if (sourceInfo != null) {
530            if (uidFromIntent != VerificationParams.NO_UID &&
531                    (mSourceInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
532                return uidFromIntent;
533
534            }
535            // We either didn't get a uid in the intent, or we don't trust it. Use the
536            // uid of the calling package instead.
537            return sourceInfo.uid;
538        }
539
540        // We couldn't get the specific calling package. Let's get the uid instead
541        int callingUid;
542        try {
543            callingUid = ActivityManagerNative.getDefault()
544                    .getLaunchedFromUid(getActivityToken());
545        } catch (android.os.RemoteException ex) {
546            Log.w(TAG, "Could not determine the launching uid.");
547            // nothing else we can do
548            return VerificationParams.NO_UID;
549        }
550
551        // If we got a uid from the intent, we need to verify that the caller is a
552        // privileged system package before we use it
553        if (uidFromIntent != VerificationParams.NO_UID) {
554            String[] callingPackages = mPm.getPackagesForUid(callingUid);
555            if (callingPackages != null) {
556                for (String packageName: callingPackages) {
557                    try {
558                        ApplicationInfo applicationInfo =
559                                mPm.getApplicationInfo(packageName, 0);
560
561                        if ((applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) {
562                            return uidFromIntent;
563                        }
564                    } catch (NameNotFoundException ex) {
565                        // ignore it, and try the next package
566                    }
567                }
568            }
569        }
570        // We either didn't get a uid from the intent, or we don't trust it. Use the
571        // calling uid instead.
572        return callingUid;
573    }
574
575    @Override
576    public void onBackPressed() {
577        mInstallFlowAnalytics.setFlowFinished(
578                InstallFlowAnalytics.RESULT_CANCELLED_BY_USER);
579        super.onBackPressed();
580    }
581
582    // Generic handling when pressing back key
583    public void onCancel(DialogInterface dialog) {
584        finish();
585    }
586
587    public void onClick(View v) {
588        if(v == mOk) {
589            if (mOkCanInstall || mScrollView == null) {
590                // Start subactivity to actually install the application
591                mInstallFlowAnalytics.setInstallButtonClicked();
592                Intent newIntent = new Intent();
593                newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
594                        mPkgInfo.applicationInfo);
595                newIntent.setData(mPackageURI);
596                newIntent.setClass(this, InstallAppProgress.class);
597                newIntent.putExtra(InstallAppProgress.EXTRA_MANIFEST_DIGEST, mPkgDigest);
598                newIntent.putExtra(
599                        InstallAppProgress.EXTRA_INSTALL_FLOW_ANALYTICS, mInstallFlowAnalytics);
600                String installerPackageName = getIntent().getStringExtra(
601                        Intent.EXTRA_INSTALLER_PACKAGE_NAME);
602                if (mOriginatingURI != null) {
603                    newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
604                }
605                if (mReferrerURI != null) {
606                    newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
607                }
608                if (mOriginatingUid != VerificationParams.NO_UID) {
609                    newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
610                }
611                if (installerPackageName != null) {
612                    newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
613                            installerPackageName);
614                }
615                if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
616                    newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
617                    newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
618                }
619                if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
620                startActivity(newIntent);
621                finish();
622            } else {
623                mScrollView.pageScroll(View.FOCUS_DOWN);
624            }
625        } else if(v == mCancel) {
626            // Cancel and finish
627            setResult(RESULT_CANCELED);
628            mInstallFlowAnalytics.setFlowFinished(
629                    InstallFlowAnalytics.RESULT_CANCELLED_BY_USER);
630            finish();
631        }
632    }
633}
634