diff --git a/res/layout/preference_list_fragment.xml b/res/layout/preference_list_fragment.xml index 6e8ad911032..195f6eb8744 100644 --- a/res/layout/preference_list_fragment.xml +++ b/res/layout/preference_list_fragment.xml @@ -36,7 +36,7 @@ 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); - } - } - } diff --git a/src/com/android/settings/applications/ApplicationsState.java b/src/com/android/settings/applications/ApplicationsState.java index 162ca7715a5..ddfc207650f 100644 --- a/src/com/android/settings/applications/ApplicationsState.java +++ b/src/com/android/settings/applications/ApplicationsState.java @@ -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() { } diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java index b6b2b828944..362903e53af 100644 --- a/src/com/android/settings/applications/ManageApplications.java +++ b/src/com/android/settings/applications/ManageApplications.java @@ -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 diff --git a/src/com/android/settings/deviceinfo/StorageSettings.java b/src/com/android/settings/deviceinfo/StorageSettings.java index 1e33230df88..74040ef20c8 100644 --- a/src/com/android/settings/deviceinfo/StorageSettings.java +++ b/src/com/android/settings/deviceinfo/StorageSettings.java @@ -41,7 +41,6 @@ import com.android.settings.search.SearchIndexableRaw; import java.util.ArrayList; import java.util.Collections; -import java.util.Comparator; import java.util.List; /** @@ -91,21 +90,6 @@ public class StorageSettings extends SettingsPreferenceFragment implements Index setHasOptionsMenu(true); } - private static final Comparator sVolumeComparator = new Comparator() { - @Override - public int compare(VolumeInfo lhs, VolumeInfo rhs) { - if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(lhs.getId())) { - return -1; - } else if (lhs.getDescription() == null) { - return 1; - } else if (rhs.getDescription() == null) { - return -1; - } else { - return lhs.getDescription().compareTo(rhs.getDescription()); - } - } - }; - private final StorageEventListener mStorageListener = new StorageEventListener() { @Override public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) { @@ -133,7 +117,7 @@ public class StorageSettings extends SettingsPreferenceFragment implements Index mExternalCategory.removeAll(); final List volumes = mStorageManager.getVolumes(); - Collections.sort(volumes, sVolumeComparator); + Collections.sort(volumes, VolumeInfo.getDescriptionComparator()); for (VolumeInfo vol : volumes) { if (vol.getType() == VolumeInfo.TYPE_PRIVATE) { diff --git a/src/com/android/settings/deviceinfo/StorageWizardMoveConfirm.java b/src/com/android/settings/deviceinfo/StorageWizardMoveConfirm.java new file mode 100644 index 00000000000..36750c078db --- /dev/null +++ b/src/com/android/settings/deviceinfo/StorageWizardMoveConfirm.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2015 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.settings.deviceinfo; + +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Bundle; +import android.os.storage.VolumeInfo; + +import com.android.internal.util.Preconditions; +import com.android.settings.R; + +public class StorageWizardMoveConfirm extends StorageWizardBase { + private String mPackageName; + private ApplicationInfo mApp; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.storage_wizard_generic); + + try { + mPackageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME); + mApp = getPackageManager().getApplicationInfo(mPackageName, 0); + } catch (NameNotFoundException e) { + throw new RuntimeException(e); + } + + Preconditions.checkNotNull(mVolume); + Preconditions.checkNotNull(mApp); + + // Sanity check that target volume is candidate + Preconditions.checkState( + getPackageManager().getApplicationCandidateVolumes(mApp).contains(mVolume)); + + final String appName = getPackageManager().getApplicationLabel(mApp).toString(); + final String volumeName = mStorage.getBestVolumeDescription(mVolume); + + setHeaderText(R.string.storage_wizard_move_confirm_title, appName); + setBodyText(R.string.storage_wizard_move_confirm_body, appName, volumeName); + + getNextButton().setText(R.string.move_app); + } + + @Override + public void onNavigateNext() { + final Intent intent = new Intent(this, StorageWizardMoveProgress.class); + intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, mVolume.getId()); + intent.putExtra(Intent.EXTRA_PACKAGE_NAME, mPackageName); + startActivity(intent); + finishAffinity(); + } +} diff --git a/src/com/android/settings/deviceinfo/StorageWizardMoveProgress.java b/src/com/android/settings/deviceinfo/StorageWizardMoveProgress.java new file mode 100644 index 00000000000..20233357c2a --- /dev/null +++ b/src/com/android/settings/deviceinfo/StorageWizardMoveProgress.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2015 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.settings.deviceinfo; + +import static com.android.settings.deviceinfo.StorageSettings.TAG; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageMoveObserver; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.RemoteException; +import android.os.storage.VolumeInfo; +import android.util.Log; +import android.view.View; +import android.widget.Toast; + +import com.android.internal.util.Preconditions; +import com.android.settings.R; + +import java.util.concurrent.CountDownLatch; + +public class StorageWizardMoveProgress extends StorageWizardBase { + private String mPackageName; + private ApplicationInfo mApp; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.storage_wizard_progress); + + try { + mPackageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME); + mApp = getPackageManager().getApplicationInfo(mPackageName, 0); + } catch (NameNotFoundException e) { + throw new RuntimeException(e); + } + + Preconditions.checkNotNull(mVolume); + Preconditions.checkNotNull(mApp); + + final String appName = getPackageManager().getApplicationLabel(mApp).toString(); + final String volumeName = mStorage.getBestVolumeDescription(mVolume); + + setHeaderText(R.string.storage_wizard_move_progress_title, appName); + setBodyText(R.string.storage_wizard_move_progress_body, volumeName, appName); + + setCurrentProgress(20); + + getNextButton().setVisibility(View.GONE); + + new MoveTask().execute(); + } + + private CharSequence moveStatusToMessage(int returnCode) { + switch (returnCode) { + case PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE: + return getString(R.string.insufficient_storage); + case PackageManager.MOVE_FAILED_DOESNT_EXIST: + return getString(R.string.does_not_exist); + case PackageManager.MOVE_FAILED_FORWARD_LOCKED: + return getString(R.string.app_forward_locked); + case PackageManager.MOVE_FAILED_INVALID_LOCATION: + return getString(R.string.invalid_location); + case PackageManager.MOVE_FAILED_SYSTEM_PACKAGE: + return getString(R.string.system_package); + case PackageManager.MOVE_FAILED_INTERNAL_ERROR: + default: + return getString(R.string.insufficient_storage); + } + } + + private class LocalPackageMoveObserver extends IPackageMoveObserver.Stub { + public int returnCode; + public CountDownLatch finished = new CountDownLatch(1); + + @Override + public void packageMoved(String packageName, int returnCode) throws RemoteException { + this.returnCode = returnCode; + this.finished.countDown(); + } + } + + public class MoveTask extends AsyncTask { + @Override + protected Integer doInBackground(Void... params) { + try { + final LocalPackageMoveObserver observer = new LocalPackageMoveObserver(); + + if (mApp.isExternalAsec()) { + getPackageManager().movePackage(mPackageName, observer, + PackageManager.MOVE_INTERNAL); + } else if (mVolume.getType() == VolumeInfo.TYPE_PUBLIC) { + getPackageManager().movePackage(mPackageName, observer, + PackageManager.MOVE_EXTERNAL_MEDIA); + } else { + getPackageManager().movePackageAndData(mPackageName, mVolume.fsUuid, observer); + } + + observer.finished.await(); + return observer.returnCode; + } catch (Exception e) { + Log.e(TAG, "Failed to move", e); + return PackageManager.MOVE_FAILED_INTERNAL_ERROR; + } + } + + @Override + protected void onPostExecute(Integer returnCode) { + final Context context = StorageWizardMoveProgress.this; + if (returnCode == PackageManager.MOVE_SUCCEEDED) { + finishAffinity(); + + } else { + Log.w(TAG, "Move failed with status " + returnCode); + Toast.makeText(context, moveStatusToMessage(returnCode), Toast.LENGTH_LONG).show(); + finishAffinity(); + } + } + } +}