Merge "Move packages between candidate volumes."
This commit is contained in:
@@ -23,13 +23,12 @@ import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageDataObserver;
|
||||
import android.content.pm.IPackageMoveObserver;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.os.storage.VolumeInfo;
|
||||
import android.text.format.Formatter;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
@@ -38,11 +37,16 @@ import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.settings.DropDownPreference;
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.applications.ApplicationsState.AppEntry;
|
||||
import com.android.settings.applications.ApplicationsState.Callbacks;
|
||||
import com.android.settings.DropDownPreference;
|
||||
import com.android.settings.deviceinfo.StorageWizardMoveConfirm;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class AppStorageSettings extends AppInfoWithHeader
|
||||
implements OnClickListener, Callbacks, DropDownPreference.Callback {
|
||||
@@ -53,7 +57,6 @@ public class AppStorageSettings extends AppInfoWithHeader
|
||||
private static final int OP_FAILED = 2;
|
||||
private static final int MSG_CLEAR_USER_DATA = 1;
|
||||
private static final int MSG_CLEAR_CACHE = 3;
|
||||
private static final int MSG_PACKAGE_MOVE = 4;
|
||||
|
||||
// invalid size value used initially and also when size retrieval through PackageManager
|
||||
// fails for whatever reason
|
||||
@@ -64,13 +67,11 @@ public class AppStorageSettings extends AppInfoWithHeader
|
||||
|
||||
private static final int DLG_CLEAR_DATA = DLG_BASE + 1;
|
||||
private static final int DLG_CANNOT_CLEAR_DATA = DLG_BASE + 2;
|
||||
private static final int DLG_MOVE_FAILED = DLG_BASE + 3;
|
||||
|
||||
private static final String KEY_MOVE_PREFERENCE = "app_location_setting";
|
||||
private static final String KEY_STORAGE_SETTINGS = "storage_settings";
|
||||
private static final String KEY_CACHE_SETTINGS = "cache_settings";
|
||||
|
||||
private CanBeOnSdCardChecker mCanBeOnSdCardChecker;
|
||||
private TextView mTotalSize;
|
||||
private TextView mAppSize;
|
||||
private TextView mDataSize;
|
||||
@@ -83,7 +84,6 @@ public class AppStorageSettings extends AppInfoWithHeader
|
||||
private Button mClearCacheButton;
|
||||
|
||||
private DropDownPreference mMoveDropDown;
|
||||
private boolean mMoveInProgress = false;
|
||||
|
||||
private boolean mCanClearData = true;
|
||||
private boolean mHaveSizes = false;
|
||||
@@ -97,7 +97,6 @@ public class AppStorageSettings extends AppInfoWithHeader
|
||||
|
||||
private ClearCacheObserver mClearCacheObserver;
|
||||
private ClearUserDataObserver mClearDataObserver;
|
||||
private PackageMoveObserver mPackageMoveObserver;
|
||||
|
||||
// Resource strings
|
||||
private CharSequence mInvalidSizeStr;
|
||||
@@ -107,7 +106,6 @@ public class AppStorageSettings extends AppInfoWithHeader
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mCanBeOnSdCardChecker = new CanBeOnSdCardChecker();
|
||||
addPreferencesFromResource(R.xml.app_storage_settings);
|
||||
setupViews();
|
||||
}
|
||||
@@ -166,18 +164,19 @@ public class AppStorageSettings extends AppInfoWithHeader
|
||||
|
||||
@Override
|
||||
public boolean onItemSelected(int pos, Object value) {
|
||||
boolean selectedExternal = (Boolean) value;
|
||||
boolean isExternal = (mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
|
||||
if (selectedExternal ^ isExternal) {
|
||||
if (mPackageMoveObserver == null) {
|
||||
mPackageMoveObserver = new PackageMoveObserver();
|
||||
}
|
||||
int moveFlags = selectedExternal ? PackageManager.MOVE_EXTERNAL_MEDIA
|
||||
: PackageManager.MOVE_INTERNAL;
|
||||
mMoveInProgress = true;
|
||||
refreshButtons();
|
||||
mPm.movePackage(mAppEntry.info.packageName, mPackageMoveObserver, moveFlags);
|
||||
final Context context = getActivity();
|
||||
|
||||
// If not current volume, kick off move wizard
|
||||
final VolumeInfo targetVol = (VolumeInfo) value;
|
||||
final VolumeInfo currentVol = context.getPackageManager().getApplicationCurrentVolume(
|
||||
mAppEntry.info);
|
||||
if (!Objects.equals(targetVol, currentVol)) {
|
||||
final Intent intent = new Intent(context, StorageWizardMoveConfirm.class);
|
||||
intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, targetVol.getId());
|
||||
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, mAppEntry.info.packageName);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -260,27 +259,17 @@ public class AppStorageSettings extends AppInfoWithHeader
|
||||
retrieveAppEntry();
|
||||
refreshButtons();
|
||||
refreshSizeInfo();
|
||||
boolean isExternal = (mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
|
||||
mMoveDropDown.setSelectedItem(isExternal ? 1 : 0);
|
||||
|
||||
final VolumeInfo currentVol = getActivity().getPackageManager()
|
||||
.getApplicationCurrentVolume(mAppEntry.info);
|
||||
mMoveDropDown.setSelectedValue(currentVol);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void refreshButtons() {
|
||||
if (!mMoveInProgress) {
|
||||
initMoveDropDown();
|
||||
initDataButtons();
|
||||
} else {
|
||||
mMoveDropDown.setSummary(R.string.moving);
|
||||
mMoveDropDown.setSelectable(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateMoveEnabled(boolean enabled) {
|
||||
mMoveDropDown.clearItems();
|
||||
mMoveDropDown.addItem(R.string.storage_type_internal, false);
|
||||
if (enabled) {
|
||||
mMoveDropDown.addItem(R.string.storage_type_external, true);
|
||||
}
|
||||
initMoveDropDown();
|
||||
initDataButtons();
|
||||
}
|
||||
|
||||
private void initDataButtons() {
|
||||
@@ -310,20 +299,18 @@ public class AppStorageSettings extends AppInfoWithHeader
|
||||
}
|
||||
|
||||
private void initMoveDropDown() {
|
||||
if (Environment.isExternalStorageEmulated()) {
|
||||
updateMoveEnabled(false);
|
||||
return;
|
||||
final Context context = getActivity();
|
||||
final StorageManager storage = context.getSystemService(StorageManager.class);
|
||||
|
||||
final List<VolumeInfo> candidates = context.getPackageManager()
|
||||
.getApplicationCandidateVolumes(mAppEntry.info);
|
||||
Collections.sort(candidates, VolumeInfo.getDescriptionComparator());
|
||||
|
||||
mMoveDropDown.clearItems();
|
||||
for (VolumeInfo vol : candidates) {
|
||||
final String volDescrip = storage.getBestVolumeDescription(vol);
|
||||
mMoveDropDown.addItem(volDescrip, vol);
|
||||
}
|
||||
boolean dataOnly = (mPackageInfo == null) && (mAppEntry != null);
|
||||
boolean moveDisable = true;
|
||||
if ((mAppEntry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
|
||||
// Always let apps move to internal storage from sdcard.
|
||||
moveDisable = false;
|
||||
} else {
|
||||
mCanBeOnSdCardChecker.init();
|
||||
moveDisable = !mCanBeOnSdCardChecker.check(mAppEntry.info);
|
||||
}
|
||||
updateMoveEnabled(!moveDisable);
|
||||
mMoveDropDown.setSelectable(!mAppControlRestricted);
|
||||
}
|
||||
|
||||
@@ -351,21 +338,6 @@ public class AppStorageSettings extends AppInfoWithHeader
|
||||
}
|
||||
}
|
||||
|
||||
private void processMoveMsg(Message msg) {
|
||||
int result = msg.arg1;
|
||||
String packageName = mAppEntry.info.packageName;
|
||||
// Refresh the button attributes.
|
||||
mMoveInProgress = false;
|
||||
if (result == PackageManager.MOVE_SUCCEEDED) {
|
||||
Log.i(TAG, "Moved resources for " + packageName);
|
||||
// Refresh size information again.
|
||||
mState.requestSize(mPackageName, mUserId);
|
||||
} else {
|
||||
showDialogInner(DLG_MOVE_FAILED, result);
|
||||
}
|
||||
refreshUi();
|
||||
}
|
||||
|
||||
/*
|
||||
* Private method to handle clear message notification from observer when
|
||||
* the async operation from PackageManager is complete
|
||||
@@ -382,24 +354,6 @@ public class AppStorageSettings extends AppInfoWithHeader
|
||||
}
|
||||
}
|
||||
|
||||
private CharSequence getMoveErrMsg(int errCode) {
|
||||
switch (errCode) {
|
||||
case PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE:
|
||||
return getActivity().getString(R.string.insufficient_storage);
|
||||
case PackageManager.MOVE_FAILED_DOESNT_EXIST:
|
||||
return getActivity().getString(R.string.does_not_exist);
|
||||
case PackageManager.MOVE_FAILED_FORWARD_LOCKED:
|
||||
return getActivity().getString(R.string.app_forward_locked);
|
||||
case PackageManager.MOVE_FAILED_INVALID_LOCATION:
|
||||
return getActivity().getString(R.string.invalid_location);
|
||||
case PackageManager.MOVE_FAILED_SYSTEM_PACKAGE:
|
||||
return getActivity().getString(R.string.system_package);
|
||||
case PackageManager.MOVE_FAILED_INTERNAL_ERROR:
|
||||
return "";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AlertDialog createDialog(int id, int errorCode) {
|
||||
switch (id) {
|
||||
@@ -427,14 +381,6 @@ public class AppStorageSettings extends AppInfoWithHeader
|
||||
}
|
||||
})
|
||||
.create();
|
||||
case DLG_MOVE_FAILED:
|
||||
CharSequence msg = getActivity().getString(R.string.move_app_failed_dlg_text,
|
||||
getMoveErrMsg(errorCode));
|
||||
return new AlertDialog.Builder(getActivity())
|
||||
.setTitle(getActivity().getText(R.string.move_app_failed_dlg_title))
|
||||
.setMessage(msg)
|
||||
.setNeutralButton(R.string.dlg_ok, null)
|
||||
.create();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -459,9 +405,6 @@ public class AppStorageSettings extends AppInfoWithHeader
|
||||
// Refresh size info
|
||||
mState.requestSize(mPackageName, mUserId);
|
||||
break;
|
||||
case MSG_PACKAGE_MOVE:
|
||||
processMoveMsg(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -508,13 +451,4 @@ public class AppStorageSettings extends AppInfoWithHeader
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
class PackageMoveObserver extends IPackageMoveObserver.Stub {
|
||||
public void packageMoved(String packageName, int returnCode) throws RemoteException {
|
||||
final Message msg = mHandler.obtainMessage(MSG_PACKAGE_MOVE);
|
||||
msg.arg1 = returnCode;
|
||||
mHandler.sendMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -295,20 +295,6 @@ public class ApplicationsState {
|
||||
}
|
||||
};
|
||||
|
||||
public static final AppFilter FILTER_ON_SD_CARD = new AppFilter() {
|
||||
final CanBeOnSdCardChecker mCanBeOnSdCardChecker
|
||||
= new CanBeOnSdCardChecker();
|
||||
|
||||
public void init() {
|
||||
mCanBeOnSdCardChecker.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean filterApp(AppEntry entry) {
|
||||
return mCanBeOnSdCardChecker.check(entry.info);
|
||||
}
|
||||
};
|
||||
|
||||
public static final AppFilter FILTER_DISABLED = new AppFilter() {
|
||||
public void init() {
|
||||
}
|
||||
|
@@ -20,15 +20,11 @@ import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.content.pm.IntentFilterVerificationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.preference.PreferenceFrameLayout;
|
||||
@@ -53,7 +49,6 @@ import android.widget.Filterable;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import com.android.internal.content.PackageHelper;
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.settings.HelpUtils;
|
||||
import com.android.settings.InstrumentedFragment;
|
||||
@@ -74,47 +69,6 @@ import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
final class CanBeOnSdCardChecker {
|
||||
final IPackageManager mPm;
|
||||
int mInstallLocation;
|
||||
|
||||
CanBeOnSdCardChecker() {
|
||||
mPm = IPackageManager.Stub.asInterface(
|
||||
ServiceManager.getService("package"));
|
||||
}
|
||||
|
||||
void init() {
|
||||
try {
|
||||
mInstallLocation = mPm.getInstallLocation();
|
||||
} catch (RemoteException e) {
|
||||
Log.e("CanBeOnSdCardChecker", "Is Package Manager running?");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
boolean check(ApplicationInfo info) {
|
||||
boolean canBe = false;
|
||||
if ((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
|
||||
canBe = true;
|
||||
} else {
|
||||
if ((info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
|
||||
if (info.installLocation == PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL ||
|
||||
info.installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {
|
||||
canBe = true;
|
||||
} else if (info.installLocation
|
||||
== PackageInfo.INSTALL_LOCATION_UNSPECIFIED) {
|
||||
if (mInstallLocation == PackageHelper.APP_INSTALL_EXTERNAL) {
|
||||
// For apps with no preference and the default value set
|
||||
// to install on sdcard.
|
||||
canBe = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return canBe;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Activity to pick an application that will be used to display installation information and
|
||||
* options to uninstall/delete user data for system applications. This activity
|
||||
|
Reference in New Issue
Block a user