Do not show install confirm activity if there are no new permissions, externalize app diff for this functionality

This commit is contained in:
Dominik Schürmann 2015-05-20 18:26:58 +02:00
parent 62a4d58756
commit f48236deb9
3 changed files with 110 additions and 50 deletions

View File

@ -0,0 +1,69 @@
/*
**
** Copyright 2007, The Android Open Source Project
** Copyright 2015 Dominik Schürmann <dominik@dominikschuermann.de>
**
** 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 org.fdroid.fdroid.installer;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
public class AppDiff {
PackageManager mPm;
PackageInfo mPkgInfo;
ApplicationInfo mAppInfo = null;
public AppDiff(PackageManager mPm, Uri mPackageURI) {
this.mPm = mPm;
final String pkgPath = mPackageURI.getPath();
mPkgInfo = mPm.getPackageArchiveInfo(pkgPath, PackageManager.GET_PERMISSIONS);
mPkgInfo.applicationInfo.sourceDir = pkgPath;
mPkgInfo.applicationInfo.publicSourceDir = pkgPath;
init();
}
private void init() {
String pkgName = mPkgInfo.packageName;
// Check if there is already a package on the device with this name
// but it has been renamed to something else.
final String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName });
if (oldName != null && oldName.length > 0 && oldName[0] != null) {
pkgName = oldName[0];
mPkgInfo.packageName = pkgName;
mPkgInfo.applicationInfo.packageName = pkgName;
}
// Check if package is already installed. display confirmation dialog if replacing pkg
try {
// This is a little convoluted because we want to get all uninstalled
// apps, but this may include apps with just data, and if it is just
// data we still want to count it as "installed".
mAppInfo = mPm.getApplicationInfo(pkgName,
PackageManager.GET_UNINSTALLED_PACKAGES);
if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
mAppInfo = null;
}
} catch (PackageManager.NameNotFoundException e) {
mAppInfo = null;
}
}
}

View File

@ -15,6 +15,7 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
package org.fdroid.fdroid.installer;
import android.app.Activity;
@ -23,9 +24,7 @@ import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
@ -47,9 +46,8 @@ public class InstallConfirmActivity extends Activity implements OnCancelListener
private Intent intent;
PackageManager mPm;
PackageInfo mPkgInfo;
private ApplicationInfo mAppInfo = null;
AppDiff mAppDiff;
// View for install progress
View mInstallConfirm;
@ -64,8 +62,8 @@ public class InstallConfirmActivity extends Activity implements OnCancelListener
private void startInstallConfirm() {
final Drawable appIcon = mPkgInfo.applicationInfo.loadIcon(mPm);
final String appLabel = (String) mPkgInfo.applicationInfo.loadLabel(mPm);
final Drawable appIcon = mAppDiff.mPkgInfo.applicationInfo.loadIcon(mPm);
final String appLabel = (String) mAppDiff.mPkgInfo.applicationInfo.loadLabel(mPm);
View appSnippet = findViewById(R.id.app_snippet);
((ImageView) appSnippet.findViewById(R.id.app_icon)).setImageDrawable(appIcon);
@ -85,12 +83,12 @@ public class InstallConfirmActivity extends Activity implements OnCancelListener
mScrollView = null;
mOkCanInstall = false;
int msg = 0;
if (mPkgInfo != null) {
AppSecurityPermissions perms = new AppSecurityPermissions(this, mPkgInfo);
if (mAppDiff.mPkgInfo != null) {
AppSecurityPermissions perms = new AppSecurityPermissions(this, mAppDiff.mPkgInfo);
final int NP = perms.getPermissionCount(AppSecurityPermissions.WHICH_PERSONAL);
final int ND = perms.getPermissionCount(AppSecurityPermissions.WHICH_DEVICE);
if (mAppInfo != null) {
msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
if (mAppDiff.mAppInfo != null) {
msg = (mAppDiff.mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
? R.string.install_confirm_update_system
: R.string.install_confirm_update;
mScrollView = new CaffeinatedScrollView(this);
@ -139,10 +137,10 @@ public class InstallConfirmActivity extends Activity implements OnCancelListener
}
}
if (!permVisible) {
if (mAppInfo != null) {
if (mAppDiff.mAppInfo != null) {
// This is an update to an application, but there are no
// permissions at all.
msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
msg = (mAppDiff.mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
? R.string.install_confirm_update_system_no_perms
: R.string.install_confirm_update_no_perms;
} else {
@ -178,33 +176,6 @@ public class InstallConfirmActivity extends Activity implements OnCancelListener
}
}
private void initiateInstall() {
String pkgName = mPkgInfo.packageName;
// Check if there is already a package on the device with this name
// but it has been renamed to something else.
final String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName });
if (oldName != null && oldName.length > 0 && oldName[0] != null) {
pkgName = oldName[0];
mPkgInfo.packageName = pkgName;
mPkgInfo.applicationInfo.packageName = pkgName;
}
// Check if package is already installed. display confirmation dialog if replacing pkg
try {
// This is a little convoluted because we want to get all uninstalled
// apps, but this may include apps with just data, and if it is just
// data we still want to count it as "installed".
mAppInfo = mPm.getApplicationInfo(pkgName,
PackageManager.GET_UNINSTALLED_PACKAGES);
if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
mAppInfo = null;
}
} catch (NameNotFoundException e) {
mAppInfo = null;
}
startInstallConfirm();
}
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
@ -214,18 +185,15 @@ public class InstallConfirmActivity extends Activity implements OnCancelListener
mPm = getPackageManager();
intent = getIntent();
Uri mPackageURI = intent.getData();
final String pkgPath = mPackageURI.getPath();
Uri packageURI = intent.getData();
mPkgInfo = mPm.getPackageArchiveInfo(pkgPath, PackageManager.GET_PERMISSIONS);
mPkgInfo.applicationInfo.sourceDir = pkgPath;
mPkgInfo.applicationInfo.publicSourceDir = pkgPath;
mAppDiff = new AppDiff(mPm, packageURI);
setContentView(R.layout.install_start);
mInstallConfirm = findViewById(R.id.install_confirm_panel);
mInstallConfirm.setVisibility(View.INVISIBLE);
initiateInstall();
startInstallConfirm();
}
@Override

View File

@ -138,9 +138,32 @@ public class SystemInstaller extends Installer {
@Override
protected void installPackageInternal(File apkFile) throws AndroidNotCompatibleException {
Intent intent = new Intent(mContext, InstallConfirmActivity.class);
intent.setData(Uri.fromFile(apkFile));
mActivity.startActivityForResult(intent, REQUEST_CONFIRM_PERMS);
Uri packageUri = Uri.fromFile(apkFile);
if (hasNewPermissions(packageUri)) {
Intent intent = new Intent(mContext, InstallConfirmActivity.class);
intent.setData(packageUri);
mActivity.startActivityForResult(intent, REQUEST_CONFIRM_PERMS);
} else {
try {
doInstallPackageInternal(packageUri);
} catch (AndroidNotCompatibleException e) {
mCallback.onError(InstallerCallback.OPERATION_INSTALL,
InstallerCallback.ERROR_CODE_OTHER);
}
}
}
private boolean hasNewPermissions(Uri packageUri) {
AppDiff appDiff = new AppDiff(mContext.getPackageManager(), packageUri);
if (appDiff.mPkgInfo != null) {
AppSecurityPermissions perms = new AppSecurityPermissions(mContext, appDiff.mPkgInfo);
if (appDiff.mAppInfo != null) { // it is an update to an existing app
// return false if there are no new permissions
return (perms.getPermissionCount(AppSecurityPermissions.WHICH_NEW) > 0);
}
}
// default: show install confirm activity
return true;
}
private void doInstallPackageInternal(Uri packageURI) throws AndroidNotCompatibleException {
@ -220,9 +243,9 @@ public class SystemInstaller extends Installer {
switch (requestCode) {
case REQUEST_CONFIRM_PERMS:
if (resultCode == Activity.RESULT_OK) {
final Uri packageURI = data.getData();
final Uri packageUri = data.getData();
try {
doInstallPackageInternal(packageURI);
doInstallPackageInternal(packageUri);
} catch (AndroidNotCompatibleException e) {
mCallback.onError(InstallerCallback.OPERATION_INSTALL,
InstallerCallback.ERROR_CODE_OTHER);