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