summaryrefslogtreecommitdiff
path: root/packages/PackageInstaller/src
diff options
context:
space:
mode:
authorPhilip P. Moltmann <moltmann@google.com>2018-08-02 12:12:55 -0700
committerPhilip P. Moltmann <moltmann@google.com>2018-08-03 10:28:56 -0700
commitd25ec877da0538406464101ea73139c84cde7794 (patch)
treec012e6cc6e73a6e005e86b33f808204300b9eaa2 /packages/PackageInstaller/src
parentbcd72a50b7629a2115457512d20ed6bf3c99fb2e (diff)
Make package installer a sequence of alert-dialogs.
To make sure the dialog does not change height a single content for all steps of the sequence. We just unhide the view that should actually be shown. Also added a night-mode theme. Test: Manually uninstalled, installed and update package. atest CtsNoPermissionTestCases CtsNoPermissionTestCases25 CtsPackageInstallTestCases CtsPackageUninstallTestCases CtsPackageInstallerTapjackingTestCases Change-Id: I890bb1f2697df3af87b6cb65e460f611334523ee
Diffstat (limited to 'packages/PackageInstaller/src')
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/InstallFailed.java45
-rwxr-xr-xpackages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java52
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/InstallStaging.java27
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/InstallSuccess.java34
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/OverlayTouchActivity.java29
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java80
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java20
7 files changed, 131 insertions, 156 deletions
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallFailed.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallFailed.java
index 5ba2d327d7d6..54105bb8432d 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallFailed.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallFailed.java
@@ -30,41 +30,49 @@ import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
-import android.widget.TextView;
+import android.view.View;
+
+import com.android.internal.app.AlertActivity;
import java.io.File;
/**
* Installation failed: Return status code to the caller or display failure UI to user
*/
-public class InstallFailed extends Activity {
+public class InstallFailed extends AlertActivity {
private static final String LOG_TAG = InstallFailed.class.getSimpleName();
/** Label of the app that failed to install */
private CharSequence mLabel;
/**
- * Convert an package installer status code into the user friendly label.
+ * Unhide the appropriate label for the statusCode.
*
* @param statusCode The status code from the package installer.
- *
- * @return The user friendly label for the status code
*/
- private int getExplanationFromErrorCode(int statusCode) {
+ private void setExplanationFromErrorCode(int statusCode) {
Log.d(LOG_TAG, "Installation status code: " + statusCode);
+ View viewToEnable;
switch (statusCode) {
case PackageInstaller.STATUS_FAILURE_BLOCKED:
- return R.string.install_failed_blocked;
+ viewToEnable = requireViewById(R.id.install_failed_blocked);
+ break;
case PackageInstaller.STATUS_FAILURE_CONFLICT:
- return R.string.install_failed_conflict;
+ viewToEnable = requireViewById(R.id.install_failed_conflict);
+ break;
case PackageInstaller.STATUS_FAILURE_INCOMPATIBLE:
- return R.string.install_failed_incompatible;
+ viewToEnable = requireViewById(R.id.install_failed_incompatible);
+ break;
case PackageInstaller.STATUS_FAILURE_INVALID:
- return R.string.install_failed_invalid_apk;
+ viewToEnable = requireViewById(R.id.install_failed_invalid_apk);
+ break;
default:
- return R.string.install_failed;
+ viewToEnable = requireViewById(R.id.install_failed);
+ break;
}
+
+ viewToEnable.setVisibility(View.VISIBLE);
}
@Override
@@ -89,8 +97,6 @@ public class InstallFailed extends Activity {
.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
Uri packageURI = intent.getData();
- setContentView(R.layout.install_failed);
-
// Set header icon and title
PackageUtil.AppSnippet as;
PackageManager pm = getPackageManager();
@@ -106,7 +112,12 @@ public class InstallFailed extends Activity {
// Store label for dialog
mLabel = as.label;
- PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);
+ mAlert.setIcon(as.icon);
+ mAlert.setTitle(as.label);
+ mAlert.setView(R.layout.install_content_view);
+ mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.done),
+ (ignored, ignored2) -> finish(), null);
+ setupAlert();
// Show out of space dialog if needed
if (statusCode == PackageInstaller.STATUS_FAILURE_STORAGE) {
@@ -114,11 +125,7 @@ public class InstallFailed extends Activity {
}
// Get status messages
- ((TextView) findViewById(R.id.simple_status)).setText(
- getExplanationFromErrorCode(statusCode));
-
- // Set up "done" button
- findViewById(R.id.done_button).setOnClickListener(view -> finish());
+ setExplanationFromErrorCode(statusCode);
}
}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
index c2dd740f91e5..deb6163cbf9d 100755
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
@@ -19,8 +19,8 @@ package com.android.packageinstaller;
import static android.content.pm.PackageInstaller.SessionParams.UID_UNKNOWN;
import android.annotation.Nullable;
-import android.app.Activity;
import android.app.PendingIntent;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInstaller;
@@ -30,9 +30,11 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
+import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
+import com.android.internal.app.AlertActivity;
import com.android.internal.content.PackageHelper;
import java.io.File;
@@ -47,7 +49,7 @@ import java.io.OutputStream;
* <p>This has two phases: First send the data to the package manager, then wait until the package
* manager processed the result.</p>
*/
-public class InstallInstalling extends Activity {
+public class InstallInstalling extends AlertActivity {
private static final String LOG_TAG = InstallInstalling.class.getSimpleName();
private static final String SESSION_ID = "com.android.packageinstaller.SESSION_ID";
@@ -78,11 +80,31 @@ public class InstallInstalling extends Activity {
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.install_installing);
-
ApplicationInfo appInfo = getIntent()
.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
mPackageURI = getIntent().getData();
+ final File sourceFile = new File(mPackageURI.getPath());
+ PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo, sourceFile);
+
+ mAlert.setIcon(as.icon);
+ mAlert.setTitle(as.label);
+ mAlert.setView(R.layout.install_content_view);
+ mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
+ (ignored, ignored2) -> {
+ if (mInstallingTask != null) {
+ mInstallingTask.cancel(true);
+ }
+
+ if (mSessionId > 0) {
+ getPackageManager().getPackageInstaller().abandonSession(mSessionId);
+ mSessionId = 0;
+ }
+
+ setResult(RESULT_CANCELED);
+ finish();
+ }, null);
+ setupAlert();
+ requireViewById(R.id.installing).setVisibility(View.VISIBLE);
if ("package".equals(mPackageURI.getScheme())) {
try {
@@ -92,10 +114,6 @@ public class InstallInstalling extends Activity {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
} else {
- final File sourceFile = new File(mPackageURI.getPath());
- PackageUtil.initSnippetForNewApp(this, PackageUtil.getAppSnippet(this, appInfo,
- sourceFile), R.id.app_snippet);
-
if (savedInstanceState != null) {
mSessionId = savedInstanceState.getInt(SESSION_ID);
mInstallId = savedInstanceState.getInt(INSTALL_ID);
@@ -153,21 +171,7 @@ public class InstallInstalling extends Activity {
}
}
- mCancelButton = (Button) findViewById(R.id.cancel_button);
-
- mCancelButton.setOnClickListener(view -> {
- if (mInstallingTask != null) {
- mInstallingTask.cancel(true);
- }
-
- if (mSessionId > 0) {
- getPackageManager().getPackageInstaller().abandonSession(mSessionId);
- mSessionId = 0;
- }
-
- setResult(RESULT_CANCELED);
- finish();
- });
+ mCancelButton = mAlert.getButton(DialogInterface.BUTTON_NEGATIVE);
mSessionCallback = new InstallSessionCallback();
}
@@ -307,7 +311,7 @@ public class InstallInstalling extends Activity {
@Override
public void onProgressChanged(int sessionId, float progress) {
if (sessionId == mSessionId) {
- ProgressBar progressBar = (ProgressBar)findViewById(R.id.progress_bar);
+ ProgressBar progressBar = requireViewById(R.id.progress);
progressBar.setMax(Integer.MAX_VALUE);
progressBar.setProgress((int) (Integer.MAX_VALUE * progress));
}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStaging.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStaging.java
index 1bc9dbd39b0a..98438cde7c68 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStaging.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStaging.java
@@ -29,6 +29,9 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
+import android.view.View;
+
+import com.android.internal.app.AlertActivity;
import java.io.File;
import java.io.FileOutputStream;
@@ -40,7 +43,7 @@ import java.io.OutputStream;
* If a package gets installed from an content URI this step loads the package and turns it into
* and installation from a file. Then it re-starts the installation as usual.
*/
-public class InstallStaging extends Activity {
+public class InstallStaging extends AlertActivity {
private static final String LOG_TAG = InstallStaging.class.getSimpleName();
private static final String STAGED_FILE = "STAGED_FILE";
@@ -55,7 +58,19 @@ public class InstallStaging extends Activity {
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- setContentView(R.layout.install_staging);
+ mAlert.setIcon(R.drawable.ic_file_download);
+ mAlert.setTitle(getString(R.string.app_name_unknown));
+ mAlert.setView(R.layout.install_content_view);
+ mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
+ (ignored, ignored2) -> {
+ if (mStagingTask != null) {
+ mStagingTask.cancel(true);
+ }
+ setResult(RESULT_CANCELED);
+ finish();
+ }, null);
+ setupAlert();
+ requireViewById(R.id.staging).setVisibility(View.VISIBLE);
if (savedInstanceState != null) {
mStagedFile = new File(savedInstanceState.getString(STAGED_FILE));
@@ -64,14 +79,6 @@ public class InstallStaging extends Activity {
mStagedFile = null;
}
}
-
- findViewById(R.id.cancel_button).setOnClickListener(view -> {
- if (mStagingTask != null) {
- mStagingTask.cancel(true);
- }
- setResult(RESULT_CANCELED);
- finish();
- });
}
@Override
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallSuccess.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallSuccess.java
index 94f6b31383bd..705d3f4bdf87 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallSuccess.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallSuccess.java
@@ -19,6 +19,7 @@ package com.android.packageinstaller;
import android.annotation.Nullable;
import android.app.Activity;
import android.content.ActivityNotFoundException;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -26,15 +27,18 @@ import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
+import android.view.View;
import android.widget.Button;
+import com.android.internal.app.AlertActivity;
+
import java.io.File;
import java.util.List;
/**
* Finish installation: Return status code to the caller or display "success" UI to user
*/
-public class InstallSuccess extends Activity {
+public class InstallSuccess extends AlertActivity {
private static final String LOG_TAG = InstallSuccess.class.getSimpleName();
@Override
@@ -53,8 +57,6 @@ public class InstallSuccess extends Activity {
intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
Uri packageURI = intent.getData();
- setContentView(R.layout.install_success);
-
// Set header icon and title
PackageUtil.AppSnippet as;
PackageManager pm = getPackageManager();
@@ -67,16 +69,20 @@ public class InstallSuccess extends Activity {
as = PackageUtil.getAppSnippet(this, appInfo, sourceFile);
}
- PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);
-
- // Set up "done" button
- findViewById(R.id.done_button).setOnClickListener(view -> {
- if (appInfo.packageName != null) {
- Log.i(LOG_TAG, "Finished installing " + appInfo.packageName);
- }
- finish();
- });
-
+ mAlert.setIcon(as.icon);
+ mAlert.setTitle(as.label);
+ mAlert.setView(R.layout.install_content_view);
+ mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.launch), null,
+ null);
+ mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.done),
+ (ignored, ignored2) -> {
+ if (appInfo.packageName != null) {
+ Log.i(LOG_TAG, "Finished installing " + appInfo.packageName);
+ }
+ finish();
+ }, null);
+ setupAlert();
+ requireViewById(R.id.install_success).setVisibility(View.VISIBLE);
// Enable or disable "launch" button
Intent launchIntent = getPackageManager().getLaunchIntentForPackage(
appInfo.packageName);
@@ -89,7 +95,7 @@ public class InstallSuccess extends Activity {
}
}
- Button launchButton = (Button)findViewById(R.id.launch_button);
+ Button launchButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
if (enabled) {
launchButton.setOnClickListener(view -> {
try {
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/OverlayTouchActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/OverlayTouchActivity.java
deleted file mode 100644
index 1fdbd97089a3..000000000000
--- a/packages/PackageInstaller/src/com/android/packageinstaller/OverlayTouchActivity.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2018 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.
- */
-package com.android.packageinstaller;
-
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-class OverlayTouchActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- getWindow().addPrivateFlags(PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
- super.onCreate(savedInstanceState);
- }
-}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index 97bafe75be90..580308a4cffd 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -16,6 +16,8 @@
*/
package com.android.packageinstaller;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.StringRes;
@@ -45,9 +47,9 @@ import android.os.UserManager;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
-import android.view.View.OnClickListener;
import android.widget.Button;
-import android.widget.TextView;
+
+import com.android.internal.app.AlertActivity;
import java.io.File;
@@ -61,7 +63,7 @@ import java.io.File;
* Based on the user response the package is then installed by launching InstallAppConfirm
* sub activity. All state transitions are handled in this activity
*/
-public class PackageInstallerActivity extends OverlayTouchActivity implements OnClickListener {
+public class PackageInstallerActivity extends AlertActivity {
private static final String TAG = "PackageInstaller";
private static final int REQUEST_TRUST_EXTERNAL_SOURCE = 1;
@@ -95,7 +97,6 @@ public class PackageInstallerActivity extends OverlayTouchActivity implements On
// Buttons to indicate user acceptance
private Button mOk;
- private Button mCancel;
private PackageUtil.AppSnippet mAppSnippet;
@@ -119,18 +120,18 @@ public class PackageInstallerActivity extends OverlayTouchActivity implements On
private boolean mEnableOk = false;
private void startInstallConfirm() {
- int msg;
+ View viewToEnable;
if (mAppInfo != null) {
- msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
- ? R.string.install_confirm_question_update_system
- : R.string.install_confirm_question_update;
+ viewToEnable = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
+ ? requireViewById(R.id.install_confirm_question_update_system)
+ : requireViewById(R.id.install_confirm_question_update);
} else {
// This is a new application with no permissions.
- msg = R.string.install_confirm_question;
+ viewToEnable = requireViewById(R.id.install_confirm_question);
}
- ((TextView) findViewById(R.id.install_confirm_question)).setText(msg);
+ viewToEnable.setVisibility(View.VISIBLE);
mEnableOk = true;
mOk.setEnabled(true);
@@ -280,6 +281,8 @@ public class PackageInstallerActivity extends OverlayTouchActivity implements On
@Override
protected void onCreate(Bundle icicle) {
+ getWindow().addPrivateFlags(PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+
super.onCreate(null);
if (icicle != null) {
@@ -344,7 +347,7 @@ public class PackageInstallerActivity extends OverlayTouchActivity implements On
// load dummy layout with OK button disabled until we override this layout in
// startInstallConfirm
- bindUi(R.layout.install_confirm);
+ bindUi();
checkIfAllowedAndInitiateInstall();
}
@@ -374,17 +377,34 @@ public class PackageInstallerActivity extends OverlayTouchActivity implements On
outState.putBoolean(ALLOW_UNKNOWN_SOURCES_KEY, mAllowUnknownSources);
}
- private void bindUi(int layout) {
- setContentView(layout);
-
- mOk = (Button) findViewById(R.id.ok_button);
- mCancel = (Button)findViewById(R.id.cancel_button);
- mOk.setOnClickListener(this);
- mCancel.setOnClickListener(this);
+ private void bindUi() {
+ mAlert.setIcon(mAppSnippet.icon);
+ mAlert.setTitle(mAppSnippet.label);
+ mAlert.setView(R.layout.install_content_view);
+ mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.install),
+ (ignored, ignored2) -> {
+ if (mOk.isEnabled()) {
+ if (mSessionId != -1) {
+ mInstaller.setPermissionsResult(mSessionId, true);
+ finish();
+ } else {
+ startInstall();
+ }
+ }
+ }, null);
+ mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
+ (ignored, ignored2) -> {
+ // Cancel and finish
+ setResult(RESULT_CANCELED);
+ if (mSessionId != -1) {
+ mInstaller.setPermissionsResult(mSessionId, false);
+ }
+ finish();
+ }, null);
+ setupAlert();
+ mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
mOk.setEnabled(false);
-
- PackageUtil.initSnippetForNewApp(this, mAppSnippet, R.id.app_snippet);
}
/**
@@ -525,26 +545,6 @@ public class PackageInstallerActivity extends OverlayTouchActivity implements On
super.onBackPressed();
}
- public void onClick(View v) {
- if (v == mOk) {
- if (mOk.isEnabled()) {
- if (mSessionId != -1) {
- mInstaller.setPermissionsResult(mSessionId, true);
- finish();
- } else {
- startInstall();
- }
- }
- } else if (v == mCancel) {
- // Cancel and finish
- setResult(RESULT_CANCELED);
- if (mSessionId != -1) {
- mInstaller.setPermissionsResult(mSessionId, false);
- }
- finish();
- }
- }
-
private void startInstall() {
// Start subactivity to actually install the application
Intent newIntent = new Intent();
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
index ba4bf8a6b838..0e89f56d2376 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageUtil.java
@@ -108,26 +108,6 @@ public class PackageUtil {
icon);
}
- /**
- * Utility method to display application snippet of a new package.
- * The content view should have been set on context before invoking this method.
- * appSnippet view should include R.id.app_icon and R.id.app_name
- * defined on it.
- *
- * @param pContext context of package that can load the resources
- * @param as The resources to be loaded
- * @param snippetId view id of app snippet view
- */
- @NonNull public static View initSnippetForNewApp(@NonNull Activity pContext,
- @NonNull AppSnippet as, int snippetId) {
- View appSnippet = pContext.findViewById(snippetId);
- if (as.icon != null) {
- ((ImageView) appSnippet.findViewById(R.id.app_icon)).setImageDrawable(as.icon);
- }
- ((TextView)appSnippet.findViewById(R.id.app_name)).setText(as.label);
- return appSnippet;
- }
-
static public class AppSnippet {
@NonNull public CharSequence label;
@Nullable public Drawable icon;