am b36586a7: Split some VolumeInfo state into VolumeRecord.

* commit 'b36586a7c9b7718f33961406537e27bbd9b16211':
  Split some VolumeInfo state into VolumeRecord.
This commit is contained in:
Jeff Sharkey
2015-04-29 05:29:50 +00:00
committed by Android Git Automerger
14 changed files with 665 additions and 278 deletions

View File

@@ -79,6 +79,7 @@ import android.view.Display;
import dalvik.system.VMRuntime;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.Preconditions;
import com.android.internal.util.UserIcons;
@@ -2054,8 +2055,7 @@ final class ApplicationPackageManager extends PackageManager {
/** {@hide} */
private static class MoveCallbackDelegate extends IPackageMoveObserver.Stub implements
Handler.Callback {
private static final int MSG_STARTED = 1;
private static final int MSG_STATUS_CHANGED = 2;
private static final int MSG_STATUS_CHANGED = 1;
final MoveCallback mCallback;
final Handler mHandler;
@@ -2067,26 +2067,25 @@ final class ApplicationPackageManager extends PackageManager {
@Override
public boolean handleMessage(Message msg) {
final int moveId = msg.arg1;
switch (msg.what) {
case MSG_STARTED:
mCallback.onStarted(moveId, (String) msg.obj);
return true;
case MSG_STATUS_CHANGED:
mCallback.onStatusChanged(moveId, msg.arg2, (long) msg.obj);
final SomeArgs args = (SomeArgs) msg.obj;
mCallback.onStatusChanged(args.argi1, (String) args.arg2, args.argi3,
(long) args.arg4);
args.recycle();
return true;
}
return false;
}
@Override
public void onStarted(int moveId, String title) {
mHandler.obtainMessage(MSG_STARTED, moveId, 0, title).sendToTarget();
}
@Override
public void onStatusChanged(int moveId, int status, long estMillis) {
mHandler.obtainMessage(MSG_STATUS_CHANGED, moveId, status, estMillis).sendToTarget();
public void onStatusChanged(int moveId, String moveTitle, int status, long estMillis) {
final SomeArgs args = SomeArgs.obtain();
args.argi1 = moveId;
args.arg2 = moveTitle;
args.argi3 = status;
args.arg4 = estMillis;
mHandler.obtainMessage(MSG_STATUS_CHANGED, args).sendToTarget();
}
}

View File

@@ -22,6 +22,5 @@ package android.content.pm;
* @hide
*/
oneway interface IPackageMoveObserver {
void onStarted(int moveId, String title);
void onStatusChanged(int moveId, int status, long estMillis);
void onStatusChanged(int moveId, String moveTitle, int status, long estMillis);
}

View File

@@ -4212,8 +4212,8 @@ public abstract class PackageManager {
/** {@hide} */
public static abstract class MoveCallback {
public abstract void onStarted(int moveId, String title);
public abstract void onStatusChanged(int moveId, int status, long estMillis);
public abstract void onStatusChanged(int moveId, String moveTitle, int status,
long estMillis);
}
/** {@hide} */

View File

@@ -941,6 +941,24 @@ public interface IMountService extends IInterface {
return _result;
}
@Override
public VolumeRecord[] getVolumeRecords(int _flags) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
VolumeRecord[] _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(_flags);
mRemote.transact(Stub.TRANSACTION_getVolumeRecords, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArray(VolumeRecord.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override
public void mount(String volId) throws RemoteException {
Parcel _data = Parcel.obtain();
@@ -1033,12 +1051,12 @@ public interface IMountService extends IInterface {
}
@Override
public void setVolumeNickname(String volId, String nickname) throws RemoteException {
public void setVolumeNickname(String fsUuid, String nickname) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(volId);
_data.writeString(fsUuid);
_data.writeString(nickname);
mRemote.transact(Stub.TRANSACTION_setVolumeNickname, _data, _reply, 0);
_reply.readException();
@@ -1049,12 +1067,12 @@ public interface IMountService extends IInterface {
}
@Override
public void setVolumeUserFlags(String volId, int flags, int mask) throws RemoteException {
public void setVolumeUserFlags(String fsUuid, int flags, int mask) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(volId);
_data.writeString(fsUuid);
_data.writeInt(flags);
_data.writeInt(mask);
mRemote.transact(Stub.TRANSACTION_setVolumeUserFlags, _data, _reply, 0);
@@ -1065,6 +1083,21 @@ public interface IMountService extends IInterface {
}
}
@Override
public void forgetVolume(String fsUuid) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(fsUuid);
mRemote.transact(Stub.TRANSACTION_forgetVolume, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public String getPrimaryStorageUuid() throws RemoteException {
Parcel _data = Parcel.obtain();
@@ -1192,20 +1225,22 @@ public interface IMountService extends IInterface {
static final int TRANSACTION_getDisks = IBinder.FIRST_CALL_TRANSACTION + 44;
static final int TRANSACTION_getVolumes = IBinder.FIRST_CALL_TRANSACTION + 45;
static final int TRANSACTION_getVolumeRecords = IBinder.FIRST_CALL_TRANSACTION + 46;
static final int TRANSACTION_mount = IBinder.FIRST_CALL_TRANSACTION + 46;
static final int TRANSACTION_unmount = IBinder.FIRST_CALL_TRANSACTION + 47;
static final int TRANSACTION_format = IBinder.FIRST_CALL_TRANSACTION + 48;
static final int TRANSACTION_mount = IBinder.FIRST_CALL_TRANSACTION + 47;
static final int TRANSACTION_unmount = IBinder.FIRST_CALL_TRANSACTION + 48;
static final int TRANSACTION_format = IBinder.FIRST_CALL_TRANSACTION + 49;
static final int TRANSACTION_partitionPublic = IBinder.FIRST_CALL_TRANSACTION + 49;
static final int TRANSACTION_partitionPrivate = IBinder.FIRST_CALL_TRANSACTION + 50;
static final int TRANSACTION_partitionMixed = IBinder.FIRST_CALL_TRANSACTION + 51;
static final int TRANSACTION_partitionPublic = IBinder.FIRST_CALL_TRANSACTION + 50;
static final int TRANSACTION_partitionPrivate = IBinder.FIRST_CALL_TRANSACTION + 51;
static final int TRANSACTION_partitionMixed = IBinder.FIRST_CALL_TRANSACTION + 52;
static final int TRANSACTION_setVolumeNickname = IBinder.FIRST_CALL_TRANSACTION + 52;
static final int TRANSACTION_setVolumeUserFlags = IBinder.FIRST_CALL_TRANSACTION + 53;
static final int TRANSACTION_setVolumeNickname = IBinder.FIRST_CALL_TRANSACTION + 53;
static final int TRANSACTION_setVolumeUserFlags = IBinder.FIRST_CALL_TRANSACTION + 54;
static final int TRANSACTION_forgetVolume = IBinder.FIRST_CALL_TRANSACTION + 55;
static final int TRANSACTION_getPrimaryStorageUuid = IBinder.FIRST_CALL_TRANSACTION + 54;
static final int TRANSACTION_setPrimaryStorageUuid = IBinder.FIRST_CALL_TRANSACTION + 55;
static final int TRANSACTION_getPrimaryStorageUuid = IBinder.FIRST_CALL_TRANSACTION + 56;
static final int TRANSACTION_setPrimaryStorageUuid = IBinder.FIRST_CALL_TRANSACTION + 57;
/**
* Cast an IBinder object into an IMountService interface, generating a
@@ -1647,6 +1682,14 @@ public interface IMountService extends IInterface {
reply.writeTypedArray(volumes, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
return true;
}
case TRANSACTION_getVolumeRecords: {
data.enforceInterface(DESCRIPTOR);
int _flags = data.readInt();
VolumeRecord[] volumes = getVolumeRecords(_flags);
reply.writeNoException();
reply.writeTypedArray(volumes, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
return true;
}
case TRANSACTION_mount: {
data.enforceInterface(DESCRIPTOR);
String volId = data.readString();
@@ -1707,6 +1750,13 @@ public interface IMountService extends IInterface {
reply.writeNoException();
return true;
}
case TRANSACTION_forgetVolume: {
data.enforceInterface(DESCRIPTOR);
String fsUuid = data.readString();
forgetVolume(fsUuid);
reply.writeNoException();
return true;
}
case TRANSACTION_getPrimaryStorageUuid: {
data.enforceInterface(DESCRIPTOR);
String volumeUuid = getPrimaryStorageUuid();
@@ -2012,6 +2062,7 @@ public interface IMountService extends IInterface {
public DiskInfo[] getDisks() throws RemoteException;
public VolumeInfo[] getVolumes(int flags) throws RemoteException;
public VolumeRecord[] getVolumeRecords(int flags) throws RemoteException;
public void mount(String volId) throws RemoteException;
public void unmount(String volId) throws RemoteException;
@@ -2021,8 +2072,9 @@ public interface IMountService extends IInterface {
public void partitionPrivate(String diskId) throws RemoteException;
public void partitionMixed(String diskId, int ratio) throws RemoteException;
public void setVolumeNickname(String volId, String nickname) throws RemoteException;
public void setVolumeUserFlags(String volId, int flags, int mask) throws RemoteException;
public void setVolumeNickname(String fsUuid, String nickname) throws RemoteException;
public void setVolumeUserFlags(String fsUuid, int flags, int mask) throws RemoteException;
public void forgetVolume(String fsUuid) throws RemoteException;
public String getPrimaryStorageUuid() throws RemoteException;
public void setPrimaryStorageUuid(String volumeUuid, IPackageMoveObserver callback)

View File

@@ -93,8 +93,8 @@ public interface IMountServiceListener extends IInterface {
}
case TRANSACTION_onVolumeMetadataChanged: {
data.enforceInterface(DESCRIPTOR);
final VolumeInfo vol = (VolumeInfo) data.readParcelable(null);
onVolumeMetadataChanged(vol);
final String fsUuid = data.readString();
onVolumeMetadataChanged(fsUuid);
reply.writeNoException();
return true;
}
@@ -192,12 +192,12 @@ public interface IMountServiceListener extends IInterface {
}
@Override
public void onVolumeMetadataChanged(VolumeInfo vol) throws RemoteException {
public void onVolumeMetadataChanged(String fsUuid) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeParcelable(vol, 0);
_data.writeString(fsUuid);
mRemote.transact(Stub.TRANSACTION_onVolumeMetadataChanged, _data, _reply,
android.os.IBinder.FLAG_ONEWAY);
_reply.readException();
@@ -253,7 +253,7 @@ public interface IMountServiceListener extends IInterface {
public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState)
throws RemoteException;
public void onVolumeMetadataChanged(VolumeInfo vol) throws RemoteException;
public void onVolumeMetadataChanged(String fsUuid) throws RemoteException;
public void onDiskScanned(DiskInfo disk, int volumeCount) throws RemoteException;
}

View File

@@ -41,7 +41,7 @@ public class StorageEventListener {
public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
}
public void onVolumeMetadataChanged(VolumeInfo vol) {
public void onVolumeMetadataChanged(String fsUuid) {
}
public void onDiskScanned(DiskInfo disk, int volumeCount) {

View File

@@ -79,9 +79,6 @@ public class StorageManager {
/** {@hide} */
public static final String UUID_PRIMARY_PHYSICAL = "primary_physical";
/** {@hide} */
public static final int FLAG_ALL_METADATA = 1 << 0;
private final Context mContext;
private final ContentResolver mResolver;
@@ -120,7 +117,7 @@ public class StorageManager {
args.recycle();
return true;
case MSG_VOLUME_METADATA_CHANGED:
mCallback.onVolumeMetadataChanged((VolumeInfo) args.arg1);
mCallback.onVolumeMetadataChanged((String) args.arg1);
args.recycle();
return true;
case MSG_DISK_SCANNED:
@@ -156,9 +153,9 @@ public class StorageManager {
}
@Override
public void onVolumeMetadataChanged(VolumeInfo vol) {
public void onVolumeMetadataChanged(String fsUuid) {
final SomeArgs args = SomeArgs.obtain();
args.arg1 = vol;
args.arg1 = fsUuid;
mHandler.obtainMessage(MSG_VOLUME_METADATA_CHANGED, args).sendToTarget();
}
@@ -515,6 +512,18 @@ public class StorageManager {
return null;
}
/** {@hide} */
public @Nullable VolumeRecord findRecordByUuid(String fsUuid) {
Preconditions.checkNotNull(fsUuid);
// TODO; go directly to service to make this faster
for (VolumeRecord rec : getVolumeRecords()) {
if (Objects.equals(rec.fsUuid, fsUuid)) {
return rec;
}
}
return null;
}
/** {@hide} */
public @Nullable VolumeInfo findPrivateForEmulated(VolumeInfo emulatedVol) {
return findVolumeById(emulatedVol.getId().replace("emulated", "private"));
@@ -527,13 +536,17 @@ public class StorageManager {
/** {@hide} */
public @NonNull List<VolumeInfo> getVolumes() {
return getVolumes(0);
try {
return Arrays.asList(mMountService.getVolumes(0));
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/** {@hide} */
public @NonNull List<VolumeInfo> getVolumes(int flags) {
public @NonNull List<VolumeRecord> getVolumeRecords() {
try {
return Arrays.asList(mMountService.getVolumes(flags));
return Arrays.asList(mMountService.getVolumeRecords(0));
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -541,13 +554,23 @@ public class StorageManager {
/** {@hide} */
public @Nullable String getBestVolumeDescription(VolumeInfo vol) {
String descrip = vol.getDescription();
if (vol.disk != null) {
if (TextUtils.isEmpty(descrip)) {
descrip = vol.disk.getDescription();
// Nickname always takes precedence when defined
if (!TextUtils.isEmpty(vol.fsUuid)) {
final VolumeRecord rec = findRecordByUuid(vol.fsUuid);
if (!TextUtils.isEmpty(rec.nickname)) {
return rec.nickname;
}
}
return descrip;
if (!TextUtils.isEmpty(vol.getDescription())) {
return vol.getDescription();
}
if (vol.disk != null) {
return vol.disk.getDescription();
}
return null;
}
/** {@hide} */
@@ -616,29 +639,38 @@ public class StorageManager {
}
/** {@hide} */
public void setVolumeNickname(String volId, String nickname) {
public void setVolumeNickname(String fsUuid, String nickname) {
try {
mMountService.setVolumeNickname(volId, nickname);
mMountService.setVolumeNickname(fsUuid, nickname);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/** {@hide} */
public void setVolumeInited(String volId, boolean inited) {
public void setVolumeInited(String fsUuid, boolean inited) {
try {
mMountService.setVolumeUserFlags(volId, inited ? VolumeInfo.USER_FLAG_INITED : 0,
VolumeInfo.USER_FLAG_INITED);
mMountService.setVolumeUserFlags(fsUuid, inited ? VolumeRecord.USER_FLAG_INITED : 0,
VolumeRecord.USER_FLAG_INITED);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/** {@hide} */
public void setVolumeSnoozed(String volId, boolean snoozed) {
public void setVolumeSnoozed(String fsUuid, boolean snoozed) {
try {
mMountService.setVolumeUserFlags(volId, snoozed ? VolumeInfo.USER_FLAG_SNOOZED : 0,
VolumeInfo.USER_FLAG_SNOOZED);
mMountService.setVolumeUserFlags(fsUuid, snoozed ? VolumeRecord.USER_FLAG_SNOOZED : 0,
VolumeRecord.USER_FLAG_SNOOZED);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/** {@hide} */
public void forgetVolume(String fsUuid) {
try {
mMountService.forgetVolume(fsUuid);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}

View File

@@ -78,9 +78,6 @@ public class VolumeInfo implements Parcelable {
public static final int MOUNT_FLAG_PRIMARY = 1 << 0;
public static final int MOUNT_FLAG_VISIBLE = 1 << 1;
public static final int USER_FLAG_INITED = 1 << 0;
public static final int USER_FLAG_SNOOZED = 1 << 1;
private static SparseArray<String> sStateToEnvironment = new SparseArray<>();
private static ArrayMap<String, String> sEnvironmentToBroadcast = new ArrayMap<>();
@@ -135,8 +132,6 @@ public class VolumeInfo implements Parcelable {
/** Framework state */
public final int mtpIndex;
public String nickname;
public int userFlags = 0;
public VolumeInfo(String id, int type, DiskInfo disk, int mtpIndex) {
this.id = Preconditions.checkNotNull(id);
@@ -161,8 +156,6 @@ public class VolumeInfo implements Parcelable {
fsLabel = parcel.readString();
path = parcel.readString();
mtpIndex = parcel.readInt();
nickname = parcel.readString();
userFlags = parcel.readInt();
}
public static @NonNull String getEnvironmentForState(int state) {
@@ -210,10 +203,6 @@ public class VolumeInfo implements Parcelable {
return fsUuid;
}
public @Nullable String getNickname() {
return nickname;
}
public int getMountUserId() {
return mountUserId;
}
@@ -221,8 +210,6 @@ public class VolumeInfo implements Parcelable {
public @Nullable String getDescription() {
if (ID_PRIVATE_INTERNAL.equals(id)) {
return Resources.getSystem().getString(com.android.internal.R.string.storage_internal);
} else if (!TextUtils.isEmpty(nickname)) {
return nickname;
} else if (!TextUtils.isEmpty(fsLabel)) {
return fsLabel;
} else {
@@ -250,14 +237,6 @@ public class VolumeInfo implements Parcelable {
return (mountFlags & MOUNT_FLAG_VISIBLE) != 0;
}
public boolean isInited() {
return (userFlags & USER_FLAG_INITED) != 0;
}
public boolean isSnoozed() {
return (userFlags & USER_FLAG_SNOOZED) != 0;
}
public boolean isVisibleToUser(int userId) {
if (type == TYPE_PUBLIC && userId == this.mountUserId) {
return isVisible();
@@ -394,8 +373,6 @@ public class VolumeInfo implements Parcelable {
pw.println();
pw.printPair("path", path);
pw.printPair("mtpIndex", mtpIndex);
pw.printPair("nickname", nickname);
pw.printPair("userFlags", DebugUtils.flagsToString(getClass(), "USER_FLAG_", userFlags));
pw.decreaseIndent();
pw.println();
}
@@ -461,7 +438,5 @@ public class VolumeInfo implements Parcelable {
parcel.writeString(fsLabel);
parcel.writeString(path);
parcel.writeInt(mtpIndex);
parcel.writeString(nickname);
parcel.writeInt(userFlags);
}
}

View File

@@ -0,0 +1,139 @@
/*
* 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 android.os.storage;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.DebugUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import java.util.Objects;
/**
* Notes for a storage volume which may not be currently present.
*
* @hide
*/
public class VolumeRecord implements Parcelable {
public static final String EXTRA_FS_UUID =
"android.os.storage.extra.FS_UUID";
public static final int USER_FLAG_INITED = 1 << 0;
public static final int USER_FLAG_SNOOZED = 1 << 1;
public final int type;
public final String fsUuid;
public String nickname;
public int userFlags;
public VolumeRecord(int type, String fsUuid) {
this.type = type;
this.fsUuid = Preconditions.checkNotNull(fsUuid);
}
public VolumeRecord(Parcel parcel) {
type = parcel.readInt();
fsUuid = parcel.readString();
nickname = parcel.readString();
userFlags = parcel.readInt();
}
public int getType() {
return type;
}
public String getFsUuid() {
return fsUuid;
}
public String getNickname() {
return nickname;
}
public boolean isInited() {
return (userFlags & USER_FLAG_INITED) != 0;
}
public boolean isSnoozed() {
return (userFlags & USER_FLAG_SNOOZED) != 0;
}
public void dump(IndentingPrintWriter pw) {
pw.println("VolumeRecord:");
pw.increaseIndent();
pw.printPair("type", DebugUtils.valueToString(VolumeInfo.class, "TYPE_", type));
pw.printPair("fsUuid", fsUuid);
pw.printPair("nickname", nickname);
pw.printPair("userFlags",
DebugUtils.flagsToString(VolumeRecord.class, "USER_FLAG_", userFlags));
pw.decreaseIndent();
pw.println();
}
@Override
public VolumeRecord clone() {
final Parcel temp = Parcel.obtain();
try {
writeToParcel(temp, 0);
temp.setDataPosition(0);
return CREATOR.createFromParcel(temp);
} finally {
temp.recycle();
}
}
@Override
public boolean equals(Object o) {
if (o instanceof VolumeRecord) {
return Objects.equals(fsUuid, ((VolumeRecord) o).fsUuid);
} else {
return false;
}
}
@Override
public int hashCode() {
return fsUuid.hashCode();
}
public static final Creator<VolumeRecord> CREATOR = new Creator<VolumeRecord>() {
@Override
public VolumeRecord createFromParcel(Parcel in) {
return new VolumeRecord(in);
}
@Override
public VolumeRecord[] newArray(int size) {
return new VolumeRecord[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(type);
parcel.writeString(fsUuid);
parcel.writeString(nickname);
parcel.writeInt(userFlags);
}
}

View File

@@ -3012,6 +3012,26 @@
<!-- Notification action to browse external media [CHAR LIMIT=20] -->
<string name="ext_media_browse_action">Explore</string>
<!-- Notification title when external media is missing [CHAR LIMIT=30] -->
<string name="ext_media_missing_title"><xliff:g id="name" example="SD card">%s</xliff:g> missing</string>
<!-- Notification body when external media is missing [CHAR LIMIT=30] -->
<string name="ext_media_missing_message">Reinsert this device</string>
<!-- Notification title when moving an application to external storage [CHAR LIMIT=30] -->
<string name="ext_media_move_specific_title">Moving <xliff:g id="name" example="Calculator">%s</xliff:g></string>
<!-- Notification title when moving data to external storage [CHAR LIMIT=32] -->
<string name="ext_media_move_title">Moving data</string>
<!-- Notification title when moving data to external storage [CHAR LIMIT=32] -->
<string name="ext_media_move_success_title">Move complete</string>
<!-- Notification title when moving data to external storage [CHAR LIMIT=64] -->
<string name="ext_media_move_success_message">Data moved to <xliff:g id="name" example="SD card">%s</xliff:g></string>
<!-- Notification title when moving data to external storage failed [CHAR LIMIT=32] -->
<string name="ext_media_move_failure_title">Couldn\'t move data</string>
<!-- Notification title when moving data to external storage failed [CHAR LIMIT=64] -->
<string name="ext_media_move_failure_message">Data left at original location</string>
<!-- Shown in LauncherActivity when the requested target Intent didn't return any matching Activities, leaving the list empty. -->
<string name="activity_list_empty">No matching activities found.</string>

View File

@@ -1899,6 +1899,14 @@
<java-symbol type="string" name="ext_media_init_action" />
<java-symbol type="string" name="ext_media_unmount_action" />
<java-symbol type="string" name="ext_media_browse_action" />
<java-symbol type="string" name="ext_media_missing_title" />
<java-symbol type="string" name="ext_media_missing_message" />
<java-symbol type="string" name="ext_media_move_specific_title" />
<java-symbol type="string" name="ext_media_move_title" />
<java-symbol type="string" name="ext_media_move_success_title" />
<java-symbol type="string" name="ext_media_move_success_message" />
<java-symbol type="string" name="ext_media_move_failure_title" />
<java-symbol type="string" name="ext_media_move_failure_message" />
<java-symbol type="string" name="usb_storage_error_message" />
<java-symbol type="string" name="usb_storage_message" />
<java-symbol type="string" name="usb_storage_notification_message" />

View File

@@ -24,11 +24,17 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.MoveCallback;
import android.os.Handler;
import android.os.UserHandle;
import android.os.storage.DiskInfo;
import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
import com.android.internal.R;
@@ -39,12 +45,14 @@ import java.util.List;
public class StorageNotification extends SystemUI {
private static final String TAG = "StorageNotification";
private static final int NOTIF_ID = 0x53544f52; // STOR
private static final int PUBLIC_ID = 0x53505542; // SPUB
private static final int PRIVATE_ID = 0x53505256; // SPRV
private static final int DISK_ID = 0x5344534b; // SDSK
private static final int MOVE_ID = 0x534d4f56; // SMOV
private static final String ACTION_SNOOZE_VOLUME = "com.android.systemui.action.SNOOZE_VOLUME";
// TODO: delay some notifications to avoid bumpy fast operations
// TODO: annoy user when private media is missing
private NotificationManager mNotificationManager;
private StorageManager mStorageManager;
@@ -52,17 +60,29 @@ public class StorageNotification extends SystemUI {
private final StorageEventListener mListener = new StorageEventListener() {
@Override
public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
onVolumeStateChangedInternal(vol, oldState, newState);
onVolumeStateChangedInternal(vol);
}
@Override
public void onVolumeMetadataChanged(VolumeInfo vol) {
public void onVolumeMetadataChanged(String fsUuid) {
// Avoid kicking notifications when getting early metadata before
// mounted. If already mounted, we're being kicked because of a
// nickname or init'ed change.
if (vol.isMountedReadable()) {
onVolumeStateChangedInternal(vol, vol.getState(), vol.getState());
final VolumeInfo vol = mStorageManager.findVolumeByUuid(fsUuid);
if (vol != null && vol.isMountedReadable()) {
onVolumeStateChangedInternal(vol);
}
final VolumeRecord rec = mStorageManager.findRecordByUuid(fsUuid);
if (rec == null) {
// Private volume was probably just forgotten
mNotificationManager.cancelAsUser(fsUuid, PRIVATE_ID, UserHandle.ALL);
}
}
@Override
public void onDiskScanned(DiskInfo disk, int volumeCount) {
onDiskScannedInternal(disk, volumeCount);
}
};
@@ -70,8 +90,19 @@ public class StorageNotification extends SystemUI {
@Override
public void onReceive(Context context, Intent intent) {
// TODO: kick this onto background thread
final String volId = intent.getStringExtra(VolumeInfo.EXTRA_VOLUME_ID);
mStorageManager.setVolumeSnoozed(volId, true);
final String fsUuid = intent.getStringExtra(VolumeRecord.EXTRA_FS_UUID);
mStorageManager.setVolumeSnoozed(fsUuid, true);
}
};
private final MoveCallback mMoveCallback = new MoveCallback() {
@Override
public void onStatusChanged(int moveId, String moveTitle, int status, long estMillis) {
if (PackageManager.isMoveStatusFinished(status)) {
onMoveFinished(moveId, moveTitle, status);
} else {
onMoveProgress(moveId, moveTitle, status, estMillis);
}
}
};
@@ -88,20 +119,99 @@ public class StorageNotification extends SystemUI {
// Kick current state into place
final List<VolumeInfo> vols = mStorageManager.getVolumes();
for (VolumeInfo vol : vols) {
onVolumeStateChangedInternal(vol, vol.getState(), vol.getState());
onVolumeStateChangedInternal(vol);
}
mContext.getPackageManager().registerMoveCallback(mMoveCallback, new Handler());
updateMissingPrivateVolumes();
}
private void updateMissingPrivateVolumes() {
final List<VolumeRecord> recs = mStorageManager.getVolumeRecords();
for (VolumeRecord rec : recs) {
if (rec.getType() != VolumeInfo.TYPE_PRIVATE) continue;
final String fsUuid = rec.getFsUuid();
final VolumeInfo info = mStorageManager.findVolumeByUuid(fsUuid);
if (info != null && info.isMountedWritable()) {
// Yay, private volume is here!
mNotificationManager.cancelAsUser(fsUuid, PRIVATE_ID, UserHandle.ALL);
} else {
// Boo, annoy the user to reinsert the private volume
final CharSequence title = mContext.getString(R.string.ext_media_missing_title,
rec.getNickname());
final CharSequence text = mContext.getString(R.string.ext_media_missing_message);
final Notification notif = new Notification.Builder(mContext)
.setSmallIcon(R.drawable.stat_notify_sdcard)
.setColor(mContext.getColor(R.color.system_notification_accent_color))
.setContentTitle(title)
.setContentText(text)
.setStyle(new Notification.BigTextStyle().bigText(text))
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setLocalOnly(true)
.setContentIntent(buildForgetPendingIntent(rec))
.setCategory(Notification.CATEGORY_SYSTEM)
.setOngoing(true)
.build();
mNotificationManager.notifyAsUser(fsUuid, PRIVATE_ID, notif, UserHandle.ALL);
}
}
}
public void onVolumeStateChangedInternal(VolumeInfo vol, int oldState, int newState) {
// We only care about public volumes
if (vol.getType() != VolumeInfo.TYPE_PUBLIC) {
return;
}
private void onDiskScannedInternal(DiskInfo disk, int volumeCount) {
if (volumeCount == 0) {
// No supported volumes found, give user option to format
final CharSequence title = mContext.getString(
R.string.ext_media_unmountable_notification_title, disk.getDescription());
final CharSequence text = mContext.getString(
R.string.ext_media_unmountable_notification_message, disk.getDescription());
Log.d(TAG, vol.toString());
final Notification notif = new Notification.Builder(mContext)
.setSmallIcon(getSmallIcon(disk, VolumeInfo.STATE_UNMOUNTABLE))
.setColor(mContext.getColor(R.color.system_notification_accent_color))
.setContentTitle(title)
.setContentText(text)
.setStyle(new Notification.BigTextStyle().bigText(text))
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setLocalOnly(true)
.setContentIntent(buildInitPendingIntent(disk))
.setCategory(Notification.CATEGORY_ERROR)
.build();
mNotificationManager.notifyAsUser(disk.getId(), DISK_ID, notif, UserHandle.ALL);
} else {
// Yay, we have volumes!
mNotificationManager.cancelAsUser(disk.getId(), DISK_ID, UserHandle.ALL);
}
}
private void onVolumeStateChangedInternal(VolumeInfo vol) {
switch (vol.getType()) {
case VolumeInfo.TYPE_PRIVATE:
onPrivateVolumeStateChangedInternal(vol);
break;
case VolumeInfo.TYPE_PUBLIC:
onPublicVolumeStateChangedInternal(vol);
break;
}
}
private void onPrivateVolumeStateChangedInternal(VolumeInfo vol) {
Log.d(TAG, "Notifying about private volume: " + vol.toString());
updateMissingPrivateVolumes();
}
private void onPublicVolumeStateChangedInternal(VolumeInfo vol) {
Log.d(TAG, "Notifying about public volume: " + vol.toString());
final Notification notif;
switch (newState) {
switch (vol.getState()) {
case VolumeInfo.STATE_UNMOUNTED:
notif = onVolumeUnmounted(vol);
break;
@@ -133,9 +243,9 @@ public class StorageNotification extends SystemUI {
}
if (notif != null) {
mNotificationManager.notifyAsUser(vol.getId(), NOTIF_ID, notif, UserHandle.ALL);
mNotificationManager.notifyAsUser(vol.getId(), PUBLIC_ID, notif, UserHandle.ALL);
} else {
mNotificationManager.cancelAsUser(vol.getId(), NOTIF_ID, UserHandle.ALL);
mNotificationManager.cancelAsUser(vol.getId(), PUBLIC_ID, UserHandle.ALL);
}
}
@@ -159,20 +269,24 @@ public class StorageNotification extends SystemUI {
}
private Notification onVolumeMounted(VolumeInfo vol) {
final VolumeRecord rec = mStorageManager.findRecordByUuid(vol.getFsUuid());
// Don't annoy when user dismissed in past
if (vol.isSnoozed()) return null;
if (rec.isSnoozed()) return null;
final DiskInfo disk = vol.getDisk();
if (disk.isAdoptable() && !vol.isInited()) {
if (disk.isAdoptable() && !rec.isInited()) {
final CharSequence title = disk.getDescription();
final CharSequence text = mContext.getString(
R.string.ext_media_new_notification_message, disk.getDescription());
final PendingIntent initAction = buildInitPendingIntent(vol);
return buildNotificationBuilder(vol, title, text)
.addAction(new Action(0, mContext.getString(R.string.ext_media_init_action),
buildInitPendingIntent(vol)))
initAction))
.addAction(new Action(0, mContext.getString(R.string.ext_media_unmount_action),
buildUnmountPendingIntent(vol)))
.setContentIntent(initAction)
.setDeleteIntent(buildSnoozeIntent(vol))
.setCategory(Notification.CATEGORY_SYSTEM)
.build();
@@ -182,11 +296,13 @@ public class StorageNotification extends SystemUI {
final CharSequence text = mContext.getString(
R.string.ext_media_ready_notification_message, disk.getDescription());
final PendingIntent browseAction = buildBrowsePendingIntent(vol);
return buildNotificationBuilder(vol, title, text)
.addAction(new Action(0, mContext.getString(R.string.ext_media_browse_action),
buildBrowsePendingIntent(vol)))
browseAction))
.addAction(new Action(0, mContext.getString(R.string.ext_media_unmount_action),
buildUnmountPendingIntent(vol)))
.setContentIntent(browseAction)
.setDeleteIntent(buildSnoozeIntent(vol))
.setCategory(Notification.CATEGORY_SYSTEM)
.setPriority(Notification.PRIORITY_LOW)
@@ -260,16 +376,84 @@ public class StorageNotification extends SystemUI {
.build();
}
private int getSmallIcon(VolumeInfo vol) {
if (vol.disk.isSd()) {
switch (vol.getState()) {
private void onMoveProgress(int moveId, String moveTitle, int status, long estMillis) {
final CharSequence title;
if (!TextUtils.isEmpty(moveTitle)) {
title = mContext.getString(R.string.ext_media_move_specific_title, moveTitle);
} else {
title = mContext.getString(R.string.ext_media_move_title);
}
final CharSequence text;
if (estMillis < 0) {
text = null;
} else {
text = DateUtils.formatDuration(estMillis);
}
final Notification notif = new Notification.Builder(mContext)
.setSmallIcon(R.drawable.stat_notify_sdcard)
.setColor(mContext.getColor(R.color.system_notification_accent_color))
.setContentTitle(title)
.setContentText(text)
.setStyle(new Notification.BigTextStyle().bigText(text))
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setLocalOnly(true)
.setCategory(Notification.CATEGORY_PROGRESS)
.setPriority(Notification.PRIORITY_LOW)
.setProgress(100, status, false)
.setOngoing(true)
.build();
mNotificationManager.notifyAsUser(moveTitle, MOVE_ID, notif, UserHandle.ALL);
}
private void onMoveFinished(int moveId, String moveTitle, int status) {
if (!TextUtils.isEmpty(moveTitle)) {
// We currently ignore finished app moves; just clear the last
// published progress
mNotificationManager.cancelAsUser(moveTitle, MOVE_ID, UserHandle.ALL);
return;
}
final VolumeInfo vol = mContext.getPackageManager().getPrimaryStorageCurrentVolume();
final String descrip = mStorageManager.getBestVolumeDescription(vol);
final CharSequence title;
final CharSequence text;
if (status == PackageManager.MOVE_SUCCEEDED) {
title = mContext.getString(R.string.ext_media_move_success_title);
text = mContext.getString(R.string.ext_media_move_success_message, descrip);
} else {
title = mContext.getString(R.string.ext_media_move_failure_title);
text = mContext.getString(R.string.ext_media_move_failure_message);
}
final Notification notif = new Notification.Builder(mContext)
.setSmallIcon(R.drawable.stat_notify_sdcard)
.setColor(mContext.getColor(R.color.system_notification_accent_color))
.setContentTitle(title)
.setContentText(text)
.setStyle(new Notification.BigTextStyle().bigText(text))
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setLocalOnly(true)
.setCategory(Notification.CATEGORY_SYSTEM)
.setPriority(Notification.PRIORITY_LOW)
.build();
mNotificationManager.notifyAsUser(moveTitle, MOVE_ID, notif, UserHandle.ALL);
}
private int getSmallIcon(DiskInfo disk, int state) {
if (disk.isSd()) {
switch (state) {
case VolumeInfo.STATE_CHECKING:
case VolumeInfo.STATE_EJECTING:
return R.drawable.stat_notify_sdcard_prepare;
default:
return R.drawable.stat_notify_sdcard;
}
} else if (vol.disk.isUsb()) {
} else if (disk.isUsb()) {
return R.drawable.stat_sys_data_usb;
} else {
return R.drawable.stat_notify_sdcard;
@@ -279,7 +463,7 @@ public class StorageNotification extends SystemUI {
private Notification.Builder buildNotificationBuilder(VolumeInfo vol, CharSequence title,
CharSequence text) {
return new Notification.Builder(mContext)
.setSmallIcon(getSmallIcon(vol))
.setSmallIcon(getSmallIcon(vol.getDisk(), vol.getState()))
.setColor(mContext.getColor(R.color.system_notification_accent_color))
.setContentTitle(title)
.setContentText(text)
@@ -288,6 +472,17 @@ public class StorageNotification extends SystemUI {
.setLocalOnly(true);
}
private PendingIntent buildInitPendingIntent(DiskInfo disk) {
final Intent intent = new Intent();
intent.setClassName("com.android.settings",
"com.android.settings.deviceinfo.StorageWizardInit");
intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.getId());
final int requestKey = disk.getId().hashCode();
return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
}
private PendingIntent buildInitPendingIntent(VolumeInfo vol) {
final Intent intent = new Intent();
intent.setClassName("com.android.settings",
@@ -321,7 +516,7 @@ public class StorageNotification extends SystemUI {
private PendingIntent buildDetailsPendingIntent(VolumeInfo vol) {
final Intent intent = new Intent();
intent.setClassName("com.android.settings",
"com.android.settings.Settings$StorageVolumeSettingsActivity");
"com.android.settings.Settings$PublicVolumeSettingsActivity");
intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
final int requestKey = vol.getId().hashCode();
@@ -331,10 +526,21 @@ public class StorageNotification extends SystemUI {
private PendingIntent buildSnoozeIntent(VolumeInfo vol) {
final Intent intent = new Intent(ACTION_SNOOZE_VOLUME);
intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.getFsUuid());
final int requestKey = vol.getId().hashCode();
return PendingIntent.getBroadcastAsUser(mContext, requestKey, intent,
PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.CURRENT);
}
private PendingIntent buildForgetPendingIntent(VolumeRecord rec) {
final Intent intent = new Intent();
intent.setClassName("com.android.settings",
"com.android.settings.Settings$PrivateVolumeForgetActivity");
intent.putExtra(VolumeRecord.EXTRA_FS_UUID, rec.getFsUuid());
final int requestKey = rec.getFsUuid().hashCode();
return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
}
}

View File

@@ -62,11 +62,11 @@ import android.os.storage.StorageManager;
import android.os.storage.StorageResultCode;
import android.os.storage.StorageVolume;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.DebugUtils;
import android.util.Log;
import android.util.Slog;
import android.util.Xml;
@@ -251,49 +251,7 @@ class MountService extends IMountService.Stub
private static final String ATTR_NICKNAME = "nickname";
private static final String ATTR_USER_FLAGS = "userFlags";
private final AtomicFile mMetadataFile;
private static class VolumeMetadata {
public final int type;
public final String fsUuid;
public String nickname;
public int userFlags;
public VolumeMetadata(int type, String fsUuid) {
this.type = type;
this.fsUuid = Preconditions.checkNotNull(fsUuid);
}
public static VolumeMetadata read(XmlPullParser in) throws IOException {
final int type = readIntAttribute(in, ATTR_TYPE);
final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
final VolumeMetadata meta = new VolumeMetadata(type, fsUuid);
meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS);
return meta;
}
public static void write(XmlSerializer out, VolumeMetadata meta) throws IOException {
out.startTag(null, TAG_VOLUME);
writeIntAttribute(out, ATTR_TYPE, meta.type);
writeStringAttribute(out, ATTR_FS_UUID, meta.fsUuid);
writeStringAttribute(out, ATTR_NICKNAME, meta.nickname);
writeIntAttribute(out, ATTR_USER_FLAGS, meta.userFlags);
out.endTag(null, TAG_VOLUME);
}
public void dump(IndentingPrintWriter pw) {
pw.println("VolumeMetadata:");
pw.increaseIndent();
pw.printPair("type", DebugUtils.valueToString(VolumeInfo.class, "TYPE_", type));
pw.printPair("fsUuid", fsUuid);
pw.printPair("nickname", nickname);
pw.printPair("userFlags",
DebugUtils.flagsToString(VolumeInfo.class, "USER_FLAG_", userFlags));
pw.decreaseIndent();
pw.println();
}
}
private final AtomicFile mSettingsFile;
/**
* <em>Never</em> hold the lock while performing downcalls into vold, since
@@ -311,9 +269,9 @@ class MountService extends IMountService.Stub
@GuardedBy("mLock")
private ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
/** Map from UUID to metadata */
/** Map from UUID to record */
@GuardedBy("mLock")
private ArrayMap<String, VolumeMetadata> mMetadata = new ArrayMap<>();
private ArrayMap<String, VolumeRecord> mRecords = new ArrayMap<>();
@GuardedBy("mLock")
private String mPrimaryStorageUuid;
@@ -370,15 +328,6 @@ class MountService extends IMountService.Stub
}
}
private VolumeMetadata findOrCreateMetadataLocked(VolumeInfo vol) {
VolumeMetadata meta = mMetadata.get(vol.fsUuid);
if (meta == null) {
meta = new VolumeMetadata(vol.type, vol.fsUuid);
mMetadata.put(meta.fsUuid, meta);
}
return meta;
}
private CountDownLatch findOrCreateDiskScanLatch(String diskId) {
synchronized (mLock) {
CountDownLatch latch = mDiskScanLatches.get(diskId);
@@ -913,7 +862,7 @@ class MountService extends IMountService.Stub
final int oldState = vol.state;
final int newState = Integer.parseInt(cooked[2]);
vol.state = newState;
onVolumeStateChangedLocked(vol.clone(), oldState, newState);
onVolumeStateChangedLocked(vol, oldState, newState);
}
break;
}
@@ -923,7 +872,6 @@ class MountService extends IMountService.Stub
if (vol != null) {
vol.fsType = cooked[2];
}
mCallbacks.notifyVolumeMetadataChanged(vol.clone());
break;
}
case VoldResponseCode.VOLUME_FS_UUID_CHANGED: {
@@ -932,8 +880,6 @@ class MountService extends IMountService.Stub
if (vol != null) {
vol.fsUuid = cooked[2];
}
refreshMetadataLocked();
mCallbacks.notifyVolumeMetadataChanged(vol.clone());
break;
}
case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: {
@@ -945,7 +891,7 @@ class MountService extends IMountService.Stub
}
vol.fsLabel = builder.toString().trim();
}
mCallbacks.notifyVolumeMetadataChanged(vol.clone());
// TODO: notify listeners that label changed
break;
}
case VoldResponseCode.VOLUME_PATH_CHANGED: {
@@ -1070,6 +1016,19 @@ class MountService extends IMountService.Stub
}
private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
// Remember that we saw this volume so we're ready to accept user
// metadata, or so we can annoy them when a private volume is ejected
if (vol.isMountedReadable() && !TextUtils.isEmpty(vol.fsUuid)) {
if (!mRecords.containsKey(vol.fsUuid)) {
final VolumeRecord rec = new VolumeRecord(vol.type, vol.fsUuid);
if (vol.type == VolumeInfo.TYPE_PRIVATE) {
rec.nickname = vol.disk.getDescription();
}
mRecords.put(rec.fsUuid, rec);
writeSettingsLocked();
}
}
mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
if (isBroadcastWorthy(vol)) {
@@ -1117,7 +1076,7 @@ class MountService extends IMountService.Stub
// TODO: estimate remaining time
try {
mMoveCallback.onStatusChanged(-1, status, -1);
mMoveCallback.onStatusChanged(-1, null, status, -1);
} catch (RemoteException ignored) {
}
@@ -1127,7 +1086,7 @@ class MountService extends IMountService.Stub
Slog.d(TAG, "Move to " + mMoveTargetUuid + " copy phase finshed; persisting");
mPrimaryStorageUuid = mMoveTargetUuid;
writeMetadataLocked();
writeSettingsLocked();
}
if (PackageManager.isMoveStatusFinished(status)) {
@@ -1138,25 +1097,6 @@ class MountService extends IMountService.Stub
}
}
/**
* Refresh latest metadata into any currently active {@link VolumeInfo}.
*/
private void refreshMetadataLocked() {
final int size = mVolumes.size();
for (int i = 0; i < size; i++) {
final VolumeInfo vol = mVolumes.valueAt(i);
final VolumeMetadata meta = mMetadata.get(vol.fsUuid);
if (meta != null) {
vol.nickname = meta.nickname;
vol.userFlags = meta.userFlags;
} else {
vol.nickname = null;
vol.userFlags = 0;
}
}
}
private void enforcePermission(String perm) {
mContext.enforceCallingOrSelfPermission(perm, perm);
}
@@ -1205,11 +1145,11 @@ class MountService extends IMountService.Stub
mLastMaintenance = mLastMaintenanceFile.lastModified();
}
mMetadataFile = new AtomicFile(
mSettingsFile = new AtomicFile(
new File(Environment.getSystemSecureDirectory(), "storage.xml"));
synchronized (mLock) {
readMetadataLocked();
readSettingsLocked();
}
/*
@@ -1235,12 +1175,12 @@ class MountService extends IMountService.Stub
mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
}
private void readMetadataLocked() {
mMetadata.clear();
private void readSettingsLocked() {
mRecords.clear();
FileInputStream fis = null;
try {
fis = mMetadataFile.openRead();
fis = mSettingsFile.openRead();
final XmlPullParser in = Xml.newPullParser();
in.setInput(fis, null);
@@ -1263,8 +1203,8 @@ class MountService extends IMountService.Stub
}
} else if (TAG_VOLUME.equals(tag)) {
final VolumeMetadata meta = VolumeMetadata.read(in);
mMetadata.put(meta.fsUuid, meta);
final VolumeRecord rec = readVolumeRecord(in);
mRecords.put(rec.fsUuid, rec);
}
}
}
@@ -1279,10 +1219,10 @@ class MountService extends IMountService.Stub
}
}
private void writeMetadataLocked() {
private void writeSettingsLocked() {
FileOutputStream fos = null;
try {
fos = mMetadataFile.startWrite();
fos = mSettingsFile.startWrite();
XmlSerializer out = new FastXmlSerializer();
out.setOutput(fos, "utf-8");
@@ -1290,22 +1230,40 @@ class MountService extends IMountService.Stub
out.startTag(null, TAG_VOLUMES);
writeIntAttribute(out, ATTR_VERSION, VERSION_ADD_PRIMARY);
writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
final int size = mMetadata.size();
final int size = mRecords.size();
for (int i = 0; i < size; i++) {
final VolumeMetadata meta = mMetadata.valueAt(i);
VolumeMetadata.write(out, meta);
final VolumeRecord rec = mRecords.valueAt(i);
writeVolumeRecord(out, rec);
}
out.endTag(null, TAG_VOLUMES);
out.endDocument();
mMetadataFile.finishWrite(fos);
mSettingsFile.finishWrite(fos);
} catch (IOException e) {
if (fos != null) {
mMetadataFile.failWrite(fos);
mSettingsFile.failWrite(fos);
}
}
}
public static VolumeRecord readVolumeRecord(XmlPullParser in) throws IOException {
final int type = readIntAttribute(in, ATTR_TYPE);
final String fsUuid = readStringAttribute(in, ATTR_FS_UUID);
final VolumeRecord meta = new VolumeRecord(type, fsUuid);
meta.nickname = readStringAttribute(in, ATTR_NICKNAME);
meta.userFlags = readIntAttribute(in, ATTR_USER_FLAGS);
return meta;
}
public static void writeVolumeRecord(XmlSerializer out, VolumeRecord rec) throws IOException {
out.startTag(null, TAG_VOLUME);
writeIntAttribute(out, ATTR_TYPE, rec.type);
writeStringAttribute(out, ATTR_FS_UUID, rec.fsUuid);
writeStringAttribute(out, ATTR_NICKNAME, rec.nickname);
writeIntAttribute(out, ATTR_USER_FLAGS, rec.userFlags);
out.endTag(null, TAG_VOLUME);
}
/**
* Exposed API calls below here
*/
@@ -1471,32 +1429,40 @@ class MountService extends IMountService.Stub
}
@Override
public void setVolumeNickname(String volId, String nickname) {
public void setVolumeNickname(String fsUuid, String nickname) {
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
waitForReady();
synchronized (mLock) {
final VolumeInfo vol = findVolumeById(volId);
final VolumeMetadata meta = findOrCreateMetadataLocked(vol);
meta.nickname = nickname;
refreshMetadataLocked();
writeMetadataLocked();
mCallbacks.notifyVolumeMetadataChanged(vol.clone());
final VolumeRecord rec = mRecords.get(fsUuid);
rec.nickname = nickname;
mCallbacks.notifyVolumeMetadataChanged(fsUuid);
writeSettingsLocked();
}
}
@Override
public void setVolumeUserFlags(String volId, int flags, int mask) {
public void setVolumeUserFlags(String fsUuid, int flags, int mask) {
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
waitForReady();
synchronized (mLock) {
final VolumeInfo vol = findVolumeById(volId);
final VolumeMetadata meta = findOrCreateMetadataLocked(vol);
meta.userFlags = (meta.userFlags & ~mask) | (flags & mask);
refreshMetadataLocked();
writeMetadataLocked();
mCallbacks.notifyVolumeMetadataChanged(vol.clone());
final VolumeRecord rec = mRecords.get(fsUuid);
rec.userFlags = (rec.userFlags & ~mask) | (flags & mask);
mCallbacks.notifyVolumeMetadataChanged(fsUuid);
writeSettingsLocked();
}
}
@Override
public void forgetVolume(String fsUuid) {
enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
waitForReady();
synchronized (mLock) {
mRecords.remove(fsUuid);
mCallbacks.notifyVolumeMetadataChanged(fsUuid);
writeSettingsLocked();
}
}
@@ -2329,11 +2295,6 @@ class MountService extends IMountService.Stub
@Override
public VolumeInfo[] getVolumes(int flags) {
if ((flags & StorageManager.FLAG_ALL_METADATA) != 0) {
// TODO: implement support for returning all metadata
throw new UnsupportedOperationException();
}
synchronized (mLock) {
final VolumeInfo[] res = new VolumeInfo[mVolumes.size()];
for (int i = 0; i < mVolumes.size(); i++) {
@@ -2343,6 +2304,17 @@ class MountService extends IMountService.Stub
}
}
@Override
public VolumeRecord[] getVolumeRecords(int flags) {
synchronized (mLock) {
final VolumeRecord[] res = new VolumeRecord[mRecords.size()];
for (int i = 0; i < mRecords.size(); i++) {
res[i] = mRecords.valueAt(i);
}
return res;
}
}
private void addObbStateLocked(ObbState obbState) throws RemoteException {
final IBinder binder = obbState.getBinder();
List<ObbState> obbStates = mObbMounts.get(binder);
@@ -2892,7 +2864,7 @@ class MountService extends IMountService.Stub
break;
}
case MSG_VOLUME_METADATA_CHANGED: {
callback.onVolumeMetadataChanged((VolumeInfo) args.arg1);
callback.onVolumeMetadataChanged((String) args.arg1);
break;
}
case MSG_DISK_SCANNED: {
@@ -2912,21 +2884,21 @@ class MountService extends IMountService.Stub
private void notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
final SomeArgs args = SomeArgs.obtain();
args.arg1 = vol;
args.arg1 = vol.clone();
args.argi2 = oldState;
args.argi3 = newState;
obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
}
private void notifyVolumeMetadataChanged(VolumeInfo vol) {
private void notifyVolumeMetadataChanged(String fsUuid) {
final SomeArgs args = SomeArgs.obtain();
args.arg1 = vol;
args.arg1 = fsUuid;
obtainMessage(MSG_VOLUME_METADATA_CHANGED, args).sendToTarget();
}
private void notifyDiskScanned(DiskInfo disk, int volumeCount) {
final SomeArgs args = SomeArgs.obtain();
args.arg1 = disk;
args.arg1 = disk.clone();
args.argi2 = volumeCount;
obtainMessage(MSG_DISK_SCANNED, args).sendToTarget();
}
@@ -2937,10 +2909,10 @@ class MountService extends IMountService.Stub
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
for (String arg : args) {
if ("--clear-metadata".equals(arg)) {
if ("--clear".equals(arg)) {
synchronized (mLock) {
mMetadata.clear();
writeMetadataLocked();
mRecords.clear();
writeSettingsLocked();
}
}
}
@@ -2966,11 +2938,11 @@ class MountService extends IMountService.Stub
pw.decreaseIndent();
pw.println();
pw.println("Metadata:");
pw.println("Records:");
pw.increaseIndent();
for (int i = 0; i < mMetadata.size(); i++) {
final VolumeMetadata meta = mMetadata.valueAt(i);
meta.dump(pw);
for (int i = 0; i < mRecords.size(); i++) {
final VolumeRecord note = mRecords.valueAt(i);
note.dump(pw);
}
pw.decreaseIndent();

View File

@@ -14192,7 +14192,8 @@ public class PackageManagerService extends IPackageManager.Stub {
movePackageInternal(packageName, volumeUuid, moveId);
} catch (PackageManagerException e) {
Slog.d(TAG, "Failed to move " + packageName, e);
mMoveCallbacks.notifyStatusChanged(moveId, PackageManager.MOVE_FAILED_INTERNAL_ERROR);
mMoveCallbacks.notifyStatusChanged(moveId, null,
PackageManager.MOVE_FAILED_INTERNAL_ERROR);
}
return moveId;
}
@@ -14209,6 +14210,7 @@ public class PackageManagerService extends IPackageManager.Stub {
final String packageAbiOverride;
final int appId;
final String seinfo;
final String moveTitle;
// reader
synchronized (mPackages) {
@@ -14228,9 +14230,6 @@ public class PackageManagerService extends IPackageManager.Stub {
// TODO: yell if already in desired location
mMoveCallbacks.notifyStarted(moveId,
String.valueOf(pm.getApplicationLabel(pkg.applicationInfo)));
pkg.mOperationPending = true;
currentAsec = pkg.applicationInfo.isForwardLocked()
@@ -14241,6 +14240,7 @@ public class PackageManagerService extends IPackageManager.Stub {
packageAbiOverride = ps.cpuAbiOverrideString;
appId = UserHandle.getAppId(pkg.applicationInfo.uid);
seinfo = pkg.applicationInfo.seinfo;
moveTitle = String.valueOf(pm.getApplicationLabel(pkg.applicationInfo));
}
int installFlags;
@@ -14268,7 +14268,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
Slog.d(TAG, "Moving " + packageName + " from " + currentVolumeUuid + " to " + volumeUuid);
mMoveCallbacks.notifyStatusChanged(moveId, 10, -1);
mMoveCallbacks.notifyStatusChanged(moveId, moveTitle, 10);
if (moveData) {
synchronized (mInstallLock) {
@@ -14288,7 +14288,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
mMoveCallbacks.notifyStatusChanged(moveId, 50);
mMoveCallbacks.notifyStatusChanged(moveId, moveTitle, 50);
final IPackageInstallObserver2 installObserver = new IPackageInstallObserver2.Stub() {
@Override
@@ -14315,15 +14315,15 @@ public class PackageManagerService extends IPackageManager.Stub {
final int status = PackageManager.installStatusToPublicStatus(returnCode);
switch (status) {
case PackageInstaller.STATUS_SUCCESS:
mMoveCallbacks.notifyStatusChanged(moveId,
mMoveCallbacks.notifyStatusChanged(moveId, moveTitle,
PackageManager.MOVE_SUCCEEDED);
break;
case PackageInstaller.STATUS_FAILURE_STORAGE:
mMoveCallbacks.notifyStatusChanged(moveId,
mMoveCallbacks.notifyStatusChanged(moveId, moveTitle,
PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE);
break;
default:
mMoveCallbacks.notifyStatusChanged(moveId,
mMoveCallbacks.notifyStatusChanged(moveId, moveTitle,
PackageManager.MOVE_FAILED_INTERNAL_ERROR);
break;
}
@@ -14346,15 +14346,12 @@ public class PackageManagerService extends IPackageManager.Stub {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null);
final int realMoveId = mNextMoveId.getAndIncrement();
final String realTitle = null;
final IPackageMoveObserver callback = new IPackageMoveObserver.Stub() {
@Override
public void onStarted(int moveId, String title) {
// Ignored
}
@Override
public void onStatusChanged(int moveId, int status, long estMillis) {
mMoveCallbacks.notifyStatusChanged(realMoveId, status, estMillis);
public void onStatusChanged(int moveId, String title, int status, long estMillis) {
mMoveCallbacks.notifyStatusChanged(realMoveId, realTitle, status, estMillis);
}
};
@@ -14709,7 +14706,6 @@ public class PackageManagerService extends IPackageManager.Stub {
}
private static class MoveCallbacks extends Handler {
private static final int MSG_STARTED = 1;
private static final int MSG_STATUS_CHANGED = 2;
private final RemoteCallbackList<IPackageMoveObserver>
@@ -14747,37 +14743,26 @@ public class PackageManagerService extends IPackageManager.Stub {
private void invokeCallback(IPackageMoveObserver callback, int what, SomeArgs args)
throws RemoteException {
switch (what) {
case MSG_STARTED: {
callback.onStarted(args.argi1, (String) args.arg2);
break;
}
case MSG_STATUS_CHANGED: {
callback.onStatusChanged(args.argi1, args.argi2, (long) args.arg3);
callback.onStatusChanged(args.argi1, (String) args.arg2, args.argi3,
(long) args.arg4);
break;
}
}
}
private void notifyStarted(int moveId, String title) {
Slog.v(TAG, "Move " + moveId + " started with title " + title);
final SomeArgs args = SomeArgs.obtain();
args.argi1 = moveId;
args.arg2 = title;
obtainMessage(MSG_STARTED, args).sendToTarget();
private void notifyStatusChanged(int moveId, String moveTitle, int status) {
notifyStatusChanged(moveId, moveTitle, status, -1);
}
private void notifyStatusChanged(int moveId, int status) {
notifyStatusChanged(moveId, status, -1);
}
private void notifyStatusChanged(int moveId, int status, long estMillis) {
private void notifyStatusChanged(int moveId, String moveTitle, int status, long estMillis) {
Slog.v(TAG, "Move " + moveId + " status " + status);
final SomeArgs args = SomeArgs.obtain();
args.argi1 = moveId;
args.argi2 = status;
args.arg3 = estMillis;
args.arg2 = moveTitle;
args.argi3 = status;
args.arg4 = estMillis;
obtainMessage(MSG_STATUS_CHANGED, args).sendToTarget();
synchronized (mLastStatus) {