Loading AndroidManifest.xml +2 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ <action android:name="android.intent.action.INSTALL_PACKAGE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="file" /> <data android:scheme="content" /> <data android:mimeType="application/vnd.android.package-archive" /> </intent-filter> <intent-filter> Loading @@ -47,6 +48,7 @@ <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="file" /> <data android:scheme="package" /> <data android:scheme="content" /> </intent-filter> <intent-filter> <action android:name="android.content.pm.action.CONFIRM_PERMISSIONS" /> Loading res/drawable/ic_file_download.xml 0 → 100644 +28 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- 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. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> <path android:fillColor="#000000" android:pathData="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z" /> <path android:pathData="M0 0h24v24H0z" /> </vector> res/values/strings.xml +6 −0 Original line number Diff line number Diff line Loading @@ -293,4 +293,10 @@ <!-- Title for the category listing the current permissions used by an app. --> <string name="current_permissions_category">Current permissions</string> <!-- Message that the app to be installed is being staged --> <string name="message_staging">Staging app…</string> <!-- Placeholder for an app name when it is unknown --> <string name="app_name_unknown">Unknown</string> </resources> src/com/android/packageinstaller/PackageInstallerActivity.java +203 −67 Original line number Diff line number Diff line Loading @@ -33,7 +33,9 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageParser; import android.content.pm.PackageUserState; import android.content.pm.VerificationParams; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.UserManager; Loading @@ -46,10 +48,16 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AppSecurityPermissions; import android.widget.Button; import android.widget.ImageView; import android.widget.TabHost; import android.widget.TextView; import com.android.packageinstaller.util.Utils; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /* * This activity is launched when a new application is installed via side loading Loading @@ -65,12 +73,20 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen private static final String TAG = "PackageInstaller"; private static final int REQUEST_ENABLE_UNKNOWN_SOURCES = 1; private static final int REQUEST_INSTALL_PACKAGE = 2; private static final String SCHEME_FILE = "file"; private static final String SCHEME_CONTENT = "content"; private static final String SCHEME_PACKAGE = "package"; private int mSessionId = -1; private Uri mPackageURI; private Uri mOriginatingURI; private Uri mReferrerURI; private int mOriginatingUid = VerificationParams.NO_UID; private File mContentUriApkStagingFile; private AsyncTask<Uri, Void, File> mStagingAsynTask; private boolean localLOGV = false; PackageManager mPm; Loading Loading @@ -108,6 +124,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen private void startInstallConfirm() { TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost); tabHost.setup(); tabHost.setVisibility(View.VISIBLE); ViewPager viewPager = (ViewPager)findViewById(R.id.pager); TabsAdapter adapter = new TabsAdapter(this, tabHost, viewPager); // If the app supports runtime permissions the new permissions will Loading Loading @@ -183,10 +200,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen ((TextView)findViewById(R.id.install_confirm_question)).setText(msg); } mInstallConfirm.setVisibility(View.VISIBLE); mOk = (Button)findViewById(R.id.ok_button); mCancel = (Button)findViewById(R.id.cancel_button); mOk.setOnClickListener(this); mCancel.setOnClickListener(this); mOk.setEnabled(true); if (mScrollView == null) { // There is nothing to scroll view, so the ok button is immediately // set to install. Loading Loading @@ -320,7 +334,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { setResult(RESULT_OK); finish(); clearCachedApkIfNeededAndFinish(); } }) .setOnCancelListener(this) Loading @@ -341,9 +355,8 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen // implement a "allow untrusted source once" feature. if (request == REQUEST_ENABLE_UNKNOWN_SOURCES && result == RESULT_OK) { initiateInstall(); } else { finish(); } clearCachedApkIfNeededAndFinish(); } private boolean isInstallRequestFromUnknownSource(Intent intent) { Loading Loading @@ -430,6 +443,10 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen mUserManager = (UserManager) getSystemService(Context.USER_SERVICE); final Intent intent = getIntent(); mOriginatingUid = getOriginatingUid(intent); final Uri packageUri; if (PackageInstaller.ACTION_CONFIRM_PERMISSIONS.equals(intent.getAction())) { final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1); final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(sessionId); Loading @@ -440,41 +457,78 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen } mSessionId = sessionId; mPackageURI = Uri.fromFile(new File(info.resolvedBaseCodePath)); packageUri = Uri.fromFile(new File(info.resolvedBaseCodePath)); mOriginatingURI = null; mReferrerURI = null; } else { mSessionId = -1; mPackageURI = intent.getData(); packageUri = intent.getData(); mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI); mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER); } final boolean unknownSourcesAllowedByAdmin = isUnknownSourcesAllowedByAdmin(); final boolean unknownSourcesAllowedByUser = isUnknownSourcesEnabled(); if (DeviceUtils.isWear(this)) { showDialogInner(DLG_NOT_SUPPORTED_ON_WEAR); return; } final String scheme = mPackageURI.getScheme(); if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) { Log.w(TAG, "Unsupported scheme " + scheme); setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI); finish(); //set view setContentView(R.layout.install_start); mInstallConfirm = findViewById(R.id.install_confirm_panel); mInstallConfirm.setVisibility(View.INVISIBLE); mOk = (Button)findViewById(R.id.ok_button); mCancel = (Button)findViewById(R.id.cancel_button); mOk.setOnClickListener(this); mCancel.setOnClickListener(this); // Block the install attempt on the Unknown Sources setting if necessary. final boolean requestFromUnknownSource = isInstallRequestFromUnknownSource(intent); if (!requestFromUnknownSource) { initiateInstall(); return; } // If the admin prohibits it, or we're running in a managed profile, just show error // and exit. Otherwise show an option to take the user to Settings to change the setting. final boolean isManagedProfile = mUserManager.isManagedProfile(); if (!isUnknownSourcesAllowedByAdmin()) { startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS)); clearCachedApkIfNeededAndFinish(); } else if (!isUnknownSourcesEnabled() && isManagedProfile) { showDialogInner(DLG_ADMIN_RESTRICTS_UNKNOWN_SOURCES); } else if (!isUnknownSourcesEnabled()) { // Ask user to enable setting first showDialogInner(DLG_UNKNOWN_SOURCES); } processPackageUri(packageUri); } @Override protected void onDestroy() { if (mStagingAsynTask != null) { mStagingAsynTask.cancel(true); mStagingAsynTask = null; } super.onDestroy(); } private void processPackageUri(final Uri packageUri) { mPackageURI = packageUri; final String scheme = packageUri.getScheme(); final PackageUtil.AppSnippet as; if ("package".equals(mPackageURI.getScheme())) { switch (scheme) { case SCHEME_PACKAGE: { try { mPkgInfo = mPm.getPackageInfo(mPackageURI.getSchemeSpecificPart(), PackageManager.GET_PERMISSIONS | PackageManager.GET_UNINSTALLED_PACKAGES); mPkgInfo = mPm.getPackageInfo(packageUri.getSchemeSpecificPart(), PackageManager.GET_PERMISSIONS | PackageManager.GET_UNINSTALLED_PACKAGES); } catch (NameNotFoundException e) { } if (mPkgInfo == null) { Log.w(TAG, "Requested package " + mPackageURI.getScheme() Log.w(TAG, "Requested package " + packageUri.getScheme() + " not available. Discontinuing installation"); showDialogInner(DLG_PACKAGE_ERROR); setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK); Loading @@ -482,8 +536,10 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen } as = new PackageUtil.AppSnippet(mPm.getApplicationLabel(mPkgInfo.applicationInfo), mPm.getApplicationIcon(mPkgInfo.applicationInfo)); } else { final File sourceFile = new File(mPackageURI.getPath()); } break; case SCHEME_FILE: { File sourceFile = new File(packageUri.getPath()); PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile); // Check for parse errors Loading @@ -497,38 +553,26 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen PackageManager.GET_PERMISSIONS, 0, 0, null, new PackageUserState()); as = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile); } //set view setContentView(R.layout.install_start); mInstallConfirm = findViewById(R.id.install_confirm_panel); mInstallConfirm.setVisibility(View.INVISIBLE); PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet); } break; mOriginatingUid = getOriginatingUid(intent); case SCHEME_CONTENT: { mStagingAsynTask = new StagingAsyncTask(); mStagingAsynTask.execute(packageUri); return; } // Block the install attempt on the Unknown Sources setting if necessary. final boolean requestFromUnknownSource = isInstallRequestFromUnknownSource(intent); if (!requestFromUnknownSource) { initiateInstall(); default: { Log.w(TAG, "Unsupported scheme " + scheme); setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI); clearCachedApkIfNeededAndFinish(); return; } } PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet); // If the admin prohibits it, or we're running in a managed profile, just show error // and exit. Otherwise show an option to take the user to Settings to change the setting. final boolean isManagedProfile = mUserManager.isManagedProfile(); if (!unknownSourcesAllowedByAdmin) { startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS)); finish(); } else if (!unknownSourcesAllowedByUser && isManagedProfile) { showDialogInner(DLG_ADMIN_RESTRICTS_UNKNOWN_SOURCES); } else if (!unknownSourcesAllowedByUser) { // Ask user to enable setting first showDialogInner(DLG_UNKNOWN_SOURCES); } else { initiateInstall(); } } /** Get the ApplicationInfo for the calling package, if available */ private ApplicationInfo getSourceInfo() { Loading Loading @@ -612,7 +656,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen // Generic handling when pressing back key public void onCancel(DialogInterface dialog) { finish(); clearCachedApkIfNeededAndFinish(); } public void onClick(View v) { Loading @@ -620,7 +664,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen if (mOkCanInstall || mScrollView == null) { if (mSessionId != -1) { mInstaller.setPermissionsResult(mSessionId, true); finish(); clearCachedApkIfNeededAndFinish(); } else { startInstall(); } Loading @@ -633,7 +677,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen if (mSessionId != -1) { mInstaller.setPermissionsResult(mSessionId, false); } finish(); clearCachedApkIfNeededAndFinish(); } } Loading Loading @@ -664,7 +708,99 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); } if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI); startActivity(newIntent); startActivityForResult(newIntent, REQUEST_INSTALL_PACKAGE); } private void clearCachedApkIfNeededAndFinish() { if (mContentUriApkStagingFile != null) { mContentUriApkStagingFile.delete(); mContentUriApkStagingFile = null; } finish(); } private final class StagingAsyncTask extends AsyncTask<Uri, Void, File> { private static final long SHOW_EMPTY_STATE_DELAY_MILLIS = 300; private final Runnable mEmptyStateRunnable = new Runnable() { @Override public void run() { ((TextView) findViewById(R.id.app_name)).setText(R.string.app_name_unknown); ((TextView) findViewById(R.id.install_confirm_question)) .setText(R.string.message_staging); mInstallConfirm.setVisibility(View.VISIBLE); findViewById(android.R.id.tabhost).setVisibility(View.INVISIBLE); findViewById(R.id.ok_button).setEnabled(false); Drawable icon = getDrawable(R.drawable.ic_file_download); Utils.applyTint(PackageInstallerActivity.this, icon, android.R.attr.colorControlNormal); ((ImageView) findViewById(R.id.app_icon)).setImageDrawable(icon); } }; @Override protected void onPreExecute() { getWindow().getDecorView().postDelayed(mEmptyStateRunnable, SHOW_EMPTY_STATE_DELAY_MILLIS); } @Override protected File doInBackground(Uri... params) { if (params == null || params.length <= 0) { return null; } Uri packageUri = params[0]; File sourceFile = null; try { sourceFile = File.createTempFile("package", ".apk", getCacheDir()); try ( InputStream in = getContentResolver().openInputStream(packageUri); OutputStream out = (in != null) ? new FileOutputStream( sourceFile) : null; ) { // Despite the comments in ContentResolver#openInputStream // the returned stream can be null. if (in == null) { return null; } byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { // Be nice and respond to a cancellation if (isCancelled()) { return null; } out.write(buffer, 0, bytesRead); } } } catch (IOException ioe) { Log.w(TAG, "Error staging apk from content URI", ioe); if (sourceFile != null) { sourceFile.delete(); } } return sourceFile; } @Override protected void onPostExecute(File file) { getWindow().getDecorView().removeCallbacks(mEmptyStateRunnable); if (isFinishing() || isDestroyed()) { return; } if (file == null) { showDialogInner(DLG_PACKAGE_ERROR); setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK); return; } mContentUriApkStagingFile = file; Uri fileUri = Uri.fromFile(file); processPackageUri(fileUri); } @Override protected void onCancelled(File file) { getWindow().getDecorView().removeCallbacks(mEmptyStateRunnable); } }; } src/com/android/packageinstaller/permission/model/PermissionApps.java +1 −1 Original line number Diff line number Diff line Loading @@ -32,7 +32,7 @@ import android.util.Log; import android.util.SparseArray; import com.android.packageinstaller.R; import com.android.packageinstaller.permission.utils.Utils; import com.android.packageinstaller.util.Utils; import java.util.ArrayList; import java.util.Collections; Loading Loading
AndroidManifest.xml +2 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ <action android:name="android.intent.action.INSTALL_PACKAGE" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="file" /> <data android:scheme="content" /> <data android:mimeType="application/vnd.android.package-archive" /> </intent-filter> <intent-filter> Loading @@ -47,6 +48,7 @@ <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="file" /> <data android:scheme="package" /> <data android:scheme="content" /> </intent-filter> <intent-filter> <action android:name="android.content.pm.action.CONFIRM_PERMISSIONS" /> Loading
res/drawable/ic_file_download.xml 0 → 100644 +28 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- 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. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> <path android:fillColor="#000000" android:pathData="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z" /> <path android:pathData="M0 0h24v24H0z" /> </vector>
res/values/strings.xml +6 −0 Original line number Diff line number Diff line Loading @@ -293,4 +293,10 @@ <!-- Title for the category listing the current permissions used by an app. --> <string name="current_permissions_category">Current permissions</string> <!-- Message that the app to be installed is being staged --> <string name="message_staging">Staging app…</string> <!-- Placeholder for an app name when it is unknown --> <string name="app_name_unknown">Unknown</string> </resources>
src/com/android/packageinstaller/PackageInstallerActivity.java +203 −67 Original line number Diff line number Diff line Loading @@ -33,7 +33,9 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageParser; import android.content.pm.PackageUserState; import android.content.pm.VerificationParams; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.UserManager; Loading @@ -46,10 +48,16 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AppSecurityPermissions; import android.widget.Button; import android.widget.ImageView; import android.widget.TabHost; import android.widget.TextView; import com.android.packageinstaller.util.Utils; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /* * This activity is launched when a new application is installed via side loading Loading @@ -65,12 +73,20 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen private static final String TAG = "PackageInstaller"; private static final int REQUEST_ENABLE_UNKNOWN_SOURCES = 1; private static final int REQUEST_INSTALL_PACKAGE = 2; private static final String SCHEME_FILE = "file"; private static final String SCHEME_CONTENT = "content"; private static final String SCHEME_PACKAGE = "package"; private int mSessionId = -1; private Uri mPackageURI; private Uri mOriginatingURI; private Uri mReferrerURI; private int mOriginatingUid = VerificationParams.NO_UID; private File mContentUriApkStagingFile; private AsyncTask<Uri, Void, File> mStagingAsynTask; private boolean localLOGV = false; PackageManager mPm; Loading Loading @@ -108,6 +124,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen private void startInstallConfirm() { TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost); tabHost.setup(); tabHost.setVisibility(View.VISIBLE); ViewPager viewPager = (ViewPager)findViewById(R.id.pager); TabsAdapter adapter = new TabsAdapter(this, tabHost, viewPager); // If the app supports runtime permissions the new permissions will Loading Loading @@ -183,10 +200,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen ((TextView)findViewById(R.id.install_confirm_question)).setText(msg); } mInstallConfirm.setVisibility(View.VISIBLE); mOk = (Button)findViewById(R.id.ok_button); mCancel = (Button)findViewById(R.id.cancel_button); mOk.setOnClickListener(this); mCancel.setOnClickListener(this); mOk.setEnabled(true); if (mScrollView == null) { // There is nothing to scroll view, so the ok button is immediately // set to install. Loading Loading @@ -320,7 +334,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { setResult(RESULT_OK); finish(); clearCachedApkIfNeededAndFinish(); } }) .setOnCancelListener(this) Loading @@ -341,9 +355,8 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen // implement a "allow untrusted source once" feature. if (request == REQUEST_ENABLE_UNKNOWN_SOURCES && result == RESULT_OK) { initiateInstall(); } else { finish(); } clearCachedApkIfNeededAndFinish(); } private boolean isInstallRequestFromUnknownSource(Intent intent) { Loading Loading @@ -430,6 +443,10 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen mUserManager = (UserManager) getSystemService(Context.USER_SERVICE); final Intent intent = getIntent(); mOriginatingUid = getOriginatingUid(intent); final Uri packageUri; if (PackageInstaller.ACTION_CONFIRM_PERMISSIONS.equals(intent.getAction())) { final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1); final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(sessionId); Loading @@ -440,41 +457,78 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen } mSessionId = sessionId; mPackageURI = Uri.fromFile(new File(info.resolvedBaseCodePath)); packageUri = Uri.fromFile(new File(info.resolvedBaseCodePath)); mOriginatingURI = null; mReferrerURI = null; } else { mSessionId = -1; mPackageURI = intent.getData(); packageUri = intent.getData(); mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI); mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER); } final boolean unknownSourcesAllowedByAdmin = isUnknownSourcesAllowedByAdmin(); final boolean unknownSourcesAllowedByUser = isUnknownSourcesEnabled(); if (DeviceUtils.isWear(this)) { showDialogInner(DLG_NOT_SUPPORTED_ON_WEAR); return; } final String scheme = mPackageURI.getScheme(); if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) { Log.w(TAG, "Unsupported scheme " + scheme); setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI); finish(); //set view setContentView(R.layout.install_start); mInstallConfirm = findViewById(R.id.install_confirm_panel); mInstallConfirm.setVisibility(View.INVISIBLE); mOk = (Button)findViewById(R.id.ok_button); mCancel = (Button)findViewById(R.id.cancel_button); mOk.setOnClickListener(this); mCancel.setOnClickListener(this); // Block the install attempt on the Unknown Sources setting if necessary. final boolean requestFromUnknownSource = isInstallRequestFromUnknownSource(intent); if (!requestFromUnknownSource) { initiateInstall(); return; } // If the admin prohibits it, or we're running in a managed profile, just show error // and exit. Otherwise show an option to take the user to Settings to change the setting. final boolean isManagedProfile = mUserManager.isManagedProfile(); if (!isUnknownSourcesAllowedByAdmin()) { startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS)); clearCachedApkIfNeededAndFinish(); } else if (!isUnknownSourcesEnabled() && isManagedProfile) { showDialogInner(DLG_ADMIN_RESTRICTS_UNKNOWN_SOURCES); } else if (!isUnknownSourcesEnabled()) { // Ask user to enable setting first showDialogInner(DLG_UNKNOWN_SOURCES); } processPackageUri(packageUri); } @Override protected void onDestroy() { if (mStagingAsynTask != null) { mStagingAsynTask.cancel(true); mStagingAsynTask = null; } super.onDestroy(); } private void processPackageUri(final Uri packageUri) { mPackageURI = packageUri; final String scheme = packageUri.getScheme(); final PackageUtil.AppSnippet as; if ("package".equals(mPackageURI.getScheme())) { switch (scheme) { case SCHEME_PACKAGE: { try { mPkgInfo = mPm.getPackageInfo(mPackageURI.getSchemeSpecificPart(), PackageManager.GET_PERMISSIONS | PackageManager.GET_UNINSTALLED_PACKAGES); mPkgInfo = mPm.getPackageInfo(packageUri.getSchemeSpecificPart(), PackageManager.GET_PERMISSIONS | PackageManager.GET_UNINSTALLED_PACKAGES); } catch (NameNotFoundException e) { } if (mPkgInfo == null) { Log.w(TAG, "Requested package " + mPackageURI.getScheme() Log.w(TAG, "Requested package " + packageUri.getScheme() + " not available. Discontinuing installation"); showDialogInner(DLG_PACKAGE_ERROR); setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK); Loading @@ -482,8 +536,10 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen } as = new PackageUtil.AppSnippet(mPm.getApplicationLabel(mPkgInfo.applicationInfo), mPm.getApplicationIcon(mPkgInfo.applicationInfo)); } else { final File sourceFile = new File(mPackageURI.getPath()); } break; case SCHEME_FILE: { File sourceFile = new File(packageUri.getPath()); PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile); // Check for parse errors Loading @@ -497,38 +553,26 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen PackageManager.GET_PERMISSIONS, 0, 0, null, new PackageUserState()); as = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile); } //set view setContentView(R.layout.install_start); mInstallConfirm = findViewById(R.id.install_confirm_panel); mInstallConfirm.setVisibility(View.INVISIBLE); PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet); } break; mOriginatingUid = getOriginatingUid(intent); case SCHEME_CONTENT: { mStagingAsynTask = new StagingAsyncTask(); mStagingAsynTask.execute(packageUri); return; } // Block the install attempt on the Unknown Sources setting if necessary. final boolean requestFromUnknownSource = isInstallRequestFromUnknownSource(intent); if (!requestFromUnknownSource) { initiateInstall(); default: { Log.w(TAG, "Unsupported scheme " + scheme); setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI); clearCachedApkIfNeededAndFinish(); return; } } PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet); // If the admin prohibits it, or we're running in a managed profile, just show error // and exit. Otherwise show an option to take the user to Settings to change the setting. final boolean isManagedProfile = mUserManager.isManagedProfile(); if (!unknownSourcesAllowedByAdmin) { startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS)); finish(); } else if (!unknownSourcesAllowedByUser && isManagedProfile) { showDialogInner(DLG_ADMIN_RESTRICTS_UNKNOWN_SOURCES); } else if (!unknownSourcesAllowedByUser) { // Ask user to enable setting first showDialogInner(DLG_UNKNOWN_SOURCES); } else { initiateInstall(); } } /** Get the ApplicationInfo for the calling package, if available */ private ApplicationInfo getSourceInfo() { Loading Loading @@ -612,7 +656,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen // Generic handling when pressing back key public void onCancel(DialogInterface dialog) { finish(); clearCachedApkIfNeededAndFinish(); } public void onClick(View v) { Loading @@ -620,7 +664,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen if (mOkCanInstall || mScrollView == null) { if (mSessionId != -1) { mInstaller.setPermissionsResult(mSessionId, true); finish(); clearCachedApkIfNeededAndFinish(); } else { startInstall(); } Loading @@ -633,7 +677,7 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen if (mSessionId != -1) { mInstaller.setPermissionsResult(mSessionId, false); } finish(); clearCachedApkIfNeededAndFinish(); } } Loading Loading @@ -664,7 +708,99 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); } if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI); startActivity(newIntent); startActivityForResult(newIntent, REQUEST_INSTALL_PACKAGE); } private void clearCachedApkIfNeededAndFinish() { if (mContentUriApkStagingFile != null) { mContentUriApkStagingFile.delete(); mContentUriApkStagingFile = null; } finish(); } private final class StagingAsyncTask extends AsyncTask<Uri, Void, File> { private static final long SHOW_EMPTY_STATE_DELAY_MILLIS = 300; private final Runnable mEmptyStateRunnable = new Runnable() { @Override public void run() { ((TextView) findViewById(R.id.app_name)).setText(R.string.app_name_unknown); ((TextView) findViewById(R.id.install_confirm_question)) .setText(R.string.message_staging); mInstallConfirm.setVisibility(View.VISIBLE); findViewById(android.R.id.tabhost).setVisibility(View.INVISIBLE); findViewById(R.id.ok_button).setEnabled(false); Drawable icon = getDrawable(R.drawable.ic_file_download); Utils.applyTint(PackageInstallerActivity.this, icon, android.R.attr.colorControlNormal); ((ImageView) findViewById(R.id.app_icon)).setImageDrawable(icon); } }; @Override protected void onPreExecute() { getWindow().getDecorView().postDelayed(mEmptyStateRunnable, SHOW_EMPTY_STATE_DELAY_MILLIS); } @Override protected File doInBackground(Uri... params) { if (params == null || params.length <= 0) { return null; } Uri packageUri = params[0]; File sourceFile = null; try { sourceFile = File.createTempFile("package", ".apk", getCacheDir()); try ( InputStream in = getContentResolver().openInputStream(packageUri); OutputStream out = (in != null) ? new FileOutputStream( sourceFile) : null; ) { // Despite the comments in ContentResolver#openInputStream // the returned stream can be null. if (in == null) { return null; } byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = in.read(buffer)) >= 0) { // Be nice and respond to a cancellation if (isCancelled()) { return null; } out.write(buffer, 0, bytesRead); } } } catch (IOException ioe) { Log.w(TAG, "Error staging apk from content URI", ioe); if (sourceFile != null) { sourceFile.delete(); } } return sourceFile; } @Override protected void onPostExecute(File file) { getWindow().getDecorView().removeCallbacks(mEmptyStateRunnable); if (isFinishing() || isDestroyed()) { return; } if (file == null) { showDialogInner(DLG_PACKAGE_ERROR); setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK); return; } mContentUriApkStagingFile = file; Uri fileUri = Uri.fromFile(file); processPackageUri(fileUri); } @Override protected void onCancelled(File file) { getWindow().getDecorView().removeCallbacks(mEmptyStateRunnable); } }; }
src/com/android/packageinstaller/permission/model/PermissionApps.java +1 −1 Original line number Diff line number Diff line Loading @@ -32,7 +32,7 @@ import android.util.Log; import android.util.SparseArray; import com.android.packageinstaller.R; import com.android.packageinstaller.permission.utils.Utils; import com.android.packageinstaller.util.Utils; import java.util.ArrayList; import java.util.Collections; Loading