summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/animation/AnimatorSet.java3
-rw-r--r--core/java/android/animation/ValueAnimator.java5
-rw-r--r--core/java/android/app/ActivityManager.java30
-rw-r--r--core/java/android/app/ActivityManagerInternal.java21
-rw-r--r--core/java/android/app/ActivityManagerNative.java9
-rw-r--r--core/java/android/app/AppOpsManager.java29
-rw-r--r--core/java/android/app/ApplicationPackageManager.java10
-rw-r--r--core/java/android/app/ContextImpl.java12
-rw-r--r--core/java/android/app/INotificationManager.aidl5
-rw-r--r--core/java/android/app/Instrumentation.java4
-rw-r--r--core/java/android/app/NotificationManager.java29
-rw-r--r--core/java/android/app/SearchDialog.java4
-rw-r--r--core/java/android/app/SystemServiceRegistry.java6
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java129
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl5
-rw-r--r--core/java/android/app/admin/SystemUpdatePolicy.java (renamed from core/java/android/app/admin/OtaPolicy.java)64
-rw-r--r--core/java/android/app/backup/BlobBackupHelper.java296
-rw-r--r--core/java/android/app/trust/ITrustListener.aidl2
-rw-r--r--core/java/android/app/trust/TrustManager.java22
-rw-r--r--core/java/android/content/Context.java22
-rw-r--r--core/java/android/content/ContextWrapper.java7
-rw-r--r--core/java/android/content/pm/ActivityInfo.java7
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java10
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl4
-rw-r--r--core/java/android/content/pm/LauncherApps.java1
-rw-r--r--core/java/android/content/pm/PackageManager.java15
-rw-r--r--core/java/android/content/pm/PackageParser.java5
-rw-r--r--core/java/android/hardware/SystemSensorManager.java8
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java41
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java53
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java3
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintUtils.java18
-rw-r--r--core/java/android/net/ConnectivityManager.java34
-rw-r--r--core/java/android/net/IConnectivityManager.aidl2
-rw-r--r--core/java/android/net/INetworkPolicyManager.aidl4
-rw-r--r--core/java/android/net/NetworkPolicyManager.java27
-rw-r--r--core/java/android/nfc/IAppCallback.aidl4
-rw-r--r--core/java/android/nfc/NfcActivityManager.java15
-rw-r--r--core/java/android/nfc/NfcEvent.java9
-rw-r--r--core/java/android/os/BatteryStats.java200
-rw-r--r--core/java/android/os/Parcel.java9
-rw-r--r--core/java/android/os/UserManager.java15
-rw-r--r--core/java/android/os/storage/DiskInfo.java35
-rw-r--r--core/java/android/os/storage/IMountServiceListener.java26
-rw-r--r--core/java/android/os/storage/StorageEventListener.java3
-rw-r--r--core/java/android/os/storage/StorageManager.java31
-rw-r--r--core/java/android/os/storage/VolumeInfo.java107
-rw-r--r--core/java/android/provider/Settings.java7
-rw-r--r--core/java/android/security/NetworkSecurityPolicy.java6
-rw-r--r--core/java/android/security/keymaster/KeymasterArgument.java1
-rw-r--r--core/java/android/security/keymaster/KeymasterArguments.java28
-rw-r--r--core/java/android/security/keymaster/KeymasterDefs.java4
-rw-r--r--core/java/android/security/keymaster/KeymasterLongArgument.java1
-rw-r--r--core/java/android/service/gatekeeper/IGateKeeperService.aidl18
-rw-r--r--core/java/android/service/trust/ITrustAgentServiceCallback.aidl2
-rw-r--r--core/java/android/service/trust/TrustAgentService.java62
-rw-r--r--core/java/android/service/wallpaper/WallpaperService.java23
-rw-r--r--core/java/android/text/TextDirectionHeuristics.java120
-rw-r--r--core/java/android/text/method/ArrowKeyMovementMethod.java39
-rw-r--r--core/java/android/text/method/BaseKeyListener.java2
-rw-r--r--core/java/android/view/Display.java9
-rw-r--r--core/java/android/view/DisplayEventReceiver.java6
-rw-r--r--core/java/android/view/DisplayInfo.java3
-rw-r--r--core/java/android/view/DisplayListCanvas.java10
-rw-r--r--core/java/android/view/IWindowManager.aidl1
-rw-r--r--core/java/android/view/KeyEvent.java18
-rw-r--r--core/java/android/view/ThreadedRenderer.java32
-rw-r--r--core/java/android/view/View.java82
-rw-r--r--core/java/android/view/ViewGroup.java198
-rw-r--r--core/java/android/webkit/WebViewFactory.java85
-rw-r--r--core/java/android/widget/AbsSeekBar.java37
-rw-r--r--core/java/android/widget/CalendarViewMaterialDelegate.java4
-rwxr-xr-xcore/java/android/widget/DatePickerCalendarDelegate.java4
-rw-r--r--core/java/android/widget/DayPickerPagerAdapter.java (renamed from core/java/android/widget/DayPickerAdapter.java)21
-rw-r--r--core/java/android/widget/DayPickerView.java265
-rw-r--r--core/java/android/widget/DayPickerViewPager.java137
-rw-r--r--core/java/android/widget/FastScroller.java9
-rw-r--r--core/java/android/widget/GridView.java3
-rw-r--r--core/java/android/widget/LinearLayout.java7
-rw-r--r--core/java/android/widget/ListView.java14
-rw-r--r--core/java/android/widget/PopupWindow.java82
-rw-r--r--core/java/android/widget/ProgressBar.java22
-rw-r--r--core/java/android/widget/ScrollView.java8
-rw-r--r--core/java/android/widget/SimpleMonthView.java214
-rw-r--r--core/java/android/widget/Spinner.java4
-rw-r--r--core/java/android/widget/TabWidget.java5
-rw-r--r--core/java/android/widget/TableLayout.java6
-rw-r--r--core/java/android/widget/TableRow.java6
-rw-r--r--core/java/android/widget/TextView.java4
-rw-r--r--core/java/com/android/internal/app/IBatteryStats.aidl3
-rw-r--r--core/java/com/android/internal/content/PackageHelper.java2
-rw-r--r--core/java/com/android/internal/logging/EventLogTags.logtags2
-rw-r--r--core/java/com/android/internal/logging/MetricsLogger.java7
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHelper.java17
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java271
-rw-r--r--core/java/com/android/internal/os/WifiPowerCalculator.java2
-rw-r--r--core/java/com/android/internal/os/WifiPowerEstimator.java2
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java7
-rw-r--r--core/java/com/android/internal/transition/EpicenterClipReveal.java119
-rw-r--r--core/java/com/android/internal/transition/EpicenterTranslate.java191
-rw-r--r--core/java/com/android/internal/transition/TransitionConstants.java24
-rw-r--r--core/java/com/android/internal/widget/ActionBarContainer.java6
-rw-r--r--core/java/com/android/internal/widget/ActionBarContextView.java3
-rw-r--r--core/java/com/android/internal/widget/FloatingToolbar.java278
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java17
-rw-r--r--core/java/com/android/internal/widget/SlidingTab.java16
-rw-r--r--core/java/com/android/server/backup/NotificationBackupHelper.java76
-rw-r--r--core/java/com/android/server/backup/PreferredActivityBackupHelper.java161
-rw-r--r--core/java/com/android/server/backup/SystemBackupAgent.java7
109 files changed, 2890 insertions, 1330 deletions
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index dd5f18e..f6ad847 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -1095,7 +1095,8 @@ public final class AnimatorSet extends Animator {
public Node clone() {
try {
Node node = (Node) super.clone();
- node.animation = (Animator) animation.clone();
+ node.animation = animation.clone();
+ node.done = false;
return node;
} catch (CloneNotSupportedException e) {
throw new AssertionError();
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 275e78e..292507b 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -1486,6 +1486,11 @@ public class ValueAnimator extends Animator {
anim.mPaused = false;
anim.mResumed = false;
anim.mStartListenersCalled = false;
+ anim.mStartTime = 0;
+ anim.mStartTimeCommitted = false;
+ anim.mPauseTime = 0;
+ anim.mCurrentFraction = 0;
+ anim.mDelayStartTime = 0;
PropertyValuesHolder[] oldValues = mValues;
if (oldValues != null) {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 51ececc..576a046 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -86,6 +86,13 @@ public class ActivityManager {
public static final String META_HOME_ALTERNATE = "android.app.home.alternate";
/**
+ * Result for IActivityManager.startActivity: trying to start a background user
+ * activity that shouldn't be displayed for all users.
+ * @hide
+ */
+ public static final int START_NOT_CURRENT_USER_ACTIVITY = -8;
+
+ /**
* Result for IActivityManager.startActivity: trying to start an activity under voice
* control when that activity does not support the VOICE category.
* @hide
@@ -862,6 +869,23 @@ public class ActivityManager {
*/
public int affiliatedTaskColor;
+ /**
+ * The component launched as the first activity in the task.
+ * This can be considered the "application" of this task.
+ */
+ public ComponentName baseActivity;
+
+ /**
+ * The activity component at the top of the history stack of the task.
+ * This is what the user is currently doing.
+ */
+ public ComponentName topActivity;
+
+ /**
+ * Number of activities in this task.
+ */
+ public int numActivities;
+
public RecentTaskInfo() {
}
@@ -895,6 +919,9 @@ public class ActivityManager {
dest.writeLong(lastActiveTime);
dest.writeInt(affiliatedTaskId);
dest.writeInt(affiliatedTaskColor);
+ ComponentName.writeToParcel(baseActivity, dest);
+ ComponentName.writeToParcel(topActivity, dest);
+ dest.writeInt(numActivities);
}
public void readFromParcel(Parcel source) {
@@ -911,6 +938,9 @@ public class ActivityManager {
lastActiveTime = source.readLong();
affiliatedTaskId = source.readInt();
affiliatedTaskColor = source.readInt();
+ baseActivity = ComponentName.readFromParcel(source);
+ topActivity = ComponentName.readFromParcel(source);
+ numActivities = source.readInt();
}
public static final Creator<RecentTaskInfo> CREATOR
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index d56dc1e..bde8f39 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -16,6 +16,8 @@
package android.app;
+import android.annotation.NonNull;
+
/**
* Activity manager local system service interface.
*
@@ -27,4 +29,23 @@ public abstract class ActivityManagerInternal {
public abstract int startIsolatedProcess(String entryPoint, String[] mainArgs,
String processName, String abiOverride, int uid, Runnable crashHandler);
+
+ /**
+ * Acquires a sleep token with the specified tag.
+ *
+ * @param tag A string identifying the purpose of the token (eg. "Dream").
+ */
+ public abstract SleepToken acquireSleepToken(@NonNull String tag);
+
+ /**
+ * Sleep tokens cause the activity manager to put the top activity to sleep.
+ * They are used by components such as dreams that may hide and block interaction
+ * with underlying activities.
+ */
+ public static abstract class SleepToken {
+ /**
+ * Releases the sleep token.
+ */
+ public abstract void release();
+ }
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 256d87d..add7af2 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -93,15 +93,20 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
}
static boolean sSystemReady = false;
+ static public void broadcastStickyIntent(Intent intent, String permission, int userId) {
+ broadcastStickyIntent(intent, permission, AppOpsManager.OP_NONE, userId);
+ }
+
/**
* Convenience for sending a sticky broadcast. For internal use only.
* If you don't care about permission, use null.
*/
- static public void broadcastStickyIntent(Intent intent, String permission, int userId) {
+ static public void broadcastStickyIntent(Intent intent, String permission, int appOp,
+ int userId) {
try {
getDefault().broadcastIntent(
null, intent, null, null, Activity.RESULT_OK, null, null,
- null /*permission*/, AppOpsManager.OP_NONE, false, true, userId);
+ null /*permission*/, appOp, false, true, userId);
} catch (RemoteException ex) {
}
}
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 381c20c..223d528 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -16,6 +16,7 @@
package android.app;
+import android.Manifest;
import android.annotation.SystemApi;
import android.app.usage.UsageStatsManager;
import android.content.Context;
@@ -212,8 +213,12 @@ public class AppOpsManager {
public static final int OP_ASSIST_STRUCTURE = 49;
/** @hide Received a screenshot from assist. */
public static final int OP_ASSIST_SCREENSHOT = 50;
+ /** @hide Read the phone state. */
+ public static final int OP_READ_PHONE_STATE = 51;
+ /** @hide Add voicemail messages to the voicemail content provider. */
+ public static final int OP_ADD_VOICEMAIL = 52;
/** @hide */
- public static final int _NUM_OP = 51;
+ public static final int _NUM_OP = 53;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION =
@@ -294,6 +299,8 @@ public class AppOpsManager {
OP_WRITE_WALLPAPER,
OP_ASSIST_STRUCTURE,
OP_ASSIST_SCREENSHOT,
+ OP_READ_PHONE_STATE,
+ OP_ADD_VOICEMAIL
};
/**
@@ -352,6 +359,8 @@ public class AppOpsManager {
null,
null,
null,
+ null,
+ null
};
/**
@@ -409,7 +418,9 @@ public class AppOpsManager {
"ACTIVATE_VPN",
"WRITE_WALLPAPER",
"ASSIST_STRUCTURE",
- "ASSIST_SCREENSHOT"
+ "ASSIST_SCREENSHOT",
+ "OP_READ_PHONE_STATE",
+ "ADD_VOICEMAIL"
};
/**
@@ -432,14 +443,14 @@ public class AppOpsManager {
null, // neighboring cells shares the coarse location perm
android.Manifest.permission.CALL_PHONE,
android.Manifest.permission.READ_SMS,
- android.Manifest.permission.WRITE_SMS,
+ null, // no permission required for writing sms
android.Manifest.permission.RECEIVE_SMS,
android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST,
android.Manifest.permission.RECEIVE_MMS,
android.Manifest.permission.RECEIVE_WAP_PUSH,
android.Manifest.permission.SEND_SMS,
android.Manifest.permission.READ_SMS,
- android.Manifest.permission.WRITE_SMS,
+ null, // no permission required for writing icc sms
android.Manifest.permission.WRITE_SETTINGS,
android.Manifest.permission.SYSTEM_ALERT_WINDOW,
android.Manifest.permission.ACCESS_NOTIFICATIONS,
@@ -468,6 +479,8 @@ public class AppOpsManager {
null, // no permission for supporting wallpaper
null, // no permission for receiving assist structure
null, // no permission for receiving assist screenshot
+ Manifest.permission.READ_PHONE_STATE,
+ Manifest.permission.ADD_VOICEMAIL
};
/**
@@ -527,6 +540,8 @@ public class AppOpsManager {
UserManager.DISALLOW_WALLPAPER, // WRITE_WALLPAPER
null, // ASSIST_STRUCTURE
null, // ASSIST_SCREENSHOT
+ null, // READ_PHONE_STATE
+ null // ADD_VOICEMAIL
};
/**
@@ -585,6 +600,8 @@ public class AppOpsManager {
false, //WALLPAPER
false, //ASSIST_STRUCTURE
false, //ASSIST_SCREENSHOT
+ false, //READ_PHONE_STATE
+ false //ADD_VOICEMAIL
};
/**
@@ -642,6 +659,8 @@ public class AppOpsManager {
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED
};
/**
@@ -703,6 +722,8 @@ public class AppOpsManager {
false,
false,
false,
+ false,
+ false
};
private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index b9ddff0..dfe7e18 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1520,19 +1520,21 @@ final class ApplicationPackageManager extends PackageManager {
// Should never happen!
}
}
+
@Override
- public void freeStorageAndNotify(long idealStorageSize, IPackageDataObserver observer) {
+ public void freeStorageAndNotify(String volumeUuid, long idealStorageSize,
+ IPackageDataObserver observer) {
try {
- mPM.freeStorageAndNotify(idealStorageSize, observer);
+ mPM.freeStorageAndNotify(volumeUuid, idealStorageSize, observer);
} catch (RemoteException e) {
// Should never happen!
}
}
@Override
- public void freeStorage(long freeStorageSize, IntentSender pi) {
+ public void freeStorage(String volumeUuid, long freeStorageSize, IntentSender pi) {
try {
- mPM.freeStorage(freeStorageSize, pi);
+ mPM.freeStorage(volumeUuid, freeStorageSize, pi);
} catch (RemoteException e) {
// Should never happen!
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 4ccd69f..81a78f6 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -860,13 +860,19 @@ class ContextImpl extends Context {
@Override
public void sendBroadcastAsUser(Intent intent, UserHandle user,
String receiverPermission) {
+ sendBroadcastAsUser(intent, user, receiverPermission, AppOpsManager.OP_NONE);
+ }
+
+ @Override
+ public void sendBroadcastAsUser(Intent intent, UserHandle user,
+ String receiverPermission, int appOp) {
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(
- mMainThread.getApplicationThread(), intent, resolvedType, null,
- Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, false, false,
- user.getIdentifier());
+ mMainThread.getApplicationThread(), intent, resolvedType, null,
+ Activity.RESULT_OK, null, null, receiverPermission, appOp, false, false,
+ user.getIdentifier());
} catch (RemoteException e) {
}
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 913159a..e275df0 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -89,4 +89,9 @@ interface INotificationManager
boolean isNotificationPolicyTokenValid(String pkg, in NotificationManager.Policy.Token token);
NotificationManager.Policy getNotificationPolicy(in NotificationManager.Policy.Token token);
void setNotificationPolicy(in NotificationManager.Policy.Token token, in NotificationManager.Policy policy);
+
+ byte[] getBackupPayload(int user);
+ void applyRestore(in byte[] payload, int user);
+
+ ParceledListSlice getAppActiveNotifications(String callingPkg, int userId);
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index fc96464..b77dec5 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1797,6 +1797,10 @@ public class Instrumentation {
case ActivityManager.START_NOT_VOICE_COMPATIBLE:
throw new SecurityException(
"Starting under voice control not allowed for: " + intent);
+ case ActivityManager.START_NOT_CURRENT_USER_ACTIVITY:
+ throw new SecurityException(
+ "Not allowed to start background user activity that shouldn't be"
+ + " displayed for all users.");
default:
throw new AndroidRuntimeException("Unknown error code "
+ res + " when starting " + intent);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 7133dce..0a59026 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -23,6 +23,7 @@ import android.app.Notification.Builder;
import android.app.NotificationManager.Policy.Token;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.ParceledListSlice;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -35,10 +36,12 @@ import android.os.StrictMode;
import android.os.UserHandle;
import android.provider.Settings.Global;
import android.service.notification.IConditionListener;
+import android.service.notification.StatusBarNotification;
import android.service.notification.ZenModeConfig;
import android.util.Log;
import java.util.Objects;
+import java.util.List;
/**
* Class to notify the user of events that happen. This is how you tell
@@ -642,4 +645,30 @@ public class NotificationManager
}
}
+ /**
+ * Recover a list of active notifications: ones that have been posted by the calling app that
+ * have not yet been dismissed by the user or {@link #cancel(String, int)}ed by the app.
+ *
+ * Each notification is embedded in a {@link StatusBarNotification} object, including the
+ * original <code>tag</code> and <code>id</code> supplied to
+ * {@link #notify(String, int, Notification) notify()}
+ * (via {@link StatusBarNotification#getTag() getTag()} and
+ * {@link StatusBarNotification#getId() getId()}) as well as a copy of the original
+ * {@link Notification} object (via {@link StatusBarNotification#getNotification()}).
+ *
+ * @return An array of {@link StatusBarNotification}.
+ */
+ public StatusBarNotification[] getActiveNotifications() {
+ final INotificationManager service = getService();
+ final String pkg = mContext.getPackageName();
+ try {
+ final ParceledListSlice<StatusBarNotification> parceledList
+ = service.getAppActiveNotifications(pkg, UserHandle.myUserId());
+ final List<StatusBarNotification> list = parceledList.getList();
+ return list.toArray(new StatusBarNotification[list.size()]);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to talk to notification manager. Woe!", e);
+ }
+ return new StatusBarNotification[0];
+ }
}
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index c719a0e..b1a5d21 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -643,6 +643,10 @@ public class SearchDialog extends Dialog {
@Override
public ActionMode startActionModeForChild(
View child, ActionMode.Callback callback, int type) {
+ // Disable Primary Action Modes in the SearchBar, as they overlap.
+ if (type != ActionMode.TYPE_PRIMARY) {
+ return super.startActionModeForChild(child, callback, type);
+ }
return null;
}
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index e446700..46da025 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -332,10 +332,10 @@ final class SystemServiceRegistry {
}});
registerService(Context.NETWORK_POLICY_SERVICE, NetworkPolicyManager.class,
- new StaticServiceFetcher<NetworkPolicyManager>() {
+ new CachedServiceFetcher<NetworkPolicyManager>() {
@Override
- public NetworkPolicyManager createService() {
- return new NetworkPolicyManager(INetworkPolicyManager.Stub.asInterface(
+ public NetworkPolicyManager createService(ContextImpl ctx) {
+ return new NetworkPolicyManager(ctx, INetworkPolicyManager.Stub.asInterface(
ServiceManager.getService(Context.NETWORK_POLICY_SERVICE)));
}});
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 44760ce..9e2da61 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -364,9 +364,12 @@ public class DevicePolicyManager {
/**
* A String extra holding the URL-safe base64 encoded SHA-1 checksum of the file at download
- * location specified in {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}. If
- * this doesn't match the file at the download location an error will be shown to the user and
- * the user will be asked to factory reset the device.
+ * location specified in {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}.
+ *
+ * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM} should be
+ * present. The provided checksum should match the checksum of the file at the download
+ * location. If the checksum doesn't match an error will be shown to the user and the user will
+ * be asked to factory reset the device.
*
* <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
* provisioning via an NFC bump.
@@ -375,6 +378,26 @@ public class DevicePolicyManager {
= "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
/**
+ * A String extra holding the URL-safe base64 encoded SHA-1 checksum of any certificate of the
+ * android package archive at the download location specified in {@link
+ * #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}.
+ *
+ * <p>The certificates of an android package archive can be obtained using
+ * {@link android.content.pm.PackageManager#getPackageArchiveInfo} with flag
+ * {@link android.content.pm.PackageManager#GET_SIGNATURES}.
+ *
+ * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM} should be
+ * present. The provided checksum should match the checksum of any certificate of the file at
+ * the download location. If the checksum does not match an error will be shown to the user and
+ * the user will be asked to factory reset the device.
+ *
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
+ * provisioning via an NFC bump.
+ */
+ public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM
+ = "android.app.extra.PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM";
+
+ /**
* Broadcast Action: This broadcast is sent to indicate that provisioning of a managed profile
* has completed successfully.
*
@@ -449,9 +472,12 @@ public class DevicePolicyManager {
/**
* A String extra holding the URL-safe base64 encoded SHA-1 checksum of the file at download
* location specified in
- * {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}. If this doesn't
- * match the file at the download location an error will be shown to the user and the user will
- * be asked to factory reset the device.
+ * {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}.
+ *
+ * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_CERTIFICATE_CHECKSUM}
+ * should be present. The provided checksum should match the checksum of the file at the
+ * download location. If the checksum doesn't match an error will be shown to the user and the
+ * user will be asked to factory reset the device.
*
* <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
* provisioning via an NFC bump.
@@ -460,6 +486,26 @@ public class DevicePolicyManager {
= "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM";
/**
+ * A String extra holding the URL-safe base64 encoded SHA-1 checksum of any certificate of the
+ * android package archive at the download location specified in {@link
+ * #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}.
+ *
+ * <p>The certificates of an android package archive can be obtained using
+ * {@link android.content.pm.PackageManager#getPackageArchiveInfo} with flag
+ * {@link android.content.pm.PackageManager#GET_SIGNATURES}.
+ *
+ * <p>Either this extra or {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM}
+ * should be present. The provided checksum should match the checksum of any certificate of the
+ * file at the download location. If the checksum doesn't match an error will be shown to the
+ * user and the user will be asked to factory reset the device.
+ *
+ * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
+ * provisioning via an NFC bump.
+ */
+ public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_CERTIFICATE_CHECKSUM
+ = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_CERTIFICATE_CHECKSUM";
+
+ /**
* A String extra holding the MAC address of the Bluetooth device to connect to with status
* updates during provisioning.
*
@@ -754,11 +800,12 @@ public class DevicePolicyManager {
public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 0x0002;
/**
- * Broadcast action: notify that a new local OTA policy has been set by the device owner.
- * The new policy can be retrieved by {@link #getOtaPolicy()}.
+ * Broadcast action: notify that a new local system update policy has been set by the device
+ * owner. The new policy can be retrieved by {@link #getSystemUpdatePolicy()}.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_OTA_POLICY_CHANGED = "android.app.action.OTA_POLICY_CHANGED";
+ public static final String ACTION_SYSTEM_UPDATE_POLICY_CHANGED
+ = "android.app.action.SYSTEM_UPDATE_POLICY_CHANGED";
/**
@@ -1588,6 +1635,23 @@ public class DevicePolicyManager {
}
/**
+ * Queries whether {@link #DO_NOT_ASK_CREDENTIALS_ON_BOOT} flag is set.
+ *
+ * @return true if DO_NOT_ASK_CREDENTIALS_ON_BOOT flag is set.
+ * @hide
+ */
+ public boolean getDoNotAskCredentialsOnBoot() {
+ if (mService != null) {
+ try {
+ return mService.getDoNotAskCredentialsOnBoot();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to call getDoNotAskCredentialsOnBoot()", e);
+ }
+ }
+ return false;
+ }
+
+ /**
* Setting this to a value greater than zero enables a built-in policy
* that will perform a device wipe after too many incorrect
* device-unlock passwords have been entered. This built-in policy combines
@@ -1664,6 +1728,16 @@ public class DevicePolicyManager {
public static final int RESET_PASSWORD_REQUIRE_ENTRY = 0x0001;
/**
+ * Flag for {@link #resetPassword}: don't ask for user credentials on device boot.
+ * If the flag is set, the device can be booted without asking for user password.
+ * The absence of this flag does not change the current boot requirements. This flag
+ * can be set by the device owner only. If the app is not the device owner, the flag
+ * is ignored. Once the flag is set, it cannot be reverted back without resetting the
+ * device to factory defaults.
+ */
+ public static final int DO_NOT_ASK_CREDENTIALS_ON_BOOT = 0x0002;
+
+ /**
* Force a new device unlock password (the password needed to access the
* entire device, not for individual accounts) on the user. This takes
* effect immediately.
@@ -1686,7 +1760,8 @@ public class DevicePolicyManager {
* <p>Calling this from a managed profile will throw a security exception.
*
* @param password The new password for the user. Null or empty clears the password.
- * @param flags May be 0 or {@link #RESET_PASSWORD_REQUIRE_ENTRY}.
+ * @param flags May be 0 or combination of {@link #RESET_PASSWORD_REQUIRE_ENTRY} and
+ * {@link #DO_NOT_ASK_CREDENTIALS_ON_BOOT}.
* @return Returns true if the password was applied, or false if it is
* not acceptable for the current constraints.
*/
@@ -4143,46 +4218,46 @@ public class DevicePolicyManager {
}
}
- /*
- * Called by device owners to set a local OTA update policy. When a new OTA policy is set,
- * {@link #ACTION_OTA_POLICY_CHANGED} is broadcasted.
+ /**
+ * Called by device owners to set a local system update policy. When a new policy is set,
+ * {@link #ACTION_SYSTEM_UPDATE_POLICY_CHANGED} is broadcasted.
*
* @param who Which {@link DeviceAdminReceiver} this request is associated with. All components
- * in the device owner package can set OTA policies and the most recent policy takes effect.
- * @param policy the new OTA policy, or null to clear the current policy.
- * @see OtaPolicy
+ * in the device owner package can set system update policies and the most recent policy takes
+ * effect.
+ * @param policy the new policy, or null to clear the current policy.
+ * @see SystemUpdatePolicy
*/
- public void setOtaPolicy(ComponentName who, OtaPolicy policy) {
+ public void setSystemUpdatePolicy(ComponentName who, SystemUpdatePolicy policy) {
if (mService != null) {
try {
if (policy != null) {
- mService.setOtaPolicy(who, policy.getPolicyBundle());
+ mService.setSystemUpdatePolicy(who, policy.getPolicyBundle());
} else {
- mService.setOtaPolicy(who, null);
+ mService.setSystemUpdatePolicy(who, null);
}
} catch (RemoteException re) {
- Log.w(TAG, "Error calling setOtaPolicy", re);
+ Log.w(TAG, "Error calling setSystemUpdatePolicy", re);
}
}
}
/**
- * Retrieve a local OTA update policy set previously by {@link #setOtaPolicy}.
+ * Retrieve a local system update policy set previously by {@link #setSystemUpdatePolicy}.
*
- * @return The current OTA policy object, or null if no policy is set or the system does not
- * support managed OTA.
+ * @return The current policy object, or null if no policy is set.
*/
- public OtaPolicy getOtaPolicy() {
+ public SystemUpdatePolicy getSystemUpdatePolicy() {
if (mService != null) {
try {
- PersistableBundle bundle = mService.getOtaPolicy();
+ PersistableBundle bundle = mService.getSystemUpdatePolicy();
if (bundle != null) {
- return new OtaPolicy(bundle);
+ return new SystemUpdatePolicy(bundle);
} else {
return null;
}
} catch (RemoteException re) {
- Log.w(TAG, "Error calling getOtaPolicy", re);
+ Log.w(TAG, "Error calling getSystemUpdatePolicy", re);
}
}
return null;
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 7502e1d..1f7498e 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -219,9 +219,10 @@ interface IDevicePolicyManager {
void setUserIcon(in ComponentName admin, in Bitmap icon);
void sendDeviceInitializerStatus(int statusCode, String description);
- void setOtaPolicy(in ComponentName who, in PersistableBundle policy);
- PersistableBundle getOtaPolicy();
+ void setSystemUpdatePolicy(in ComponentName who, in PersistableBundle policy);
+ PersistableBundle getSystemUpdatePolicy();
boolean setKeyguardEnabledState(in ComponentName admin, boolean enabled);
void setStatusBarEnabledState(in ComponentName who, boolean enabled);
+ boolean getDoNotAskCredentialsOnBoot();
}
diff --git a/core/java/android/app/admin/OtaPolicy.java b/core/java/android/app/admin/SystemUpdatePolicy.java
index 98581a7..de56cd0 100644
--- a/core/java/android/app/admin/OtaPolicy.java
+++ b/core/java/android/app/admin/SystemUpdatePolicy.java
@@ -23,12 +23,12 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * A class that represents a local OTA policy set by the device owner.
+ * A class that represents a local system update policy set by the device owner.
*
- * @see DevicePolicyManager#setOtaPolicy
- * @see DevicePolicyManager#getOtaPolicy
+ * @see DevicePolicyManager#setSystemUpdatePolicy
+ * @see DevicePolicyManager#getSystemUpdatePolicy
*/
-public class OtaPolicy {
+public class SystemUpdatePolicy {
/** @hide */
@IntDef({
@@ -36,22 +36,27 @@ public class OtaPolicy {
TYPE_INSTALL_WINDOWED,
TYPE_POSTPONE})
@Retention(RetentionPolicy.SOURCE)
- @interface OtaPolicyType {}
+ @interface SystemUpdatePolicyType {}
/**
- * Install OTA update automatically as soon as one is available.
+ * Install system update automatically as soon as one is available.
*/
public static final int TYPE_INSTALL_AUTOMATIC = 1;
/**
- * Install OTA update automatically within a daily maintenance window, for a maximum of two-week
- * period. After that period the OTA will be installed automatically.
+ * Install system update automatically within a daily maintenance window, for a maximum of 30
+ * days. After the expiration the policy will no longer be effective and the system should
+ * revert back to its normal behavior as if no policy were set. The only exception is
+ * {@link #TYPE_INSTALL_AUTOMATIC} which should still take effect to install system update
+ * immediately.
*/
public static final int TYPE_INSTALL_WINDOWED = 2;
/**
- * Incoming OTA will be blocked for a maximum of two weeks, after which it will be installed
- * automatically.
+ * Incoming system update will be blocked for a maximum of 30 days, after which the system
+ * should revert back to its normal behavior as if no policy were set. The only exception is
+ * {@link #TYPE_INSTALL_AUTOMATIC} which should still take effect to install system update
+ * immediately.
*/
public static final int TYPE_POSTPONE = 3;
@@ -61,15 +66,15 @@ public class OtaPolicy {
private PersistableBundle mPolicy;
- public OtaPolicy() {
+ public SystemUpdatePolicy() {
mPolicy = new PersistableBundle();
}
/**
- * Construct an OtaPolicy object from a bundle.
+ * Construct an SystemUpdatePolicy object from a bundle.
* @hide
*/
- public OtaPolicy(PersistableBundle in) {
+ public SystemUpdatePolicy(PersistableBundle in) {
mPolicy = new PersistableBundle(in);
}
@@ -82,7 +87,9 @@ public class OtaPolicy {
}
/**
- * Set the OTA policy to: install OTA update automatically as soon as one is available.
+ * Set the policy to: install update automatically as soon as one is available.
+ *
+ * @see #TYPE_INSTALL_AUTOMATIC
*/
public void setAutomaticInstallPolicy() {
mPolicy.clear();
@@ -90,18 +97,19 @@ public class OtaPolicy {
}
/**
- * Set the OTA policy to: new OTA update will only be installed automatically when the system
+ * Set the policy to: new system update will only be installed automatically when the system
* clock is inside a daily maintenance window. If the start and end times are the same, the
- * window is considered to include the WHOLE 24 hours, that is, OTAs can install at any time. If
- * the given window in invalid, a {@link OtaPolicy.InvalidWindowException} will be thrown. If
- * start time is later than end time, the window is considered spanning midnight, i.e. end time
- * donates a time on the next day. The maintenance window will last for two weeks, after which
- * the OTA will be installed automatically.
+ * window is considered to include the WHOLE 24 hours, that is, updates can install at any time.
+ * If the given window in invalid, a {@link SystemUpdatePolicy.InvalidWindowException} will be
+ * thrown. If start time is later than end time, the window is considered spanning midnight,
+ * i.e. end time donates a time on the next day. The maintenance window will last for 30 days,
+ * after which the system should revert back to its normal behavior as if no policy were set.
*
* @param startTime the start of the maintenance window, measured as the number of minutes from
- * midnight in the device's local time. Must be in the range of [0, 1440).
+ * midnight in the device's local time. Must be in the range of [0, 1440).
* @param endTime the end of the maintenance window, measured as the number of minutes from
- * midnight in the device's local time. Must be in the range of [0, 1440).
+ * midnight in the device's local time. Must be in the range of [0, 1440).
+ * @see #TYPE_INSTALL_WINDOWED
*/
public void setWindowedInstallPolicy(int startTime, int endTime) throws InvalidWindowException{
if (startTime < 0 || startTime >= 1440 || endTime < 0 || endTime >= 1440) {
@@ -114,8 +122,10 @@ public class OtaPolicy {
}
/**
- * Set the OTA policy to: block installation for a maximum period of two weeks. After the
- * block expires the OTA will be installed automatically.
+ * Set the policy to: block installation for a maximum period of 30 days. After expiration the
+ * system should revert back to its normal behavior as if no policy were set.
+ *
+ * @see #TYPE_POSTPONE
*/
public void setPostponeInstallPolicy() {
mPolicy.clear();
@@ -123,12 +133,12 @@ public class OtaPolicy {
}
/**
- * Returns the type of OTA policy.
+ * Returns the type of system update policy.
*
* @return an integer, either one of {@link #TYPE_INSTALL_AUTOMATIC},
* {@link #TYPE_INSTALL_WINDOWED} and {@link #TYPE_POSTPONE}, or -1 if no policy has been set.
*/
- @OtaPolicyType
+ @SystemUpdatePolicyType
public int getPolicyType() {
return mPolicy.getInt(KEY_POLICY_TYPE, -1);
}
@@ -167,7 +177,7 @@ public class OtaPolicy {
}
/**
- * Exception thrown by {@link OtaPolicy#setWindowedInstallPolicy(int, int)} in case the
+ * Exception thrown by {@link SystemUpdatePolicy#setWindowedInstallPolicy(int, int)} in case the
* specified window is invalid.
*/
public static class InvalidWindowException extends Exception {
diff --git a/core/java/android/app/backup/BlobBackupHelper.java b/core/java/android/app/backup/BlobBackupHelper.java
new file mode 100644
index 0000000..cdc62dc
--- /dev/null
+++ b/core/java/android/app/backup/BlobBackupHelper.java
@@ -0,0 +1,296 @@
+/*
+ * 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.app.backup;
+
+import android.os.ParcelFileDescriptor;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.zip.CRC32;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.InflaterInputStream;
+
+/**
+ * Utility class for writing BackupHelpers whose underlying data is a
+ * fixed set of byte-array blobs. The helper manages diff detection
+ * and compression on the wire.
+ *
+ * @hide
+ */
+public abstract class BlobBackupHelper implements BackupHelper {
+ private static final String TAG = "BlobBackupHelper";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private final int mCurrentBlobVersion;
+ private final String[] mKeys;
+
+ public BlobBackupHelper(int currentBlobVersion, String... keys) {
+ mCurrentBlobVersion = currentBlobVersion;
+ mKeys = keys;
+ }
+
+ // Client interface
+
+ /**
+ * Generate and return the byte array containing the backup payload describing
+ * the current data state. During a backup operation this method is called once
+ * per key that was supplied to the helper's constructor.
+ *
+ * @return A byte array containing the data blob that the caller wishes to store,
+ * or {@code null} if the current state is empty or undefined.
+ */
+ abstract protected byte[] getBackupPayload(String key);
+
+ /**
+ * Given a byte array that was restored from backup, do whatever is appropriate
+ * to apply that described state in the live system. This method is called once
+ * per key/value payload that was delivered for restore. Typically data is delivered
+ * for restore in lexical order by key, <i>not</i> in the order in which the keys
+ * were supplied in the constructor.
+ *
+ * @param payload The byte array that was passed to {@link #getBackupPayload()}
+ * on the ancestral device.
+ */
+ abstract protected void applyRestoredPayload(String key, byte[] payload);
+
+
+ // Internal implementation
+
+ /*
+ * State on-disk format:
+ * [Int] : overall blob version number
+ * [Int=N] : number of keys represented in the state blob
+ * N* :
+ * [String] key
+ * [Long] blob checksum, calculated after compression
+ */
+ @SuppressWarnings("resource")
+ private ArrayMap<String, Long> readOldState(ParcelFileDescriptor oldStateFd) {
+ final ArrayMap<String, Long> state = new ArrayMap<String, Long>();
+
+ FileInputStream fis = new FileInputStream(oldStateFd.getFileDescriptor());
+ BufferedInputStream bis = new BufferedInputStream(fis);
+ DataInputStream in = new DataInputStream(bis);
+
+ try {
+ int version = in.readInt();
+ if (version <= mCurrentBlobVersion) {
+ final int numKeys = in.readInt();
+ for (int i = 0; i < numKeys; i++) {
+ String key = in.readUTF();
+ long checksum = in.readLong();
+ state.put(key, checksum);
+ }
+ } else {
+ Log.w(TAG, "Prior state from unrecognized version " + version);
+ }
+ } catch (EOFException e) {
+ // Empty file is expected on first backup, so carry on. If the state
+ // is truncated we just treat it the same way.
+ state.clear();
+ } catch (Exception e) {
+ Log.e(TAG, "Error examining prior backup state " + e.getMessage());
+ state.clear();
+ }
+
+ return state;
+ }
+
+ /**
+ * New overall state record
+ */
+ private void writeBackupState(ArrayMap<String, Long> state, ParcelFileDescriptor stateFile) {
+ try {
+ FileOutputStream fos = new FileOutputStream(stateFile.getFileDescriptor());
+
+ // We explicitly don't close 'out' because we must not close the backing fd.
+ // The FileOutputStream will not close it implicitly.
+ @SuppressWarnings("resource")
+ DataOutputStream out = new DataOutputStream(fos);
+
+ out.writeInt(mCurrentBlobVersion);
+
+ final int N = (state != null) ? state.size() : 0;
+ out.writeInt(N);
+ for (int i = 0; i < N; i++) {
+ out.writeUTF(state.keyAt(i));
+ out.writeLong(state.valueAt(i).longValue());
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to write updated state", e);
+ }
+ }
+
+ // Also versions the deflated blob internally in case we need to revise it
+ private byte[] deflate(byte[] data) {
+ byte[] result = null;
+ if (data != null) {
+ try {
+ ByteArrayOutputStream sink = new ByteArrayOutputStream();
+ DataOutputStream headerOut = new DataOutputStream(sink);
+
+ // write the header directly to the sink ahead of the deflated payload
+ headerOut.writeInt(mCurrentBlobVersion);
+
+ DeflaterOutputStream out = new DeflaterOutputStream(sink);
+ out.write(data);
+ out.close(); // finishes and commits the compression run
+ result = sink.toByteArray();
+ if (DEBUG) {
+ Log.v(TAG, "Deflated " + data.length + " bytes to " + result.length);
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Unable to process payload: " + e.getMessage());
+ }
+ }
+ return result;
+ }
+
+ // Returns null if inflation failed
+ private byte[] inflate(byte[] compressedData) {
+ byte[] result = null;
+ if (compressedData != null) {
+ try {
+ ByteArrayInputStream source = new ByteArrayInputStream(compressedData);
+ DataInputStream headerIn = new DataInputStream(source);
+ int version = headerIn.readInt();
+ if (version > mCurrentBlobVersion) {
+ Log.w(TAG, "Saved payload from unrecognized version " + version);
+ return null;
+ }
+
+ InflaterInputStream in = new InflaterInputStream(source);
+ ByteArrayOutputStream inflated = new ByteArrayOutputStream();
+ byte[] buffer = new byte[4096];
+ int nRead;
+ while ((nRead = in.read(buffer)) > 0) {
+ inflated.write(buffer, 0, nRead);
+ }
+ in.close();
+ inflated.flush();
+ result = inflated.toByteArray();
+ if (DEBUG) {
+ Log.v(TAG, "Inflated " + compressedData.length + " bytes to " + result.length);
+ }
+ } catch (IOException e) {
+ // result is still null here
+ Log.w(TAG, "Unable to process restored payload: " + e.getMessage());
+ }
+ }
+ return result;
+ }
+
+ private long checksum(byte[] buffer) {
+ if (buffer != null) {
+ try {
+ CRC32 crc = new CRC32();
+ ByteArrayInputStream bis = new ByteArrayInputStream(buffer);
+ byte[] buf = new byte[4096];
+ int nRead = 0;
+ while ((nRead = bis.read(buf)) >= 0) {
+ crc.update(buf, 0, nRead);
+ }
+ return crc.getValue();
+ } catch (Exception e) {
+ // whoops; fall through with an explicitly bogus checksum
+ }
+ }
+ return -1;
+ }
+
+ // BackupHelper interface
+
+ @Override
+ public void performBackup(ParcelFileDescriptor oldStateFd, BackupDataOutput data,
+ ParcelFileDescriptor newStateFd) {
+
+ final ArrayMap<String, Long> oldState = readOldState(oldStateFd);
+ final ArrayMap<String, Long> newState = new ArrayMap<String, Long>();
+
+ try {
+ for (String key : mKeys) {
+ final byte[] payload = deflate(getBackupPayload(key));
+ final long checksum = checksum(payload);
+ newState.put(key, checksum);
+
+ Long oldChecksum = oldState.get(key);
+ if (oldChecksum == null || checksum != oldChecksum) {
+ if (DEBUG) {
+ Log.i(TAG, "State has changed for key " + key + ", writing");
+ }
+ if (payload != null) {
+ data.writeEntityHeader(key, payload.length);
+ data.writeEntityData(payload, payload.length);
+ } else {
+ // state's changed but there's no current payload => delete
+ data.writeEntityHeader(key, -1);
+ }
+ } else {
+ if (DEBUG) {
+ Log.i(TAG, "No change under key " + key + " => not writing");
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Unable to record notification state: " + e.getMessage());
+ newState.clear();
+ } finally {
+ // Always recommit the state even if nothing changed
+ writeBackupState(newState, newStateFd);
+ }
+ }
+
+ @Override
+ public void restoreEntity(BackupDataInputStream data) {
+ final String key = data.getKey();
+ try {
+ // known key?
+ int which;
+ for (which = 0; which < mKeys.length; which++) {
+ if (key.equals(mKeys[which])) {
+ break;
+ }
+ }
+ if (which >= mKeys.length) {
+ Log.e(TAG, "Unrecognized key " + key + ", ignoring");
+ return;
+ }
+
+ byte[] compressed = new byte[data.size()];
+ data.read(compressed);
+ byte[] payload = inflate(compressed);
+ applyRestoredPayload(key, payload);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception restoring entity " + key + " : " + e.getMessage());
+ }
+ }
+
+ @Override
+ public void writeNewStateDescription(ParcelFileDescriptor newState) {
+ // Just ensure that we do a full backup the first time after a restore
+ writeBackupState(null, newState);
+ }
+}
diff --git a/core/java/android/app/trust/ITrustListener.aidl b/core/java/android/app/trust/ITrustListener.aidl
index d80f58c..506dd12 100644
--- a/core/java/android/app/trust/ITrustListener.aidl
+++ b/core/java/android/app/trust/ITrustListener.aidl
@@ -22,6 +22,6 @@ package android.app.trust;
* {@hide}
*/
oneway interface ITrustListener {
- void onTrustChanged(boolean enabled, int userId, boolean initiatedByUser);
+ void onTrustChanged(boolean enabled, int userId, int flags);
void onTrustManagedChanged(boolean managed, int userId);
} \ No newline at end of file
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 705a144..b5c5317 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -34,7 +34,7 @@ public class TrustManager {
private static final int MSG_TRUST_MANAGED_CHANGED = 2;
private static final String TAG = "TrustManager";
- private static final String DATA_INITIATED_BY_USER = "initiatedByUser";
+ private static final String DATA_FLAGS = "initiatedByUser";
private final ITrustManager mService;
private final ArrayMap<TrustListener, ITrustListener> mTrustListeners;
@@ -109,11 +109,11 @@ public class TrustManager {
try {
ITrustListener.Stub iTrustListener = new ITrustListener.Stub() {
@Override
- public void onTrustChanged(boolean enabled, int userId, boolean initiatedByUser) {
+ public void onTrustChanged(boolean enabled, int userId, int flags) {
Message m = mHandler.obtainMessage(MSG_TRUST_CHANGED, (enabled ? 1 : 0), userId,
trustListener);
- if (initiatedByUser) {
- m.getData().putBoolean(DATA_INITIATED_BY_USER, initiatedByUser);
+ if (flags != 0) {
+ m.getData().putInt(DATA_FLAGS, flags);
}
m.sendToTarget();
}
@@ -156,11 +156,8 @@ public class TrustManager {
public void handleMessage(Message msg) {
switch(msg.what) {
case MSG_TRUST_CHANGED:
- boolean initiatedByUser = msg.peekData() != null &&
- msg.peekData().getBoolean(DATA_INITIATED_BY_USER);
- ((TrustListener)msg.obj).onTrustChanged(
- msg.arg1 != 0, msg.arg2, initiatedByUser);
-
+ int flags = msg.peekData() != null ? msg.peekData().getInt(DATA_FLAGS) : 0;
+ ((TrustListener)msg.obj).onTrustChanged(msg.arg1 != 0, msg.arg2, flags);
break;
case MSG_TRUST_MANAGED_CHANGED:
((TrustListener)msg.obj).onTrustManagedChanged(msg.arg1 != 0, msg.arg2);
@@ -174,10 +171,11 @@ public class TrustManager {
* Reports that the trust state has changed.
* @param enabled if true, the system believes the environment to be trusted.
* @param userId the user, for which the trust changed.
- * @param initiatedByUser indicates that the user has explicitly initiated an action that
- * proves the user is about to use the device.
+ * @param flags flags specified by the trust agent when granting trust. See
+ * {@link android.service.trust.TrustAgentService#grantTrust(CharSequence, long, int)
+ * TrustAgentService.grantTrust(CharSequence, long, int)}.
*/
- void onTrustChanged(boolean enabled, int userId, boolean initiatedByUser);
+ void onTrustChanged(boolean enabled, int userId, int flags);
/**
* Reports that whether trust is managed has changed
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 370f61c..3bf3f85 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1608,6 +1608,28 @@ public abstract class Context {
public abstract void sendBroadcastAsUser(Intent intent, UserHandle user,
@Nullable String receiverPermission);
+
+ /**
+ * Version of {@link #sendBroadcast(Intent, String)} that allows you to specify the
+ * user the broadcast will be sent to. This is not available to applications
+ * that are not pre-installed on the system image. Using it requires holding
+ * the INTERACT_ACROSS_USERS permission.
+ *
+ * @param intent The Intent to broadcast; all receivers matching this
+ * Intent will receive the broadcast.
+ * @param user UserHandle to send the intent to.
+ * @param receiverPermission (optional) String naming a permission that
+ * a receiver must hold in order to receive your broadcast.
+ * If null, no permission is required.
+ * @param appOp The app op associated with the broadcast.
+ *
+ * @see #sendBroadcast(Intent, String)
+ *
+ * @hide
+ */
+ public abstract void sendBroadcastAsUser(Intent intent, UserHandle user,
+ @Nullable String receiverPermission, int appOp);
+
/**
* Version of
* {@link #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)}
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 92f0079..fb9e194 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -444,6 +444,13 @@ public class ContextWrapper extends Context {
mBase.sendBroadcastAsUser(intent, user, receiverPermission);
}
+ /** @hide */
+ @Override
+ public void sendBroadcastAsUser(Intent intent, UserHandle user,
+ String receiverPermission, int appOp) {
+ mBase.sendBroadcastAsUser(intent, user, receiverPermission, appOp);
+ }
+
@Override
public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 8d82aa2..16f6b1e 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -223,11 +223,12 @@ public class ActivityInfo extends ComponentInfo
*/
public static final int FLAG_HARDWARE_ACCELERATED = 0x0200;
/**
- * Value for {@link #flags}: true when the application can be displayed over the lockscreen
- * and consequently over all users' windows.
+ * Value for {@link #flags}: true when the application can be displayed for all users
+ * regardless of if the user of the application is the current user. Set from the
+ * {@link android.R.attr#showForAllUsers} attribute.
* @hide
*/
- public static final int FLAG_SHOW_ON_LOCK_SCREEN = 0x0400;
+ public static final int FLAG_SHOW_FOR_ALL_USERS = 0x0400;
/**
* Bit in {@link #flags} corresponding to an immersive activity
* that wishes not to be interrupted by notifications.
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index caf069f..6c32873 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -339,8 +339,14 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* (e.g., HTTP rather than HTTPS; WebSockets rather than WebSockets Secure; XMPP, IMAP, STMP
* without STARTTLS or TLS). If {@code false}, the app declares that it does not intend to use
* cleartext network traffic, in which case platform components (e.g., HTTP stacks,
- * {@code WebView}, {@code MediaPlayer}) will refuse app's requests to use cleartext traffic.
- * Third-party libraries are encouraged to honor this flag as well.
+ * {@code DownloadManager}, {@code MediaPlayer}) will refuse app's requests to use cleartext
+ * traffic. Third-party libraries are encouraged to honor this flag as well.
+ *
+ * <p>NOTE: {@code WebView} does not honor this flag.
+ *
+ * <p>This flag comes from
+ * {@link android.R.styleable#AndroidManifestApplication_usesCleartextTraffic
+ * android:usesCleartextTraffic} of the &lt;application&gt; tag.
*/
public static final int FLAG_USES_CLEARTEXT_TRAFFIC = 1<<27;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index c2580c0..447c668 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -328,7 +328,7 @@ interface IPackageManager {
* @param observer call back used to notify when
* the operation is completed
*/
- void freeStorageAndNotify(in long freeStorageSize,
+ void freeStorageAndNotify(in String volumeUuid, in long freeStorageSize,
IPackageDataObserver observer);
/**
@@ -352,7 +352,7 @@ interface IPackageManager {
* notify when the operation is completed.May be null
* to indicate that no call back is desired.
*/
- void freeStorage(in long freeStorageSize,
+ void freeStorage(in String volumeUuid, in long freeStorageSize,
in IntentSender pi);
/**
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index c81517a..5c21c8e 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -146,6 +146,7 @@ public class LauncherApps {
try {
activities = mService.getLauncherActivities(packageName, user);
} catch (RemoteException re) {
+ throw new RuntimeException("Failed to call LauncherAppsService");
}
if (activities == null) {
return Collections.EMPTY_LIST;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index a128872..a0cec50 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3798,7 +3798,13 @@ public abstract class PackageManager {
* @hide
*/
// @SystemApi
- public abstract void freeStorageAndNotify(long freeStorageSize, IPackageDataObserver observer);
+ public void freeStorageAndNotify(long freeStorageSize, IPackageDataObserver observer) {
+ freeStorageAndNotify(null, freeStorageSize, observer);
+ }
+
+ /** {@hide} */
+ public abstract void freeStorageAndNotify(String volumeUuid, long freeStorageSize,
+ IPackageDataObserver observer);
/**
* Free storage by deleting LRU sorted list of cache files across
@@ -3823,7 +3829,12 @@ public abstract class PackageManager {
*
* @hide
*/
- public abstract void freeStorage(long freeStorageSize, IntentSender pi);
+ public void freeStorage(long freeStorageSize, IntentSender pi) {
+ freeStorage(null, freeStorageSize, pi);
+ }
+
+ /** {@hide} */
+ public abstract void freeStorage(String volumeUuid, long freeStorageSize, IntentSender pi);
/**
* Retrieve the size information for a package.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 40f4e8f..fed9261 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3099,8 +3099,9 @@ public class PackageParser {
a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
}
- if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false)) {
- a.info.flags |= ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN;
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_showOnLockScreen, false)
+ || sa.getBoolean(R.styleable.AndroidManifestActivity_showForAllUsers, false)) {
+ a.info.flags |= ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
}
if (sa.getBoolean(R.styleable.AndroidManifestActivity_immersive, false)) {
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 88fa339..7ad3a68 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -26,6 +26,7 @@ import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import dalvik.system.CloseGuard;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -224,8 +225,8 @@ public class SystemSensorManager extends SensorManager {
* the queues and the listeners.
*/
private static abstract class BaseEventQueue {
- private native long nativeInitBaseEventQueue(BaseEventQueue eventQ, MessageQueue msgQ,
- float[] scratch, String packageName);
+ private native long nativeInitBaseEventQueue(WeakReference<BaseEventQueue> eventQWeak,
+ MessageQueue msgQ, float[] scratch, String packageName);
private static native int nativeEnableSensor(long eventQ, int handle, int rateUs,
int maxBatchReportLatencyUs);
private static native int nativeDisableSensor(long eventQ, int handle);
@@ -240,7 +241,8 @@ public class SystemSensorManager extends SensorManager {
protected final SystemSensorManager mManager;
BaseEventQueue(Looper looper, SystemSensorManager manager) {
- nSensorEventQueue = nativeInitBaseEventQueue(this, looper.getQueue(), mScratch,
+ nSensorEventQueue = nativeInitBaseEventQueue(new WeakReference<BaseEventQueue>(this),
+ looper.getQueue(), mScratch,
manager.mPackageName);
mCloseGuard.open("dispose");
mManager = manager;
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 8f7aed4..87a1ca9 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1030,12 +1030,13 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* point, <code>z_s = 1</code>, and <code>w_s</code> is a measurement of disparity
* (depth) in pixel coordinates.</p>
* <p><b>Units</b>:
- * Pixels in the android.sensor.activeArraySize coordinate
+ * Pixels in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate
* system.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
* @see CameraCharacteristics#LENS_POSE_ROTATION
* @see CameraCharacteristics#LENS_POSE_TRANSLATION
+ * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
*/
@PublicKey
public static final Key<float[]> LENS_INTRINSIC_CALIBRATION =
@@ -1330,6 +1331,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS READ_SENSOR_SETTINGS}</li>
* <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE BURST_CAPTURE}</li>
* <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING YUV_REPROCESSING}</li>
+ * <li>{@link #REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT DEPTH_OUTPUT}</li>
* </ul></p>
* <p>This key is available on all devices.</p>
*
@@ -1342,6 +1344,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* @see #REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS
* @see #REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE
* @see #REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING
+ * @see #REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT
*/
@PublicKey
public static final Key<int[]> REQUEST_AVAILABLE_CAPABILITIES =
@@ -2542,11 +2545,23 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* post-processing, arbitrary cropping regions, and has relaxed performance constraints.</p>
* <p>Each higher level supports everything the lower level supports
* in this order: FULL <code>&gt;</code> LIMITED <code>&gt;</code> LEGACY.</p>
+ * <p>A HIGH_RESOLUTION device is equivalent to a FULL device, except that:</p>
+ * <ul>
+ * <li>At least one output resolution of 8 megapixels or higher in uncompressed YUV is
+ * supported at <code>&gt;=</code> 20 fps.</li>
+ * <li>Maximum-size (sensor resolution) uncompressed YUV is supported at <code>&gt;=</code> 10
+ * fps.</li>
+ * <li>For devices that list the RAW capability and support either RAW10 or RAW12 output,
+ * maximum-resolution RAW10 or RAW12 capture will operate at least at the rate of
+ * maximum-resolution YUV capture, and at least one supported output resolution of
+ * 8 megapixels or higher in RAW10 or RAW12 is supported <code>&gt;=</code> 20 fps.</li>
+ * </ul>
* <p><b>Possible values:</b>
* <ul>
* <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED}</li>
* <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}</li>
* <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY}</li>
+ * <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_HIGH_RESOLUTION HIGH_RESOLUTION}</li>
* </ul></p>
* <p>This key is available on all devices.</p>
*
@@ -2564,6 +2579,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* @see #INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED
* @see #INFO_SUPPORTED_HARDWARE_LEVEL_FULL
* @see #INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY
+ * @see #INFO_SUPPORTED_HARDWARE_LEVEL_HIGH_RESOLUTION
*/
@PublicKey
public static final Key<Integer> INFO_SUPPORTED_HARDWARE_LEVEL =
@@ -2694,6 +2710,29 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS =
new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.depth.availableDepthStallDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class);
+ /**
+ * <p>Indicates whether a capture request may target both a
+ * DEPTH16 / DEPTH_POINT_CLOUD output, and normal color outputs (such as
+ * YUV_420_888, JPEG, or RAW) simultaneously.</p>
+ * <p>If TRUE, including both depth and color outputs in a single
+ * capture request is not supported. An application must interleave color
+ * and depth requests. If FALSE, a single request can target both types
+ * of output.</p>
+ * <p>Typically, this restriction exists on camera devices that
+ * need to emit a specific pattern or wavelength of light to
+ * measure depth values, which causes the color image to be
+ * corrupted during depth measurement.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * <p><b>Limited capability</b> -
+ * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+ * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+ *
+ * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+ */
+ @PublicKey
+ public static final Key<Boolean> DEPTH_DEPTH_IS_EXCLUSIVE =
+ new Key<Boolean>("android.depth.depthIsExclusive", boolean.class);
+
/*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
* End generated code
*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 4a5bd08..e3f1d73 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -303,10 +303,13 @@ public abstract class CameraMetadata<TKey> {
* <p>The minimal set of capabilities that every camera
* device (regardless of {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel})
* supports.</p>
- * <p>This capability is listed by all devices, and
+ * <p>This capability is listed by all normal devices, and
* indicates that the camera device has a feature set
* that's comparable to the baseline requirements for the
* older android.hardware.Camera API.</p>
+ * <p>Devices with the DEPTH_OUTPUT capability might not list this
+ * capability, indicating that they support only depth measurement,
+ * not standard color output.</p>
*
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
@@ -545,6 +548,11 @@ public abstract class CameraMetadata<TKey> {
* {@link CameraCharacteristics#CONTROL_AWB_LOCK_AVAILABLE android.control.awbLockAvailable} are also guaranteed
* to be <code>true</code> so burst capture with these two locks ON
* yields consistent image output.</p>
+ * <p>On a camera device that reports the HIGH_RESOLUTION hardware
+ * level, meaning the device supports very large capture sizes,
+ * BURST_CAPTURE means that at least 8-megapixel images can be
+ * captured at <code>&gt;=</code> 20 fps, and maximum-resolution images can be
+ * captured at <code>&gt;=</code> 10 fps.</p>
*
* @see CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES
* @see CameraCharacteristics#CONTROL_AE_LOCK_AVAILABLE
@@ -596,6 +604,42 @@ public abstract class CameraMetadata<TKey> {
*/
public static final int REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING = 7;
+ /**
+ * <p>The camera device can produce depth measurements from its field of view.</p>
+ * <p>This capability requires the camera device to support the following:</p>
+ * <ul>
+ * <li>DEPTH16 is supported as an output format.</li>
+ * <li>DEPTH_POINT_CLOUD is optionally supported as an output format.</li>
+ * <li>This camera device, and all camera devices with the same android.lens.info.facing,
+ * will list the following calibration entries in both CameraCharacteristics and
+ * CaptureResults:<ul>
+ * <li>{@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}</li>
+ * <li>{@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}</li>
+ * <li>android.lens.intrinsicCalibration</li>
+ * <li>android.lens.radialDistortion</li>
+ * </ul>
+ * </li>
+ * <li>The {@link CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE android.depth.depthIsExclusive} entry is listed by this device.</li>
+ * <li>A LIMITED camera with only the DEPTH_OUTPUT capability does not have to support
+ * normal YUV_420_888, JPEG, and PRIV-format outputs. It only has to support the DEPTH16
+ * format.</li>
+ * </ul>
+ * <p>Generally, depth output operates at a slower frame rate than standard color capture,
+ * so the DEPTH16 and DEPTH_POINT_CLOUD formats will commonly have a stall duration that
+ * should be accounted for (see
+ * android.hardware.camera2.StreamConfigurationMap#getOutputStallDuration). On a device
+ * that supports both depth and color-based output, to enable smooth preview, using a
+ * repeating burst is recommended, where a depth-output target is only included once
+ * every N frames, where N is the ratio between preview output rate and depth output
+ * rate, including depth stall time.</p>
+ *
+ * @see CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE
+ * @see CameraCharacteristics#LENS_POSE_ROTATION
+ * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ */
+ public static final int REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT = 8;
+
//
// Enumeration values for CameraCharacteristics#SCALER_CROPPING_TYPE
//
@@ -808,6 +852,13 @@ public abstract class CameraMetadata<TKey> {
*/
public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2;
+ /**
+ * <p>This camera device is capable of supporting advanced imaging applications at full rate,
+ * and additional high-resolution outputs at lower rates.</p>
+ * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+ */
+ public static final int INFO_SUPPORTED_HARDWARE_LEVEL_HIGH_RESOLUTION = 3;
+
//
// Enumeration values for CameraCharacteristics#SYNC_MAX_LATENCY
//
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 4134d28..ef5d75c 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2628,12 +2628,13 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* point, <code>z_s = 1</code>, and <code>w_s</code> is a measurement of disparity
* (depth) in pixel coordinates.</p>
* <p><b>Units</b>:
- * Pixels in the android.sensor.activeArraySize coordinate
+ * Pixels in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate
* system.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
* @see CameraCharacteristics#LENS_POSE_ROTATION
* @see CameraCharacteristics#LENS_POSE_TRANSLATION
+ * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
*/
@PublicKey
public static final Key<float[]> LENS_INTRINSIC_CALIBRATION =
diff --git a/core/java/android/hardware/fingerprint/FingerprintUtils.java b/core/java/android/hardware/fingerprint/FingerprintUtils.java
index ae3d4a4..525f254 100644
--- a/core/java/android/hardware/fingerprint/FingerprintUtils.java
+++ b/core/java/android/hardware/fingerprint/FingerprintUtils.java
@@ -17,6 +17,8 @@
package android.hardware.fingerprint;
import android.content.ContentResolver;
+import android.content.Context;
+import android.os.Vibrator;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
@@ -35,6 +37,8 @@ public
class FingerprintUtils {
private static final boolean DEBUG = true;
private static final String TAG = "FingerprintUtils";
+ private static final long[] FP_ERROR_VIBRATE_PATTERN = new long[] {0, 30, 100, 30};
+ private static final long[] FP_SUCCESS_VIBRATE_PATTERN = new long[] {0, 30};
private static int[] toIntArray(List<Integer> list) {
if (list == null) {
@@ -104,5 +108,19 @@ class FingerprintUtils {
return false;
}
+ public static void vibrateFingerprintError(Context context) {
+ Vibrator vibrator = context.getSystemService(Vibrator.class);
+ if (vibrator != null) {
+ vibrator.vibrate(FP_ERROR_VIBRATE_PATTERN, -1);
+ }
+ }
+
+ public static void vibrateFingerprintSuccess(Context context) {
+ Vibrator vibrator = context.getSystemService(Vibrator.class);
+ if (vibrator != null) {
+ vibrator.vibrate(FP_SUCCESS_VIBRATE_PATTERN, -1);
+ }
+ }
+
};
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 47d5fc6..6870327 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -40,7 +40,6 @@ import android.telephony.SubscriptionManager;
import android.util.ArrayMap;
import android.util.Log;
-import com.android.internal.net.VpnConfig;
import com.android.internal.telephony.ITelephony;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.util.Protocol;
@@ -99,16 +98,6 @@ public class ConnectivityManager {
public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
/**
- * Identical to {@link #CONNECTIVITY_ACTION} broadcast, but sent without any
- * historic {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY}.
- *
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String CONNECTIVITY_ACTION_IMMEDIATE =
- "android.net.conn.CONNECTIVITY_CHANGE_IMMEDIATE";
-
- /**
* The lookup key for a {@link NetworkInfo} object. Retrieve with
* {@link android.content.Intent#getParcelableExtra(String)}.
*
@@ -2517,30 +2506,9 @@ public class ConnectivityManager {
* @hide
*/
public void factoryReset() {
- // Turn airplane mode off
- setAirplaneMode(false);
-
- // Untether
- for (String tether : getTetheredIfaces()) {
- untether(tether);
- }
-
- // Turn VPN off
try {
- VpnConfig vpnConfig = mService.getVpnConfig();
- if (vpnConfig != null) {
- if (vpnConfig.legacy) {
- mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN);
- } else {
- // Prevent this app from initiating VPN connections in the future without
- // user intervention.
- mService.setVpnPackageAuthorization(false);
-
- mService.prepareVpn(vpnConfig.user, VpnConfig.LEGACY_VPN);
- }
- }
+ mService.factoryReset();
} catch (RemoteException e) {
- // Well, we tried
}
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 9152f69..efc76b3 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -164,4 +164,6 @@ interface IConnectivityManager
boolean addVpnAddress(String address, int prefixLength);
boolean removeVpnAddress(String address, int prefixLength);
boolean setUnderlyingNetworksForVpn(in Network[] networks);
+
+ void factoryReset();
}
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 7e92de2..c722fbc 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -45,7 +45,7 @@ interface INetworkPolicyManager {
/** Control network policies atomically. */
void setNetworkPolicies(in NetworkPolicy[] policies);
- NetworkPolicy[] getNetworkPolicies();
+ NetworkPolicy[] getNetworkPolicies(String callingPackage);
/** Snooze limit on policy matching given template. */
void snoozeLimit(in NetworkTemplate template);
@@ -58,4 +58,6 @@ interface INetworkPolicyManager {
NetworkQuotaInfo getNetworkQuotaInfo(in NetworkState state);
boolean isNetworkMetered(in NetworkState state);
+
+ void factoryReset(String subscriber);
}
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index a7ffee9..bc03637 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -61,12 +61,14 @@ public class NetworkPolicyManager {
*/
public static final String EXTRA_NETWORK_TEMPLATE = "android.net.NETWORK_TEMPLATE";
+ private final Context mContext;
private INetworkPolicyManager mService;
- public NetworkPolicyManager(INetworkPolicyManager service) {
+ public NetworkPolicyManager(Context context, INetworkPolicyManager service) {
if (service == null) {
throw new IllegalArgumentException("missing INetworkPolicyManager");
}
+ mContext = context;
mService = service;
}
@@ -158,7 +160,7 @@ public class NetworkPolicyManager {
public NetworkPolicy[] getNetworkPolicies() {
try {
- return mService.getNetworkPolicies();
+ return mService.getNetworkPolicies(mContext.getOpPackageName());
} catch (RemoteException e) {
return null;
}
@@ -185,24 +187,9 @@ public class NetworkPolicyManager {
* @hide
*/
public void factoryReset(String subscriber) {
- // Turn mobile data limit off
- NetworkPolicy[] policies = getNetworkPolicies();
- NetworkTemplate template = NetworkTemplate.buildTemplateMobileAll(subscriber);
- for (NetworkPolicy policy : policies) {
- if (policy.template.equals(template)) {
- policy.limitBytes = NetworkPolicy.LIMIT_DISABLED;
- policy.inferred = false;
- policy.clearSnooze();
- }
- }
- setNetworkPolicies(policies);
-
- // Turn restrict background data off
- setRestrictBackground(false);
-
- // Remove app's "restrict background data" flag
- for (int uid : getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND)) {
- setUidPolicy(uid, NetworkPolicyManager.POLICY_NONE);
+ try {
+ mService.factoryReset(subscriber);
+ } catch (RemoteException e) {
}
}
diff --git a/core/java/android/nfc/IAppCallback.aidl b/core/java/android/nfc/IAppCallback.aidl
index 9599308..c027d54 100644
--- a/core/java/android/nfc/IAppCallback.aidl
+++ b/core/java/android/nfc/IAppCallback.aidl
@@ -24,7 +24,7 @@ import android.nfc.Tag;
*/
interface IAppCallback
{
- BeamShareData createBeamShareData();
- void onNdefPushComplete();
+ BeamShareData createBeamShareData(byte peerLlcpVersion);
+ void onNdefPushComplete(byte peerLlcpVersion);
void onTagDiscovered(in Tag tag);
}
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index d009295..76bd0ec 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -46,7 +46,6 @@ public final class NfcActivityManager extends IAppCallback.Stub
static final Boolean DBG = false;
final NfcAdapter mAdapter;
- final NfcEvent mDefaultEvent; // cached NfcEvent (its currently always the same)
// All objects in the lists are protected by this
final List<NfcApplicationState> mApps; // Application(s) that have NFC state. Usually one
@@ -200,7 +199,6 @@ public final class NfcActivityManager extends IAppCallback.Stub
mAdapter = adapter;
mActivities = new LinkedList<NfcActivityState>();
mApps = new ArrayList<NfcApplicationState>(1); // Android VM usually has 1 app
- mDefaultEvent = new NfcEvent(mAdapter);
}
public void enableReaderMode(Activity activity, ReaderCallback callback, int flags,
@@ -354,13 +352,14 @@ public final class NfcActivityManager extends IAppCallback.Stub
/** Callback from NFC service, usually on binder thread */
@Override
- public BeamShareData createBeamShareData() {
+ public BeamShareData createBeamShareData(byte peerLlcpVersion) {
NfcAdapter.CreateNdefMessageCallback ndefCallback;
NfcAdapter.CreateBeamUrisCallback urisCallback;
NdefMessage message;
Activity activity;
Uri[] uris;
int flags;
+ NfcEvent event = new NfcEvent(mAdapter, peerLlcpVersion);
synchronized (NfcActivityManager.this) {
NfcActivityState state = findResumedActivityState();
if (state == null) return null;
@@ -375,10 +374,10 @@ public final class NfcActivityManager extends IAppCallback.Stub
// Make callbacks without lock
if (ndefCallback != null) {
- message = ndefCallback.createNdefMessage(mDefaultEvent);
+ message = ndefCallback.createNdefMessage(event);
}
if (urisCallback != null) {
- uris = urisCallback.createBeamUris(mDefaultEvent);
+ uris = urisCallback.createBeamUris(event);
if (uris != null) {
ArrayList<Uri> validUris = new ArrayList<Uri>();
for (Uri uri : uris) {
@@ -412,7 +411,7 @@ public final class NfcActivityManager extends IAppCallback.Stub
/** Callback from NFC service, usually on binder thread */
@Override
- public void onNdefPushComplete() {
+ public void onNdefPushComplete(byte peerLlcpVersion) {
NfcAdapter.OnNdefPushCompleteCallback callback;
synchronized (NfcActivityManager.this) {
NfcActivityState state = findResumedActivityState();
@@ -420,10 +419,10 @@ public final class NfcActivityManager extends IAppCallback.Stub
callback = state.onNdefPushCompleteCallback;
}
-
+ NfcEvent event = new NfcEvent(mAdapter, peerLlcpVersion);
// Make callback without lock
if (callback != null) {
- callback.onNdefPushComplete(mDefaultEvent);
+ callback.onNdefPushComplete(event);
}
}
diff --git a/core/java/android/nfc/NfcEvent.java b/core/java/android/nfc/NfcEvent.java
index 860700a..cf1d71a 100644
--- a/core/java/android/nfc/NfcEvent.java
+++ b/core/java/android/nfc/NfcEvent.java
@@ -38,7 +38,14 @@ public final class NfcEvent {
*/
public final NfcAdapter nfcAdapter;
- NfcEvent(NfcAdapter nfcAdapter) {
+ /**
+ * The LLCP version of the peer associated with the NFC event.
+ * The major version is in the top nibble, the minor version is in the bottom nibble.
+ */
+ public final byte peerLlcpVersion;
+
+ NfcEvent(NfcAdapter nfcAdapter, byte peerLlcpVersion) {
this.nfcAdapter = nfcAdapter;
+ this.peerLlcpVersion = peerLlcpVersion;
}
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 7c5ddee..4dfe0de 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -152,10 +152,15 @@ public abstract class BatteryStats implements Parcelable {
private static final String[] STAT_NAMES = { "l", "c", "u" };
/**
- * Bump the version on this if the checkin format changes.
+ * Current version of checkin data format.
+ */
+ static final String CHECKIN_VERSION = "14";
+
+ /**
+ * Old version, we hit 9 and ran out of room, need to remove.
*/
private static final int BATTERY_STATS_CHECKIN_VERSION = 9;
-
+
private static final long BYTES_PER_KB = 1024;
private static final long BYTES_PER_MB = 1048576; // 1024^2
private static final long BYTES_PER_GB = 1073741824; //1024^3
@@ -178,7 +183,9 @@ public abstract class BatteryStats implements Parcelable {
private static final String BATTERY_DATA = "bt";
private static final String BATTERY_DISCHARGE_DATA = "dc";
private static final String BATTERY_LEVEL_DATA = "lv";
+ private static final String GLOBAL_WIFI_DATA = "gwfl";
private static final String WIFI_DATA = "wfl";
+ private static final String GLOBAL_BLUETOOTH_DATA = "gble";
private static final String MISC_DATA = "m";
private static final String GLOBAL_NETWORK_DATA = "gn";
private static final String HISTORY_STRING_POOL = "hsp";
@@ -195,8 +202,6 @@ public abstract class BatteryStats implements Parcelable {
private static final String WIFI_SUPPL_STATE_COUNT_DATA = "wssc";
private static final String WIFI_SIGNAL_STRENGTH_TIME_DATA = "wsgt";
private static final String WIFI_SIGNAL_STRENGTH_COUNT_DATA = "wsgc";
- private static final String BLUETOOTH_STATE_TIME_DATA = "bst";
- private static final String BLUETOOTH_STATE_COUNT_DATA = "bsc";
private static final String POWER_USE_SUMMARY_DATA = "pws";
private static final String POWER_USE_ITEM_DATA = "pwi";
private static final String DISCHARGE_STEP_DATA = "dsd";
@@ -1055,22 +1060,23 @@ public abstract class BatteryStats implements Parcelable {
public static final int STATE_GPS_ON_FLAG = 1<<29;
public static final int STATE_WIFI_FULL_LOCK_FLAG = 1<<28;
public static final int STATE_WIFI_SCAN_FLAG = 1<<27;
- public static final int STATE_WIFI_MULTICAST_ON_FLAG = 1<<26;
+ public static final int STATE_WIFI_RADIO_ACTIVE_FLAG = 1<<26;
public static final int STATE_MOBILE_RADIO_ACTIVE_FLAG = 1<<25;
// These are on the lower bits used for the command; if they change
// we need to write another int of data.
public static final int STATE_SENSOR_ON_FLAG = 1<<23;
public static final int STATE_AUDIO_ON_FLAG = 1<<22;
public static final int STATE_PHONE_SCANNING_FLAG = 1<<21;
- public static final int STATE_SCREEN_ON_FLAG = 1<<20;
- public static final int STATE_BATTERY_PLUGGED_FLAG = 1<<19;
- public static final int STATE_PHONE_IN_CALL_FLAG = 1<<18;
- public static final int STATE_CHARGING_FLAG = 1<<17;
- public static final int STATE_BLUETOOTH_ON_FLAG = 1<<16;
+ public static final int STATE_SCREEN_ON_FLAG = 1<<20; // consider moving to states2
+ public static final int STATE_BATTERY_PLUGGED_FLAG = 1<<19; // consider moving to states2
+ // empty slot
+ // empty slot
+ public static final int STATE_WIFI_MULTICAST_ON_FLAG = 1<<16;
public static final int MOST_INTERESTING_STATES =
- STATE_BATTERY_PLUGGED_FLAG | STATE_SCREEN_ON_FLAG
- | STATE_PHONE_IN_CALL_FLAG | STATE_BLUETOOTH_ON_FLAG;
+ STATE_BATTERY_PLUGGED_FLAG | STATE_SCREEN_ON_FLAG;
+
+ public static final int SETTLE_TO_ZERO_STATES = 0xffff0000 & ~MOST_INTERESTING_STATES;
public int states;
@@ -1088,9 +1094,15 @@ public abstract class BatteryStats implements Parcelable {
public static final int STATE2_WIFI_ON_FLAG = 1<<28;
public static final int STATE2_FLASHLIGHT_FLAG = 1<<27;
public static final int STATE2_DEVICE_IDLE_FLAG = 1<<26;
+ public static final int STATE2_CHARGING_FLAG = 1<<25;
+ public static final int STATE2_PHONE_IN_CALL_FLAG = 1<<24;
+ public static final int STATE2_BLUETOOTH_ON_FLAG = 1<<23;
public static final int MOST_INTERESTING_STATES2 =
- STATE2_POWER_SAVE_FLAG | STATE2_WIFI_ON_FLAG | STATE2_DEVICE_IDLE_FLAG;
+ STATE2_POWER_SAVE_FLAG | STATE2_WIFI_ON_FLAG | STATE2_DEVICE_IDLE_FLAG
+ | STATE2_CHARGING_FLAG | STATE2_PHONE_IN_CALL_FLAG | STATE2_BLUETOOTH_ON_FLAG;
+
+ public static final int SETTLE_TO_ZERO_STATES2 = 0xffff0000 & ~MOST_INTERESTING_STATES2;
public int states2;
@@ -1137,8 +1149,10 @@ public abstract class BatteryStats implements Parcelable {
public static final int EVENT_PACKAGE_UNINSTALLED = 0x000d;
// Event for a package being uninstalled.
public static final int EVENT_ALARM = 0x000e;
+ // Record that we have decided we need to collect new stats data.
+ public static final int EVENT_COLLECT_EXTERNAL_STATS = 0x000f;
// Number of event types.
- public static final int EVENT_COUNT = 0x000f;
+ public static final int EVENT_COUNT = 0x0010;
// Mask to extract out only the type part of the event.
public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH);
@@ -1750,14 +1764,12 @@ public abstract class BatteryStats implements Parcelable {
new BitDescription(HistoryItem.STATE_WIFI_FULL_LOCK_FLAG, "wifi_full_lock", "Wl"),
new BitDescription(HistoryItem.STATE_WIFI_SCAN_FLAG, "wifi_scan", "Ws"),
new BitDescription(HistoryItem.STATE_WIFI_MULTICAST_ON_FLAG, "wifi_multicast", "Wm"),
+ new BitDescription(HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG, "wifi_radio", "Wr"),
new BitDescription(HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG, "mobile_radio", "Pr"),
new BitDescription(HistoryItem.STATE_PHONE_SCANNING_FLAG, "phone_scanning", "Psc"),
new BitDescription(HistoryItem.STATE_AUDIO_ON_FLAG, "audio", "a"),
new BitDescription(HistoryItem.STATE_SCREEN_ON_FLAG, "screen", "S"),
new BitDescription(HistoryItem.STATE_BATTERY_PLUGGED_FLAG, "plugged", "BP"),
- new BitDescription(HistoryItem.STATE_PHONE_IN_CALL_FLAG, "phone_in_call", "Pcl"),
- new BitDescription(HistoryItem.STATE_CHARGING_FLAG, "charging", "ch"),
- new BitDescription(HistoryItem.STATE_BLUETOOTH_ON_FLAG, "bluetooth", "b"),
new BitDescription(HistoryItem.STATE_DATA_CONNECTION_MASK,
HistoryItem.STATE_DATA_CONNECTION_SHIFT, "data_conn", "Pcn",
DATA_CONNECTION_NAMES, DATA_CONNECTION_NAMES),
@@ -1778,10 +1790,13 @@ public abstract class BatteryStats implements Parcelable {
= new BitDescription[] {
new BitDescription(HistoryItem.STATE2_POWER_SAVE_FLAG, "power_save", "ps"),
new BitDescription(HistoryItem.STATE2_VIDEO_ON_FLAG, "video", "v"),
- new BitDescription(HistoryItem.STATE2_WIFI_RUNNING_FLAG, "wifi_running", "Wr"),
+ new BitDescription(HistoryItem.STATE2_WIFI_RUNNING_FLAG, "wifi_running", "Ww"),
new BitDescription(HistoryItem.STATE2_WIFI_ON_FLAG, "wifi", "W"),
new BitDescription(HistoryItem.STATE2_FLASHLIGHT_FLAG, "flashlight", "fl"),
new BitDescription(HistoryItem.STATE2_DEVICE_IDLE_FLAG, "device_idle", "di"),
+ new BitDescription(HistoryItem.STATE2_CHARGING_FLAG, "charging", "ch"),
+ new BitDescription(HistoryItem.STATE2_PHONE_IN_CALL_FLAG, "phone_in_call", "Pcl"),
+ new BitDescription(HistoryItem.STATE2_BLUETOOTH_ON_FLAG, "bluetooth", "b"),
new BitDescription(HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_MASK,
HistoryItem.STATE2_WIFI_SIGNAL_STRENGTH_SHIFT, "wifi_signal_strength", "Wss",
new String[] { "0", "1", "2", "3", "4" },
@@ -1793,12 +1808,12 @@ public abstract class BatteryStats implements Parcelable {
public static final String[] HISTORY_EVENT_NAMES = new String[] {
"null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn",
- "motion", "active", "pkginst", "pkgunin", "alarm"
+ "motion", "active", "pkginst", "pkgunin", "alarm", "stats"
};
public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
"Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf", "Ecn",
- "Esm", "Eac", "Epi", "Epu", "Eal"
+ "Esm", "Eac", "Epi", "Epu", "Eal", "Est"
};
/**
@@ -1883,43 +1898,6 @@ public abstract class BatteryStats implements Parcelable {
public abstract int getWifiSignalStrengthCount(int strengthBin, int which);
/**
- * Returns the time in microseconds that bluetooth has been on while the device was
- * running on battery.
- *
- * {@hide}
- */
- public abstract long getBluetoothOnTime(long elapsedRealtimeUs, int which);
-
- public abstract int getBluetoothPingCount();
-
- public static final int BLUETOOTH_STATE_INACTIVE = 0;
- public static final int BLUETOOTH_STATE_LOW = 1;
- public static final int BLUETOOTH_STATE_MEDIUM = 2;
- public static final int BLUETOOTH_STATE_HIGH = 3;
-
- static final String[] BLUETOOTH_STATE_NAMES = {
- "inactive", "low", "med", "high"
- };
-
- public static final int NUM_BLUETOOTH_STATES = BLUETOOTH_STATE_HIGH +1;
-
- /**
- * Returns the time in microseconds that Bluetooth has been running in the
- * given active state.
- *
- * {@hide}
- */
- public abstract long getBluetoothStateTime(int bluetoothState,
- long elapsedRealtimeUs, int which);
-
- /**
- * Returns the number of times that Bluetooth has entered the given active state.
- *
- * {@hide}
- */
- public abstract int getBluetoothStateCount(int bluetoothState, int which);
-
- /**
* Returns the time in microseconds that the flashlight has been on while the device was
* running on battery.
*
@@ -2431,9 +2409,6 @@ public abstract class BatteryStats implements Parcelable {
final long deviceIdlingTime = getDeviceIdlingTime(rawRealtime, which);
final int connChanges = getNumConnectivityChange(which);
final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
- final long wifiOnTime = getWifiOnTime(rawRealtime, which);
- final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
- final long bluetoothOnTime = getBluetoothOnTime(rawRealtime, which);
final StringBuilder sb = new StringBuilder(128);
@@ -2475,7 +2450,8 @@ public abstract class BatteryStats implements Parcelable {
}
}
}
-
+
+ // Dump network stats
final long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
final long mobileTxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
final long wifiRxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
@@ -2484,19 +2460,34 @@ public abstract class BatteryStats implements Parcelable {
final long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
final long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
final long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
-
- // Dump network stats
dumpLine(pw, 0 /* uid */, category, GLOBAL_NETWORK_DATA,
mobileRxTotalBytes, mobileTxTotalBytes, wifiRxTotalBytes, wifiTxTotalBytes,
mobileRxTotalPackets, mobileTxTotalPackets, wifiRxTotalPackets, wifiTxTotalPackets);
+ // Dump Wifi controller stats
+ final long wifiOnTime = getWifiOnTime(rawRealtime, which);
+ final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
+ final long wifiIdleTimeMs = getWifiControllerActivity(CONTROLLER_IDLE_TIME, which);
+ final long wifiRxTimeMs = getWifiControllerActivity(CONTROLLER_RX_TIME, which);
+ final long wifiTxTimeMs = getWifiControllerActivity(CONTROLLER_TX_TIME, which);
+ final long wifiPowerMaMs = getWifiControllerActivity(CONTROLLER_POWER_DRAIN, which);
+ dumpLine(pw, 0 /* uid */, category, GLOBAL_WIFI_DATA,
+ wifiOnTime / 1000, wifiRunningTime / 1000,
+ wifiIdleTimeMs, wifiRxTimeMs, wifiTxTimeMs, wifiPowerMaMs / (1000*60*60));
+
+ // Dump Bluetooth controller stats
+ final long btIdleTimeMs = getBluetoothControllerActivity(CONTROLLER_IDLE_TIME, which);
+ final long btRxTimeMs = getBluetoothControllerActivity(CONTROLLER_RX_TIME, which);
+ final long btTxTimeMs = getBluetoothControllerActivity(CONTROLLER_TX_TIME, which);
+ final long btPowerMaMs = getBluetoothControllerActivity(CONTROLLER_POWER_DRAIN, which);
+ dumpLine(pw, 0 /* uid */, category, GLOBAL_BLUETOOTH_DATA,
+ btIdleTimeMs, btRxTimeMs, btTxTimeMs, btPowerMaMs / (1000*60*60));
+
// Dump misc stats
dumpLine(pw, 0 /* uid */, category, MISC_DATA,
- screenOnTime / 1000, phoneOnTime / 1000, wifiOnTime / 1000,
- wifiRunningTime / 1000, bluetoothOnTime / 1000,
- mobileRxTotalBytes, mobileTxTotalBytes, wifiRxTotalBytes, wifiTxTotalBytes,
+ screenOnTime / 1000, phoneOnTime / 1000,
fullWakeLockTimeTotal / 1000, partialWakeLockTimeTotal / 1000,
- 0 /*legacy input event count*/, getMobileRadioActiveTime(rawRealtime, which) / 1000,
+ getMobileRadioActiveTime(rawRealtime, which) / 1000,
getMobileRadioActiveAdjustedTime(which) / 1000, interactiveTime / 1000,
powerSaveModeEnabledTime / 1000, connChanges, deviceIdleModeEnabledTime / 1000,
getDeviceIdleModeEnabledCount(which), deviceIdlingTime / 1000,
@@ -2566,17 +2557,6 @@ public abstract class BatteryStats implements Parcelable {
}
dumpLine(pw, 0 /* uid */, category, WIFI_SIGNAL_STRENGTH_COUNT_DATA, args);
- // Dump bluetooth state stats
- args = new Object[NUM_BLUETOOTH_STATES];
- for (int i=0; i<NUM_BLUETOOTH_STATES; i++) {
- args[i] = getBluetoothStateTime(i, rawRealtime, which) / 1000;
- }
- dumpLine(pw, 0 /* uid */, category, BLUETOOTH_STATE_TIME_DATA, args);
- for (int i=0; i<NUM_BLUETOOTH_STATES; i++) {
- args[i] = getBluetoothStateCount(i, which);
- }
- dumpLine(pw, 0 /* uid */, category, BLUETOOTH_STATE_COUNT_DATA, args);
-
if (which == STATS_SINCE_UNPLUGGED) {
dumpLine(pw, 0 /* uid */, category, BATTERY_LEVEL_DATA, getDischargeStartLevel(),
getDischargeCurrentLevel());
@@ -2681,6 +2661,7 @@ public abstract class BatteryStats implements Parcelable {
continue;
}
final Uid u = uidStats.valueAt(iu);
+
// Dump Network stats per uid, if any
final long mobileBytesRx = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
final long mobileBytesTx = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
@@ -2692,11 +2673,6 @@ public abstract class BatteryStats implements Parcelable {
final int mobileActiveCount = u.getMobileRadioActiveCount(which);
final long wifiPacketsRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
final long wifiPacketsTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
- final long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
- final long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
- final int wifiScanCount = u.getWifiScanCount(which);
- final long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
-
if (mobileBytesRx > 0 || mobileBytesTx > 0 || wifiBytesRx > 0 || wifiBytesTx > 0
|| mobilePacketsRx > 0 || mobilePacketsTx > 0 || wifiPacketsRx > 0
|| wifiPacketsTx > 0 || mobileActiveTime > 0 || mobileActiveCount > 0) {
@@ -2707,10 +2683,19 @@ public abstract class BatteryStats implements Parcelable {
mobileActiveTime, mobileActiveCount);
}
+ final long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
+ final long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
+ final int wifiScanCount = u.getWifiScanCount(which);
+ final long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
+ final long uidWifiIdleTimeMs = u.getWifiControllerActivity(CONTROLLER_IDLE_TIME, which);
+ final long uidWifiRxTimeMs = u.getWifiControllerActivity(CONTROLLER_RX_TIME, which);
+ final long uidWifiTxTimeMs = u.getWifiControllerActivity(CONTROLLER_TX_TIME, which);
if (fullWifiLockOnTime != 0 || wifiScanTime != 0 || wifiScanCount != 0
- || uidWifiRunningTime != 0) {
+ || uidWifiRunningTime != 0 || uidWifiIdleTimeMs != 0 || uidWifiRxTimeMs != 0
+ || uidWifiTxTimeMs != 0) {
dumpLine(pw, uid, category, WIFI_DATA,
- fullWifiLockOnTime, wifiScanTime, uidWifiRunningTime, wifiScanCount);
+ fullWifiLockOnTime, wifiScanTime, uidWifiRunningTime, wifiScanCount,
+ uidWifiIdleTimeMs, uidWifiRxTimeMs, uidWifiTxTimeMs);
}
if (u.hasUserActivity()) {
@@ -2968,7 +2953,6 @@ public abstract class BatteryStats implements Parcelable {
final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
final long wifiOnTime = getWifiOnTime(rawRealtime, which);
- final long bluetoothOnTime = getBluetoothOnTime(rawRealtime, which);
sb.setLength(0);
sb.append(prefix);
sb.append(" Screen on: "); formatTimeMs(sb, screenOnTime / 1000);
@@ -3317,42 +3301,11 @@ public abstract class BatteryStats implements Parcelable {
sb.setLength(0);
sb.append(prefix);
- sb.append(" WiFi Energy use: ").append(BatteryStatsHelper.makemAh(
+ sb.append(" WiFi Power drain: ").append(BatteryStatsHelper.makemAh(
getWifiControllerActivity(CONTROLLER_POWER_DRAIN, which) / (double)(1000*60*60)));
sb.append(" mAh");
pw.println(sb.toString());
- sb.setLength(0);
- sb.append(prefix);
- sb.append(" Bluetooth on: "); formatTimeMs(sb, bluetoothOnTime / 1000);
- sb.append("("); sb.append(formatRatioLocked(bluetoothOnTime, whichBatteryRealtime));
- sb.append(")");
- pw.println(sb.toString());
-
- sb.setLength(0);
- sb.append(prefix);
- sb.append(" Bluetooth states:");
- didOne = false;
- for (int i=0; i<NUM_BLUETOOTH_STATES; i++) {
- final long time = getBluetoothStateTime(i, rawRealtime, which);
- if (time == 0) {
- continue;
- }
- sb.append("\n ");
- didOne = true;
- sb.append(BLUETOOTH_STATE_NAMES[i]);
- sb.append(" ");
- formatTimeMs(sb, time/1000);
- sb.append("(");
- sb.append(formatRatioLocked(time, whichBatteryRealtime));
- sb.append(") ");
- sb.append(getPhoneDataConnectionCount(i, which));
- sb.append("x");
- }
-
- if (!didOne) sb.append(" (no activity)");
- pw.println(sb.toString());
-
final long bluetoothIdleTimeMs =
getBluetoothControllerActivity(CONTROLLER_IDLE_TIME, which);
final long bluetoothRxTimeMs = getBluetoothControllerActivity(CONTROLLER_RX_TIME, which);
@@ -3384,6 +3337,14 @@ public abstract class BatteryStats implements Parcelable {
sb.append(")");
pw.println(sb.toString());
+ sb.setLength(0);
+ sb.append(prefix);
+ sb.append(" Bluetooth Power drain: ").append(BatteryStatsHelper.makemAh(
+ getBluetoothControllerActivity(CONTROLLER_POWER_DRAIN, which) /
+ (double)(1000*60*60)));
+ sb.append(" mAh");
+ pw.println(sb.toString());
+
pw.println();
if (which == STATS_SINCE_UNPLUGGED) {
@@ -4883,7 +4844,8 @@ public abstract class BatteryStats implements Parcelable {
prepareForDumpLocked();
dumpLine(pw, 0 /* uid */, "i" /* category */, VERSION_DATA,
- "13", getParcelVersion(), getStartPlatformVersion(), getEndPlatformVersion());
+ CHECKIN_VERSION, getParcelVersion(), getStartPlatformVersion(),
+ getEndPlatformVersion());
long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 9d8a1ba..af23f11 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -283,6 +283,8 @@ public final class Parcel {
private static native void nativeWriteInterfaceToken(long nativePtr, String interfaceName);
private static native void nativeEnforceInterface(long nativePtr, String interfaceName);
+ private static native long nativeGetBlobAshmemSize(long nativePtr);
+
public final static Parcelable.Creator<String> STRING_CREATOR
= new Parcelable.Creator<String>() {
public String createFromParcel(Parcel source) {
@@ -2594,4 +2596,11 @@ public final class Parcel {
N--;
}
}
+
+ /**
+ * @hide For testing
+ */
+ public long getBlobAshmemSize() {
+ return nativeGetBlobAshmemSize(mNativePtr);
+ }
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index b9e307f..44eb1ed 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -466,9 +466,9 @@ public class UserManager {
}
/**
- * Returns the user handle for the user that the calling process is running on.
+ * Returns the user handle for the user that this process is running under.
*
- * @return the user handle of the user making this call.
+ * @return the user handle of this process.
* @hide
*/
public int getUserHandle() {
@@ -505,6 +505,17 @@ public class UserManager {
}
/**
+ * Used to check if this process is running under the system user. The system user
+ * is the initial user that is implicitly created on first boot and hosts most of the
+ * system services.
+ *
+ * @return whether this process is running under the system user.
+ */
+ public boolean isSystemUser() {
+ return UserHandle.myUserId() == UserHandle.USER_OWNER;
+ }
+
+ /**
* Used to check if the user making this call is linked to another user. Linked users may have
* a reduced number of available apps, app restrictions and account restrictions.
* @return whether the user making this call is a linked user
diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java
index 2c60d41..64f2a05 100644
--- a/core/java/android/os/storage/DiskInfo.java
+++ b/core/java/android/os/storage/DiskInfo.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.content.res.Resources;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import android.util.DebugUtils;
import com.android.internal.util.IndentingPrintWriter;
@@ -46,7 +47,6 @@ public class DiskInfo implements Parcelable {
public final int flags;
public long size;
public String label;
- public String[] volumeIds;
public DiskInfo(String id, int flags) {
this.id = Preconditions.checkNotNull(id);
@@ -58,19 +58,39 @@ public class DiskInfo implements Parcelable {
flags = parcel.readInt();
size = parcel.readLong();
label = parcel.readString();
- volumeIds = parcel.readStringArray();
}
public @NonNull String getId() {
return id;
}
+ private boolean isInteresting(String label) {
+ if (TextUtils.isEmpty(label)) {
+ return false;
+ }
+ if (label.equalsIgnoreCase("ata")) {
+ return false;
+ }
+ if (label.toLowerCase().contains("generic")) {
+ return false;
+ }
+ return true;
+ }
+
public String getDescription() {
- // TODO: splice vendor label into these strings
+ final Resources res = Resources.getSystem();
if ((flags & FLAG_SD) != 0) {
- return Resources.getSystem().getString(com.android.internal.R.string.storage_sd_card);
+ if (isInteresting(label)) {
+ return res.getString(com.android.internal.R.string.storage_sd_card_label, label);
+ } else {
+ return res.getString(com.android.internal.R.string.storage_sd_card);
+ }
} else if ((flags & FLAG_USB) != 0) {
- return Resources.getSystem().getString(com.android.internal.R.string.storage_usb);
+ if (isInteresting(label)) {
+ return res.getString(com.android.internal.R.string.storage_usb_drive_label, label);
+ } else {
+ return res.getString(com.android.internal.R.string.storage_usb_drive);
+ }
} else {
return null;
}
@@ -96,13 +116,11 @@ public class DiskInfo implements Parcelable {
}
public void dump(IndentingPrintWriter pw) {
- pw.println("DiskInfo:");
+ pw.println("DiskInfo{" + id + "}:");
pw.increaseIndent();
- pw.printPair("id", id);
pw.printPair("flags", DebugUtils.flagsToString(getClass(), "FLAG_", flags));
pw.printPair("size", size);
pw.printPair("label", label);
- pw.printPair("volumeIds", volumeIds);
pw.decreaseIndent();
pw.println();
}
@@ -156,6 +174,5 @@ public class DiskInfo implements Parcelable {
parcel.writeInt(this.flags);
parcel.writeLong(size);
parcel.writeString(label);
- parcel.writeStringArray(volumeIds);
}
}
diff --git a/core/java/android/os/storage/IMountServiceListener.java b/core/java/android/os/storage/IMountServiceListener.java
index fd914bc..8e878a4 100644
--- a/core/java/android/os/storage/IMountServiceListener.java
+++ b/core/java/android/os/storage/IMountServiceListener.java
@@ -98,6 +98,13 @@ public interface IMountServiceListener extends IInterface {
reply.writeNoException();
return true;
}
+ case TRANSACTION_onDiskUnsupported: {
+ data.enforceInterface(DESCRIPTOR);
+ final DiskInfo disk = (DiskInfo) data.readParcelable(null);
+ onDiskUnsupported(disk);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
}
@@ -198,6 +205,22 @@ public interface IMountServiceListener extends IInterface {
_data.recycle();
}
}
+
+ @Override
+ public void onDiskUnsupported(DiskInfo disk) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeParcelable(disk, 0);
+ mRemote.transact(Stub.TRANSACTION_onDiskUnsupported, _data, _reply,
+ android.os.IBinder.FLAG_ONEWAY);
+ _reply.readException();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ }
}
static final int TRANSACTION_onUsbMassStorageConnectionChanged = (IBinder.FIRST_CALL_TRANSACTION + 0);
@@ -206,6 +229,7 @@ public interface IMountServiceListener extends IInterface {
static final int TRANSACTION_onVolumeStateChanged = (IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_onVolumeMetadataChanged = (IBinder.FIRST_CALL_TRANSACTION + 3);
+ static final int TRANSACTION_onDiskUnsupported = (IBinder.FIRST_CALL_TRANSACTION + 4);
}
/**
@@ -230,4 +254,6 @@ public interface IMountServiceListener extends IInterface {
throws RemoteException;
public void onVolumeMetadataChanged(VolumeInfo vol) throws RemoteException;
+
+ public void onDiskUnsupported(DiskInfo disk) throws RemoteException;
}
diff --git a/core/java/android/os/storage/StorageEventListener.java b/core/java/android/os/storage/StorageEventListener.java
index 28a187d..ad2fae0 100644
--- a/core/java/android/os/storage/StorageEventListener.java
+++ b/core/java/android/os/storage/StorageEventListener.java
@@ -43,4 +43,7 @@ public class StorageEventListener {
public void onVolumeMetadataChanged(VolumeInfo vol) {
}
+
+ public void onDiskUnsupported(DiskInfo disk) {
+ }
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 0e977ff..f101352 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -69,6 +69,8 @@ public class StorageManager {
/** {@hide} */
public static final String PROP_PRIMARY_PHYSICAL = "ro.vold.primary_physical";
+ /** {@hide} */
+ public static final String PROP_FORCE_ADOPTABLE = "persist.fw.force_adoptable";
/** {@hide} */
public static final int FLAG_ALL_METADATA = 1 << 0;
@@ -87,6 +89,7 @@ public class StorageManager {
private static final int MSG_STORAGE_STATE_CHANGED = 1;
private static final int MSG_VOLUME_STATE_CHANGED = 2;
private static final int MSG_VOLUME_METADATA_CHANGED = 3;
+ private static final int MSG_DISK_UNSUPPORTED = 4;
final StorageEventListener mCallback;
final Handler mHandler;
@@ -113,6 +116,10 @@ public class StorageManager {
mCallback.onVolumeMetadataChanged((VolumeInfo) args.arg1);
args.recycle();
return true;
+ case MSG_DISK_UNSUPPORTED:
+ mCallback.onDiskUnsupported((DiskInfo) args.arg1);
+ args.recycle();
+ return true;
}
args.recycle();
return false;
@@ -147,6 +154,13 @@ public class StorageManager {
args.arg1 = vol;
mHandler.obtainMessage(MSG_VOLUME_METADATA_CHANGED, args).sendToTarget();
}
+
+ @Override
+ public void onDiskUnsupported(DiskInfo disk) {
+ final SomeArgs args = SomeArgs.obtain();
+ args.arg1 = disk;
+ mHandler.obtainMessage(MSG_DISK_UNSUPPORTED, args).sendToTarget();
+ }
}
/**
@@ -494,6 +508,16 @@ public class StorageManager {
}
/** {@hide} */
+ public @Nullable VolumeInfo findPrivateForEmulated(VolumeInfo emulatedVol) {
+ return findVolumeById(emulatedVol.getId().replace("emulated", "private"));
+ }
+
+ /** {@hide} */
+ public @Nullable VolumeInfo findEmulatedForPrivate(VolumeInfo privateVol) {
+ return findVolumeById(privateVol.getId().replace("private", "emulated"));
+ }
+
+ /** {@hide} */
public @NonNull List<VolumeInfo> getVolumes() {
return getVolumes(0);
}
@@ -511,10 +535,9 @@ public class StorageManager {
public @Nullable String getBestVolumeDescription(VolumeInfo vol) {
String descrip = vol.getDescription();
- if (vol.diskId != null) {
- final DiskInfo disk = findDiskById(vol.diskId);
- if (disk != null && TextUtils.isEmpty(descrip)) {
- descrip = disk.getDescription();
+ if (vol.disk != null) {
+ if (TextUtils.isEmpty(descrip)) {
+ descrip = vol.disk.getDescription();
}
}
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index a241728..f3498d5 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -49,7 +49,10 @@ import java.util.Objects;
* @hide
*/
public class VolumeInfo implements Parcelable {
- public static final String EXTRA_VOLUME_ID = "android.os.storage.extra.VOLUME_ID";
+ public static final String ACTION_VOLUME_STATE_CHANGED =
+ "android.os.storage.action.VOLUME_STATE_CHANGED";
+ public static final String EXTRA_VOLUME_ID =
+ "android.os.storage.extra.VOLUME_ID";
/** Stub volume representing internal private storage */
public static final String ID_PRIVATE_INTERNAL = "private";
@@ -63,15 +66,17 @@ public class VolumeInfo implements Parcelable {
public static final int TYPE_OBB = 4;
public static final int STATE_UNMOUNTED = 0;
- public static final int STATE_MOUNTING = 1;
+ public static final int STATE_CHECKING = 1;
public static final int STATE_MOUNTED = 2;
- public static final int STATE_FORMATTING = 3;
- public static final int STATE_UNMOUNTING = 4;
- public static final int STATE_UNMOUNTABLE = 5;
- public static final int STATE_REMOVED = 6;
+ public static final int STATE_MOUNTED_READ_ONLY = 3;
+ public static final int STATE_FORMATTING = 4;
+ public static final int STATE_EJECTING = 5;
+ public static final int STATE_UNMOUNTABLE = 6;
+ public static final int STATE_REMOVED = 7;
+ public static final int STATE_BAD_REMOVAL = 8;
- public static final int FLAG_PRIMARY = 1 << 0;
- public static final int FLAG_VISIBLE = 1 << 1;
+ 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;
@@ -97,26 +102,31 @@ public class VolumeInfo implements Parcelable {
static {
sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTED, Environment.MEDIA_UNMOUNTED);
- sStateToEnvironment.put(VolumeInfo.STATE_MOUNTING, Environment.MEDIA_CHECKING);
+ sStateToEnvironment.put(VolumeInfo.STATE_CHECKING, Environment.MEDIA_CHECKING);
sStateToEnvironment.put(VolumeInfo.STATE_MOUNTED, Environment.MEDIA_MOUNTED);
+ sStateToEnvironment.put(VolumeInfo.STATE_MOUNTED_READ_ONLY, Environment.MEDIA_MOUNTED_READ_ONLY);
sStateToEnvironment.put(VolumeInfo.STATE_FORMATTING, Environment.MEDIA_UNMOUNTED);
- sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTING, Environment.MEDIA_EJECTING);
+ sStateToEnvironment.put(VolumeInfo.STATE_EJECTING, Environment.MEDIA_EJECTING);
sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTABLE, Environment.MEDIA_UNMOUNTABLE);
sStateToEnvironment.put(VolumeInfo.STATE_REMOVED, Environment.MEDIA_REMOVED);
+ sStateToEnvironment.put(VolumeInfo.STATE_BAD_REMOVAL, Environment.MEDIA_BAD_REMOVAL);
sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTED, Intent.ACTION_MEDIA_UNMOUNTED);
sEnvironmentToBroadcast.put(Environment.MEDIA_CHECKING, Intent.ACTION_MEDIA_CHECKING);
sEnvironmentToBroadcast.put(Environment.MEDIA_MOUNTED, Intent.ACTION_MEDIA_MOUNTED);
+ sEnvironmentToBroadcast.put(Environment.MEDIA_MOUNTED_READ_ONLY, Intent.ACTION_MEDIA_MOUNTED);
sEnvironmentToBroadcast.put(Environment.MEDIA_EJECTING, Intent.ACTION_MEDIA_EJECT);
sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTABLE, Intent.ACTION_MEDIA_UNMOUNTABLE);
sEnvironmentToBroadcast.put(Environment.MEDIA_REMOVED, Intent.ACTION_MEDIA_REMOVED);
+ sEnvironmentToBroadcast.put(Environment.MEDIA_BAD_REMOVAL, Intent.ACTION_MEDIA_BAD_REMOVAL);
}
/** vold state */
public final String id;
public final int type;
- public int flags = 0;
- public int userId = -1;
+ public final DiskInfo disk;
+ public int mountFlags = 0;
+ public int mountUserId = -1;
public int state = STATE_UNMOUNTED;
public String fsType;
public String fsUuid;
@@ -125,28 +135,32 @@ public class VolumeInfo implements Parcelable {
/** Framework state */
public final int mtpIndex;
- public String diskId;
public String nickname;
public int userFlags = 0;
- public VolumeInfo(String id, int type, int mtpIndex) {
+ public VolumeInfo(String id, int type, DiskInfo disk, int mtpIndex) {
this.id = Preconditions.checkNotNull(id);
this.type = type;
+ this.disk = disk;
this.mtpIndex = mtpIndex;
}
public VolumeInfo(Parcel parcel) {
id = parcel.readString();
type = parcel.readInt();
- flags = parcel.readInt();
- userId = parcel.readInt();
+ if (parcel.readInt() != 0) {
+ disk = DiskInfo.CREATOR.createFromParcel(parcel);
+ } else {
+ disk = null;
+ }
+ mountFlags = parcel.readInt();
+ mountUserId = parcel.readInt();
state = parcel.readInt();
fsType = parcel.readString();
fsUuid = parcel.readString();
fsLabel = parcel.readString();
path = parcel.readString();
mtpIndex = parcel.readInt();
- diskId = parcel.readString();
nickname = parcel.readString();
userFlags = parcel.readInt();
}
@@ -176,8 +190,12 @@ public class VolumeInfo implements Parcelable {
return id;
}
+ public @Nullable DiskInfo getDisk() {
+ return disk;
+ }
+
public @Nullable String getDiskId() {
- return diskId;
+ return (disk != null) ? disk.id : null;
}
public int getType() {
@@ -196,6 +214,10 @@ public class VolumeInfo implements Parcelable {
return nickname;
}
+ public int getMountUserId() {
+ return mountUserId;
+ }
+
public @Nullable String getDescription() {
if (ID_PRIVATE_INTERNAL.equals(id)) {
return Resources.getSystem().getString(com.android.internal.R.string.storage_internal);
@@ -208,12 +230,20 @@ public class VolumeInfo implements Parcelable {
}
}
+ public boolean isMountedReadable() {
+ return state == STATE_MOUNTED || state == STATE_MOUNTED_READ_ONLY;
+ }
+
+ public boolean isMountedWritable() {
+ return state == STATE_MOUNTED;
+ }
+
public boolean isPrimary() {
- return (flags & FLAG_PRIMARY) != 0;
+ return (mountFlags & MOUNT_FLAG_PRIMARY) != 0;
}
public boolean isVisible() {
- return (flags & FLAG_VISIBLE) != 0;
+ return (mountFlags & MOUNT_FLAG_VISIBLE) != 0;
}
public boolean isInited() {
@@ -225,7 +255,7 @@ public class VolumeInfo implements Parcelable {
}
public boolean isVisibleToUser(int userId) {
- if (type == TYPE_PUBLIC && userId == this.userId) {
+ if (type == TYPE_PUBLIC && userId == this.mountUserId) {
return isVisible();
} else if (type == TYPE_EMULATED) {
return isVisible();
@@ -241,7 +271,7 @@ public class VolumeInfo implements Parcelable {
public File getPathForUser(int userId) {
if (path == null) {
return null;
- } else if (type == TYPE_PUBLIC && userId == this.userId) {
+ } else if (type == TYPE_PUBLIC && userId == this.mountUserId) {
return new File(path);
} else if (type == TYPE_EMULATED) {
return new File(path, Integer.toString(userId));
@@ -250,6 +280,19 @@ public class VolumeInfo implements Parcelable {
}
}
+ /**
+ * Path which is accessible to apps holding
+ * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}.
+ */
+ public File getInternalPathForUser(int userId) {
+ if (type == TYPE_PUBLIC) {
+ // TODO: plumb through cleaner path from vold
+ return new File(path.replace("/storage/", "/mnt/media_rw/"));
+ } else {
+ return getPathForUser(userId);
+ }
+ }
+
public StorageVolume buildStorageVolume(Context context, int userId) {
final boolean removable;
final boolean emulated;
@@ -333,12 +376,12 @@ public class VolumeInfo implements Parcelable {
}
public void dump(IndentingPrintWriter pw) {
- pw.println("VolumeInfo:");
+ pw.println("VolumeInfo{" + id + "}:");
pw.increaseIndent();
- pw.printPair("id", id);
pw.printPair("type", DebugUtils.valueToString(getClass(), "TYPE_", type));
- pw.printPair("flags", DebugUtils.flagsToString(getClass(), "FLAG_", flags));
- pw.printPair("userId", userId);
+ pw.printPair("diskId", getDiskId());
+ pw.printPair("mountFlags", DebugUtils.flagsToString(getClass(), "MOUNT_FLAG_", mountFlags));
+ pw.printPair("mountUserId", mountUserId);
pw.printPair("state", DebugUtils.valueToString(getClass(), "STATE_", state));
pw.println();
pw.printPair("fsType", fsType);
@@ -347,7 +390,6 @@ public class VolumeInfo implements Parcelable {
pw.println();
pw.printPair("path", path);
pw.printPair("mtpIndex", mtpIndex);
- pw.printPair("diskId", diskId);
pw.printPair("nickname", nickname);
pw.printPair("userFlags", DebugUtils.flagsToString(getClass(), "USER_FLAG_", userFlags));
pw.decreaseIndent();
@@ -401,15 +443,20 @@ public class VolumeInfo implements Parcelable {
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(id);
parcel.writeInt(type);
- parcel.writeInt(this.flags);
- parcel.writeInt(userId);
+ if (disk != null) {
+ parcel.writeInt(1);
+ disk.writeToParcel(parcel, flags);
+ } else {
+ parcel.writeInt(0);
+ }
+ parcel.writeInt(mountFlags);
+ parcel.writeInt(mountUserId);
parcel.writeInt(state);
parcel.writeString(fsType);
parcel.writeString(fsUuid);
parcel.writeString(fsLabel);
parcel.writeString(path);
parcel.writeInt(mtpIndex);
- parcel.writeString(diskId);
parcel.writeString(nickname);
parcel.writeInt(userFlags);
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 793971f..a622a21 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6033,6 +6033,13 @@ public final class Settings {
public static final String DISPLAY_SIZE_FORCED = "display_size_forced";
/**
+ * The saved value for WindowManagerService.setForcedDisplayScalingMode().
+ * 0 or unset if scaling is automatic, 1 if scaling is disabled.
+ * @hide
+ */
+ public static final String DISPLAY_SCALING_FORCE = "display_scaling_force";
+
+ /**
* The maximum size, in bytes, of a download that the download manager will transfer over
* a non-wifi connection.
* @hide
diff --git a/core/java/android/security/NetworkSecurityPolicy.java b/core/java/android/security/NetworkSecurityPolicy.java
index 0b3bf45..7e87717 100644
--- a/core/java/android/security/NetworkSecurityPolicy.java
+++ b/core/java/android/security/NetworkSecurityPolicy.java
@@ -46,8 +46,8 @@ public class NetworkSecurityPolicy {
* without TLS or STARTTLS) is permitted for this process.
*
* <p>When cleartext network traffic is not permitted, the platform's components (e.g. HTTP and
- * FTP stacks, {@link android.webkit.WebView}, {@link android.media.MediaPlayer}) will refuse
- * this process's requests to use cleartext traffic. Third-party libraries are strongly
+ * FTP stacks, {@link android.app.DownloadManager}, {@link android.media.MediaPlayer}) will
+ * refuse this process's requests to use cleartext traffic. Third-party libraries are strongly
* encouraged to honor this setting as well.
*
* <p>This flag is honored on a best effort basis because it's impossible to prevent all
@@ -56,6 +56,8 @@ public class NetworkSecurityPolicy {
* because it cannot determine whether its traffic is in cleartext. However, most network
* traffic from applications is handled by higher-level network stacks/components which can
* honor this aspect of the policy.
+ *
+ * <p>NOTE: {@link android.webkit.WebView} does not honor this flag.
*/
public boolean isCleartextTrafficPermitted() {
return libcore.net.NetworkSecurityPolicy.isCleartextTrafficPermitted();
diff --git a/core/java/android/security/keymaster/KeymasterArgument.java b/core/java/android/security/keymaster/KeymasterArgument.java
index 9a1c894..9adde35 100644
--- a/core/java/android/security/keymaster/KeymasterArgument.java
+++ b/core/java/android/security/keymaster/KeymasterArgument.java
@@ -42,6 +42,7 @@ abstract class KeymasterArgument implements Parcelable {
case KeymasterDefs.KM_INT_REP:
return new KeymasterIntArgument(tag, in);
case KeymasterDefs.KM_LONG:
+ case KeymasterDefs.KM_LONG_REP:
return new KeymasterLongArgument(tag, in);
case KeymasterDefs.KM_DATE:
return new KeymasterDateArgument(tag, in);
diff --git a/core/java/android/security/keymaster/KeymasterArguments.java b/core/java/android/security/keymaster/KeymasterArguments.java
index 8ed288c..82f65c7 100644
--- a/core/java/android/security/keymaster/KeymasterArguments.java
+++ b/core/java/android/security/keymaster/KeymasterArguments.java
@@ -63,6 +63,12 @@ public class KeymasterArguments implements Parcelable {
}
}
+ public void addLongs(int tag, long... values) {
+ for (long value : values) {
+ addLong(tag, value);
+ }
+ }
+
public void addBoolean(int tag) {
mArguments.add(new KeymasterBooleanArgument(tag));
}
@@ -111,8 +117,13 @@ public class KeymasterArguments implements Parcelable {
}
public long getLong(int tag, long defaultValue) {
- if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_LONG) {
- throw new IllegalArgumentException("Tag is not a long type: " + tag);
+ switch (KeymasterDefs.getTagType(tag)) {
+ case KeymasterDefs.KM_LONG:
+ break; // Accepted type
+ case KeymasterDefs.KM_LONG_REP:
+ throw new IllegalArgumentException("Repeatable tags must use getLongs: " + tag);
+ default:
+ throw new IllegalArgumentException("Tag is not a long type: " + tag);
}
KeymasterArgument arg = getArgumentByTag(tag);
if (arg == null) {
@@ -175,6 +186,19 @@ public class KeymasterArguments implements Parcelable {
return values;
}
+ public List<Long> getLongs(int tag) {
+ if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_LONG_REP) {
+ throw new IllegalArgumentException("Tag is not a repeating long: " + tag);
+ }
+ List<Long> values = new ArrayList<Long>();
+ for (KeymasterArgument arg : mArguments) {
+ if (arg.tag == tag) {
+ values.add(((KeymasterLongArgument) arg).value);
+ }
+ }
+ return values;
+ }
+
public int size() {
return mArguments.size();
}
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index ab8a8b6..40baf9c 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -118,9 +118,9 @@ public final class KeymasterDefs {
public static final int KM_DIGEST_SHA_2_512 = 6;
// Key origins.
- public static final int KM_ORIGIN_HARDWARE = 0;
- public static final int KM_ORIGIN_SOFTWARE = 1;
+ public static final int KM_ORIGIN_GENERATED = 0;
public static final int KM_ORIGIN_IMPORTED = 2;
+ public static final int KM_ORIGIN_UNKNOWN = 3;
// Key usability requirements.
public static final int KM_BLOB_STANDALONE = 0;
diff --git a/core/java/android/security/keymaster/KeymasterLongArgument.java b/core/java/android/security/keymaster/KeymasterLongArgument.java
index 9d2be09..eb17b7e 100644
--- a/core/java/android/security/keymaster/KeymasterLongArgument.java
+++ b/core/java/android/security/keymaster/KeymasterLongArgument.java
@@ -28,6 +28,7 @@ class KeymasterLongArgument extends KeymasterArgument {
super(tag);
switch (KeymasterDefs.getTagType(tag)) {
case KeymasterDefs.KM_LONG:
+ case KeymasterDefs.KM_LONG_REP:
break; // OK.
default:
throw new IllegalArgumentException("Bad long tag " + tag);
diff --git a/core/java/android/service/gatekeeper/IGateKeeperService.aidl b/core/java/android/service/gatekeeper/IGateKeeperService.aidl
index 2f3e296..4f46701 100644
--- a/core/java/android/service/gatekeeper/IGateKeeperService.aidl
+++ b/core/java/android/service/gatekeeper/IGateKeeperService.aidl
@@ -53,13 +53,27 @@ interface IGateKeeperService {
* Verifies an enrolled handle against a provided, plaintext blob.
* @param uid The Android user ID associated to this enrollment
* @param challenge a challenge to authenticate agaisnt the device credential. If successful
- * authentication occurs, this value will be written to the returned
+ * authentication occurs, this value will be written to the returned
* authentication attestation.
* @param enrolledPasswordHandle The handle against which the provided password will be
* verified.
* @param The plaintext blob to verify against enrolledPassword.
* @return an opaque attestation of authentication on success, or null.
*/
- byte[] verifyChallenge(int uid, long challenge, in byte[] enrolledPasswordHandle,
+ byte[] verifyChallenge(int uid, long challenge, in byte[] enrolledPasswordHandle,
in byte[] providedPassword);
+
+ /**
+ * Retrieves the secure identifier for the user with the provided Android ID,
+ * or 0 if none is found.
+ * @param uid the Android user id
+ */
+ long getSecureUserId(int uid);
+
+ /**
+ * Clears secure user id associated with the provided Android ID.
+ * Must be called when password is set to NONE.
+ * @param uid the Android user id.
+ */
+ void clearSecureUserId(int uid);
}
diff --git a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
index 76b2be0..ec66cc8 100644
--- a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
+++ b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl
@@ -24,7 +24,7 @@ import android.os.UserHandle;
* @hide
*/
oneway interface ITrustAgentServiceCallback {
- void grantTrust(CharSequence message, long durationMs, boolean initiatedByUser);
+ void grantTrust(CharSequence message, long durationMs, int flags);
void revokeTrust();
void setManagingTrust(boolean managingTrust);
void onConfigureCompleted(boolean result, IBinder token);
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index a3178e2..9d7ffad 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -17,6 +17,7 @@
package android.service.trust;
import android.Manifest;
+import android.annotation.IntDef;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
import android.app.Service;
@@ -32,6 +33,8 @@ import android.os.RemoteException;
import android.util.Log;
import android.util.Slog;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.List;
/**
@@ -69,6 +72,7 @@ import java.util.List;
*/
@SystemApi
public class TrustAgentService extends Service {
+
private final String TAG = TrustAgentService.class.getSimpleName() +
"[" + getClass().getSimpleName() + "]";
private static final boolean DEBUG = false;
@@ -86,6 +90,34 @@ public class TrustAgentService extends Service {
*/
public static final String TRUST_AGENT_META_DATA = "android.service.trust.trustagent";
+
+ /**
+ * Flag for {@link #grantTrust(CharSequence, long, int)} indicating that trust is being granted
+ * as the direct result of user action - such as solving a security challenge. The hint is used
+ * by the system to optimize the experience. Behavior may vary by device and release, so
+ * one should only set this parameter if it meets the above criteria rather than relying on
+ * the behavior of any particular device or release.
+ */
+ public static final int FLAG_GRANT_TRUST_INITIATED_BY_USER = 1 << 0;
+
+ /**
+ * Flag for {@link #grantTrust(CharSequence, long, int)} indicating that the agent would like
+ * to dismiss the keyguard. When using this flag, the {@code TrustAgentService} must ensure
+ * it is only set in response to a direct user action with the expectation of dismissing the
+ * keyguard.
+ */
+ public static final int FLAG_GRANT_TRUST_DISMISS_KEYGUARD = 1 << 1;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true,
+ value = {
+ FLAG_GRANT_TRUST_INITIATED_BY_USER,
+ FLAG_GRANT_TRUST_DISMISS_KEYGUARD,
+ })
+ public @interface GrantTrustFlags {}
+
+
private static final int MSG_UNLOCK_ATTEMPT = 1;
private static final int MSG_CONFIGURE = 2;
private static final int MSG_TRUST_TIMEOUT = 3;
@@ -228,11 +260,35 @@ public class TrustAgentService extends Service {
* direct result of user action - such as solving a security challenge. The hint is used
* by the system to optimize the experience. Behavior may vary by device and release, so
* one should only set this parameter if it meets the above criteria rather than relying on
- * the behavior of any particular device or release.
+ * the behavior of any particular device or release. Corresponds to
+ * {@link #FLAG_GRANT_TRUST_INITIATED_BY_USER}.
* @throws IllegalStateException if the agent is not currently managing trust.
+ *
+ * @deprecated use {@link #grantTrust(CharSequence, long, int)} instead.
*/
+ @Deprecated
public final void grantTrust(
final CharSequence message, final long durationMs, final boolean initiatedByUser) {
+ grantTrust(message, durationMs, initiatedByUser ? FLAG_GRANT_TRUST_INITIATED_BY_USER : 0);
+ }
+
+ /**
+ * Call to grant trust on the device.
+ *
+ * @param message describes why the device is trusted, e.g. "Trusted by location".
+ * @param durationMs amount of time in milliseconds to keep the device in a trusted state.
+ * Trust for this agent will automatically be revoked when the timeout expires unless
+ * extended by a subsequent call to this function. The timeout is measured from the
+ * invocation of this function as dictated by {@link SystemClock#elapsedRealtime())}.
+ * For security reasons, the value should be no larger than necessary.
+ * The value may be adjusted by the system as necessary to comply with a policy controlled
+ * by the system or {@link DevicePolicyManager} restrictions. See {@link #onTrustTimeout()}
+ * for determining when trust expires.
+ * @param flags TBDocumented
+ * @throws IllegalStateException if the agent is not currently managing trust.
+ */
+ public final void grantTrust(
+ final CharSequence message, final long durationMs, @GrantTrustFlags final int flags) {
synchronized (mLock) {
if (!mManagingTrust) {
throw new IllegalStateException("Cannot grant trust if agent is not managing trust."
@@ -240,7 +296,7 @@ public class TrustAgentService extends Service {
}
if (mCallback != null) {
try {
- mCallback.grantTrust(message.toString(), durationMs, initiatedByUser);
+ mCallback.grantTrust(message.toString(), durationMs, flags);
} catch (RemoteException e) {
onError("calling enableTrust()");
}
@@ -250,7 +306,7 @@ public class TrustAgentService extends Service {
mPendingGrantTrustTask = new Runnable() {
@Override
public void run() {
- grantTrust(message, durationMs, initiatedByUser);
+ grantTrust(message, durationMs, flags);
}
};
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 1674950..016541f 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -17,6 +17,7 @@
package android.service.wallpaper;
import android.content.res.TypedArray;
+import android.graphics.Canvas;
import android.os.SystemProperties;
import android.view.WindowInsets;
@@ -185,6 +186,7 @@ public abstract class WallpaperService extends Service {
DisplayManager mDisplayManager;
Display mDisplay;
+ private int mDisplayState;
final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() {
{
@@ -228,7 +230,19 @@ public abstract class WallpaperService extends Service {
throw new UnsupportedOperationException(
"Wallpapers do not support keep screen on");
}
-
+
+ @Override
+ public Canvas lockCanvas() {
+ if (mDisplayState == Display.STATE_DOZE
+ || mDisplayState == Display.STATE_DOZE_SUSPEND) {
+ try {
+ mSession.pokeDrawLock(mWindow);
+ } catch (RemoteException e) {
+ // System server died, can be ignored.
+ }
+ }
+ return super.lockCanvas();
+ }
};
final class WallpaperInputEventReceiver extends InputEventReceiver {
@@ -831,9 +845,12 @@ public abstract class WallpaperService extends Service {
mWindow.setSession(mSession);
+ mLayout.packageName = getPackageName();
+
mDisplayManager = (DisplayManager)getSystemService(Context.DISPLAY_SERVICE);
mDisplayManager.registerDisplayListener(mDisplayListener, mCaller.getHandler());
mDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
+ mDisplayState = mDisplay.getState();
if (DEBUG) Log.v(TAG, "onCreate(): " + this);
onCreate(mSurfaceHolder);
@@ -873,8 +890,8 @@ public abstract class WallpaperService extends Service {
void reportVisibility() {
if (!mDestroyed) {
- boolean visible = mVisible
- & mDisplay != null && mDisplay.getState() != Display.STATE_OFF;
+ mDisplayState = mDisplay == null ? Display.STATE_UNKNOWN : mDisplay.getState();
+ boolean visible = mVisible && mDisplayState != Display.STATE_OFF;
if (mReportedVisible != visible) {
mReportedVisible = visible;
if (DEBUG) Log.v(TAG, "onVisibilityChanged(" + visible
diff --git a/core/java/android/text/TextDirectionHeuristics.java b/core/java/android/text/TextDirectionHeuristics.java
index 866137c..354c15f 100644
--- a/core/java/android/text/TextDirectionHeuristics.java
+++ b/core/java/android/text/TextDirectionHeuristics.java
@@ -81,29 +81,47 @@ public class TextDirectionHeuristics {
private static final int STATE_FALSE = 1;
private static final int STATE_UNKNOWN = 2;
- private static int isRtlText(int directionality) {
- switch (directionality) {
- case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
- return STATE_FALSE;
- case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
- case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
- return STATE_TRUE;
- default:
- return STATE_UNKNOWN;
- }
- }
-
- private static int isRtlTextOrFormat(int directionality) {
- switch (directionality) {
+ /* Returns STATE_TRUE for strong RTL characters, STATE_FALSE for strong LTR characters, and
+ * STATE_UNKNOWN for everything else.
+ */
+ private static int isRtlCodePoint(int codePoint) {
+ switch (Character.getDirectionality(codePoint)) {
case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
- case Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING:
- case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE:
return STATE_FALSE;
case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
- case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING:
- case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE:
return STATE_TRUE;
+ case Character.DIRECTIONALITY_UNDEFINED:
+ // Unassigned characters still have bidi direction, defined at:
+ // http://www.unicode.org/Public/UCD/latest/ucd/extracted/DerivedBidiClass.txt
+
+ if ((0x0590 <= codePoint && codePoint <= 0x08FF) ||
+ (0xFB1D <= codePoint && codePoint <= 0xFDCF) ||
+ (0xFDF0 <= codePoint && codePoint <= 0xFDFF) ||
+ (0xFE70 <= codePoint && codePoint <= 0xFEFF) ||
+ (0x10800 <= codePoint && codePoint <= 0x10FFF) ||
+ (0x1E800 <= codePoint && codePoint <= 0x1EFFF)) {
+ // Unassigned RTL character
+ return STATE_TRUE;
+ } else if (
+ // Potentially-unassigned Default_Ignorable. Ranges are from unassigned
+ // characters that have Unicode property Other_Default_Ignorable_Code_Point
+ // plus some enlargening to cover bidi isolates and simplify checks.
+ (0x2065 <= codePoint && codePoint <= 0x2069) ||
+ (0xFFF0 <= codePoint && codePoint <= 0xFFF8) ||
+ (0xE0000 <= codePoint && codePoint <= 0xE0FFF) ||
+ // Non-character
+ (0xFDD0 <= codePoint && codePoint <= 0xFDEF) ||
+ ((codePoint & 0xFFFE) == 0xFFFE) ||
+ // Currency symbol
+ (0x20A0 <= codePoint && codePoint <= 0x20CF) ||
+ // Unpaired surrogate
+ (0xD800 <= codePoint && codePoint <= 0xDFFF)) {
+ return STATE_UNKNOWN;
+ } else {
+ // Unassigned LTR character
+ return STATE_FALSE;
+ }
default:
return STATE_UNKNOWN;
}
@@ -181,14 +199,26 @@ public class TextDirectionHeuristics {
/**
* Algorithm that uses the first strong directional character to determine the paragraph
- * direction. This is the standard Unicode Bidirectional algorithm.
+ * direction. This is the standard Unicode Bidirectional Algorithm (steps P2 and P3), with the
+ * exception that if no strong character is found, UNKNOWN is returned.
*/
private static class FirstStrong implements TextDirectionAlgorithm {
@Override
public int checkRtl(CharSequence cs, int start, int count) {
int result = STATE_UNKNOWN;
- for (int i = start, e = start + count; i < e && result == STATE_UNKNOWN; ++i) {
- result = isRtlTextOrFormat(Character.getDirectionality(cs.charAt(i)));
+ int openIsolateCount = 0;
+ for (int cp, i = start, end = start + count;
+ i < end && result == STATE_UNKNOWN;
+ i += Character.charCount(cp)) {
+ cp = Character.codePointAt(cs, i);
+ if (0x2066 <= cp && cp <= 0x2068) { // Opening isolates
+ openIsolateCount += 1;
+ } else if (cp == 0x2069) { // POP DIRECTIONAL ISOLATE (PDI)
+ if (openIsolateCount > 0) openIsolateCount -= 1;
+ } else if (openIsolateCount == 0) {
+ // Only consider the characters outside isolate pairs
+ result = isRtlCodePoint(cp);
+ }
}
return result;
}
@@ -200,9 +230,10 @@ public class TextDirectionHeuristics {
}
/**
- * Algorithm that uses the presence of any strong directional non-format
- * character (e.g. excludes LRE, LRO, RLE, RLO) to determine the
- * direction of text.
+ * Algorithm that uses the presence of any strong directional character of the type indicated
+ * in the constructor parameter to determine the direction of text.
+ *
+ * Characters inside isolate pairs are skipped.
*/
private static class AnyStrong implements TextDirectionAlgorithm {
private final boolean mLookForRtl;
@@ -210,22 +241,31 @@ public class TextDirectionHeuristics {
@Override
public int checkRtl(CharSequence cs, int start, int count) {
boolean haveUnlookedFor = false;
- for (int i = start, e = start + count; i < e; ++i) {
- switch (isRtlText(Character.getDirectionality(cs.charAt(i)))) {
- case STATE_TRUE:
- if (mLookForRtl) {
- return STATE_TRUE;
- }
- haveUnlookedFor = true;
- break;
- case STATE_FALSE:
- if (!mLookForRtl) {
- return STATE_FALSE;
- }
- haveUnlookedFor = true;
- break;
- default:
- break;
+ int openIsolateCount = 0;
+ for (int cp, i = start, end = start + count; i < end; i += Character.charCount(cp)) {
+ cp = Character.codePointAt(cs, i);
+ if (0x2066 <= cp && cp <= 0x2068) { // Opening isolates
+ openIsolateCount += 1;
+ } else if (cp == 0x2069) { // POP DIRECTIONAL ISOLATE (PDI)
+ if (openIsolateCount > 0) openIsolateCount -= 1;
+ } else if (openIsolateCount == 0) {
+ // Only consider the characters outside isolate pairs
+ switch (isRtlCodePoint(cp)) {
+ case STATE_TRUE:
+ if (mLookForRtl) {
+ return STATE_TRUE;
+ }
+ haveUnlookedFor = true;
+ break;
+ case STATE_FALSE:
+ if (!mLookForRtl) {
+ return STATE_FALSE;
+ }
+ haveUnlookedFor = true;
+ break;
+ default:
+ break;
+ }
}
}
if (haveUnlookedFor) {
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index fcc3a40..de509b2 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -240,23 +240,30 @@ public class ArrowKeyMovementMethod extends BaseMovementMethod implements Moveme
boolean handled = Touch.onTouchEvent(widget, buffer, event);
- if (widget.isFocused() && !widget.didTouchFocusSelect()) {
- if (action == MotionEvent.ACTION_DOWN) {
- // Capture the mouse pointer down location to ensure selection starts
- // right under the mouse (and is not influenced by cursor location).
- // The code below needs to run for mouse events.
- // For touch events, the code should run only when selection is active.
- if (isMouse || isTouchSelecting(isMouse, buffer)) {
- int offset = widget.getOffsetForPosition(event.getX(), event.getY());
- buffer.setSpan(LAST_TAP_DOWN, offset, offset, Spannable.SPAN_POINT_POINT);
- // Disallow intercepting of the touch events, so that
- // users can scroll and select at the same time.
- // without this, users would get booted out of select
- // mode once the view detected it needed to scroll.
- widget.getParent().requestDisallowInterceptTouchEvent(true);
+ if (widget.didTouchFocusSelect() && !isMouse) {
+ return handled;
+ }
+ if (action == MotionEvent.ACTION_DOWN) {
+ // Capture the mouse pointer down location to ensure selection starts
+ // right under the mouse (and is not influenced by cursor location).
+ // The code below needs to run for mouse events.
+ // For touch events, the code should run only when selection is active.
+ if (isMouse || isTouchSelecting(isMouse, buffer)) {
+ if (!widget.isFocused()) {
+ if (!widget.requestFocus()) {
+ return handled;
+ }
}
- } else if (action == MotionEvent.ACTION_MOVE) {
-
+ int offset = widget.getOffsetForPosition(event.getX(), event.getY());
+ buffer.setSpan(LAST_TAP_DOWN, offset, offset, Spannable.SPAN_POINT_POINT);
+ // Disallow intercepting of the touch events, so that
+ // users can scroll and select at the same time.
+ // without this, users would get booted out of select
+ // mode once the view detected it needed to scroll.
+ widget.getParent().requestDisallowInterceptTouchEvent(true);
+ }
+ } else if (widget.isFocused()) {
+ if (action == MotionEvent.ACTION_MOVE) {
// Cursor can be active at any location in the text while mouse pointer can start
// selection from a totally different location. Use LAST_TAP_DOWN span to ensure
// text selection will start from mouse pointer location.
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index 07c1ec3..fe7571f 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -97,7 +97,7 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener
// Delete a character.
final int start = Selection.getSelectionEnd(content);
final int end;
- if (isForwardDelete || event.isShiftPressed() || isShiftActive) {
+ if (isForwardDelete) {
end = TextUtils.getOffsetAfter(content, start);
} else {
end = TextUtils.getOffsetBefore(content, start);
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 71863b7..71e2251 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -170,6 +170,15 @@ public final class Display {
public static final int FLAG_PRESENTATION = 1 << 3;
/**
+ * Display flag: Indicates that the contents of the display should not be scaled
+ * to fit the physical screen dimensions. Used for development only to emulate
+ * devices with smaller physicals screens while preserving density.
+ *
+ * @hide
+ */
+ public static final int FLAG_SCALING_DISABLED = 1 << 30;
+
+ /**
* Display type: Unknown display type.
* @hide
*/
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index de46a4a..5a9a1ea 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -22,6 +22,8 @@ import android.os.Looper;
import android.os.MessageQueue;
import android.util.Log;
+import java.lang.ref.WeakReference;
+
/**
* Provides a low-level mechanism for an application to receive display events
* such as vertical sync.
@@ -42,7 +44,7 @@ public abstract class DisplayEventReceiver {
// GC'd while the native peer of the receiver is using them.
private MessageQueue mMessageQueue;
- private static native long nativeInit(DisplayEventReceiver receiver,
+ private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver,
MessageQueue messageQueue);
private static native void nativeDispose(long receiverPtr);
private static native void nativeScheduleVsync(long receiverPtr);
@@ -58,7 +60,7 @@ public abstract class DisplayEventReceiver {
}
mMessageQueue = looper.getQueue();
- mReceiverPtr = nativeInit(this, mMessageQueue);
+ mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue);
mCloseGuard.open("dispose");
}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index ecf45b4..243961c 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -538,6 +538,9 @@ public final class DisplayInfo implements Parcelable {
if ((flags & Display.FLAG_PRESENTATION) != 0) {
result.append(", FLAG_PRESENTATION");
}
+ if ((flags & Display.FLAG_SCALING_DISABLED) != 0) {
+ result.append(", FLAG_SCALING_DISABLED");
+ }
return result.toString();
}
}
diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java
index e9f2353..eedbc70 100644
--- a/core/java/android/view/DisplayListCanvas.java
+++ b/core/java/android/view/DisplayListCanvas.java
@@ -88,10 +88,10 @@ public class DisplayListCanvas extends Canvas {
///////////////////////////////////////////////////////////////////////////
private DisplayListCanvas() {
- super(nCreateDisplayListRenderer());
+ super(nCreateDisplayListCanvas());
}
- private static native long nCreateDisplayListRenderer();
+ private static native long nCreateDisplayListCanvas();
public static void setProperty(String name, String value) {
nSetProperty(name, value);
@@ -283,7 +283,7 @@ public class DisplayListCanvas extends Canvas {
Bitmap bitmap = patch.getBitmap();
throwIfCannotDraw(bitmap);
final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
- nDrawPatch(mNativeCanvasWrapper, bitmap, patch.mNativeChunk,
+ nDrawPatch(mNativeCanvasWrapper, bitmap.getSkBitmap(), patch.mNativeChunk,
dst.left, dst.top, dst.right, dst.bottom, nativePaint);
}
@@ -293,11 +293,11 @@ public class DisplayListCanvas extends Canvas {
Bitmap bitmap = patch.getBitmap();
throwIfCannotDraw(bitmap);
final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
- nDrawPatch(mNativeCanvasWrapper, bitmap, patch.mNativeChunk,
+ nDrawPatch(mNativeCanvasWrapper, bitmap.getSkBitmap(), patch.mNativeChunk,
dst.left, dst.top, dst.right, dst.bottom, nativePaint);
}
- private static native void nDrawPatch(long renderer, Bitmap bitmap, long chunk,
+ private static native void nDrawPatch(long renderer, long bitmap, long chunk,
float left, float top, float right, float bottom, long paint);
public void drawCircle(CanvasProperty<Float> cx, CanvasProperty<Float> cy,
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index d6625c8..5994d4f 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -70,6 +70,7 @@ interface IWindowManager
int getBaseDisplayDensity(int displayId);
void setForcedDisplayDensity(int displayId, int density);
void clearForcedDisplayDensity(int displayId);
+ void setForcedDisplayScalingMode(int displayId, int mode); // 0 = auto, 1 = disable
void setOverscan(int displayId, int left, int top, int right, int bottom);
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 779560c..1ac3f45 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -747,8 +747,22 @@ public class KeyEvent extends InputEvent implements Parcelable {
public static final int KEYCODE_TV_TIMER_PROGRAMMING = 258;
/** Key code constant: Help key. */
public static final int KEYCODE_HELP = 259;
-
- private static final int LAST_KEYCODE = KEYCODE_HELP;
+ /** Key code constant: Navigate to previous key.
+ * Goes backward by one item in an ordered collection of items. */
+ public static final int KEYCODE_NAVIGATE_PREVIOUS = 260;
+ /** Key code constant: Navigate to next key.
+ * Advances to the next item in an ordered collection of items. */
+ public static final int KEYCODE_NAVIGATE_NEXT = 261;
+ /** Key code constant: Navigate in key.
+ * Activates the item that currently has focus or expands to the next level of a navigation
+ * hierarchy. */
+ public static final int KEYCODE_NAVIGATE_IN = 262;
+ /** Key code constant: Navigate out key.
+ * Backs out one level of a navigation hierarchy or collapses the item that currently has
+ * focus. */
+ public static final int KEYCODE_NAVIGATE_OUT = 263;
+
+ private static final int LAST_KEYCODE = KEYCODE_NAVIGATE_OUT;
// NOTE: If you add a new keycode here you must also add it to:
// isSystem()
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 25c5127..87d5d9a 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -360,7 +360,7 @@ public class ThreadedRenderer extends HardwareRenderer {
@Override
boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
return nCopyLayerInto(mNativeProxy,
- layer.getDeferredLayerUpdater(), bitmap);
+ layer.getDeferredLayerUpdater(), bitmap.getSkBitmap());
}
@Override
@@ -460,6 +460,8 @@ public class ThreadedRenderer extends HardwareRenderer {
if (buffer != null) {
long[] map = atlas.getMap();
if (map != null) {
+ // TODO Remove after fixing b/15425820
+ validateMap(context, map);
nSetAtlas(renderProxy, buffer, map);
}
// If IAssetAtlas is not the same class as the IBinder
@@ -474,6 +476,32 @@ public class ThreadedRenderer extends HardwareRenderer {
Log.w(LOG_TAG, "Could not acquire atlas", e);
}
}
+
+ private static void validateMap(Context context, long[] map) {
+ Log.d("Atlas", "Validating map...");
+ HashSet<Long> preloadedPointers = new HashSet<Long>();
+
+ // We only care about drawables that hold bitmaps
+ final Resources resources = context.getResources();
+ final LongSparseArray<Drawable.ConstantState> drawables = resources.getPreloadedDrawables();
+
+ final int count = drawables.size();
+ ArrayList<Bitmap> tmpList = new ArrayList<Bitmap>();
+ for (int i = 0; i < count; i++) {
+ drawables.valueAt(i).addAtlasableBitmaps(tmpList);
+ for (int j = 0; j < tmpList.size(); j++) {
+ preloadedPointers.add(tmpList.get(j).getSkBitmap());
+ }
+ tmpList.clear();
+ }
+
+ for (int i = 0; i < map.length; i += 4) {
+ if (!preloadedPointers.contains(map[i])) {
+ Log.w("Atlas", String.format("Pointer 0x%X, not in getPreloadedDrawables?", map[i]));
+ map[i] = 0;
+ }
+ }
+ }
}
static native void setupShadersDiskCache(String cacheFile);
@@ -503,7 +531,7 @@ public class ThreadedRenderer extends HardwareRenderer {
private static native long nCreateTextureLayer(long nativeProxy);
private static native void nBuildLayer(long nativeProxy, long node);
- private static native boolean nCopyLayerInto(long nativeProxy, long layer, Bitmap bitmap);
+ private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
private static native void nPushLayerUpdate(long nativeProxy, long layer);
private static native void nCancelLayerUpdate(long nativeProxy, long layer);
private static native void nDetachSurfaceTexture(long nativeProxy, long layer);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 25fa349..9741239 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -15101,6 +15101,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
return (mClipBounds != null) ? new Rect(mClipBounds) : null;
}
+
+ /**
+ * Populates an output rectangle with the clip bounds of the view,
+ * returning {@code true} if successful or {@code false} if the view's
+ * clip bounds are {@code null}.
+ *
+ * @param outRect rectangle in which to place the clip bounds of the view
+ * @return {@code true} if successful or {@code false} if the view's
+ * clip bounds are {@code null}
+ */
+ public boolean getClipBounds(Rect outRect) {
+ if (mClipBounds != null) {
+ outRect.set(mClipBounds);
+ return true;
+ }
+ return false;
+ }
+
/**
* Utility function, called by draw(canvas, parent, drawingTime) to handle the less common
* case of an active Animation being run on the view.
@@ -15283,9 +15301,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
RenderNode renderNode = null;
Bitmap cache = null;
- int layerType = getLayerType();
+ int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local
if (layerType == LAYER_TYPE_SOFTWARE
|| (!drawingWithRenderNode && layerType != LAYER_TYPE_NONE)) {
+ // If not drawing with RenderNode, treat HW layers as SW
layerType = LAYER_TYPE_SOFTWARE;
buildDrawingCache(true);
cache = getDrawingCache(true);
@@ -15312,10 +15331,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
sy = mScrollY;
}
- final boolean hasNoCache = cache == null || drawingWithRenderNode;
- final boolean offsetForScroll = cache == null
- && !drawingWithRenderNode
- && layerType != LAYER_TYPE_HARDWARE;
+ final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode;
+ final boolean offsetForScroll = cache == null && !drawingWithRenderNode;
int restoreTo = -1;
if (!drawingWithRenderNode || transformToApply != null) {
@@ -15388,17 +15405,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA;
}
parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION;
- if (hasNoCache) {
+ if (!drawingWithDrawingCache) {
final int multipliedAlpha = (int) (255 * alpha);
if (!onSetAlpha(multipliedAlpha)) {
- int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
- if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0
- || layerType != LAYER_TYPE_NONE) {
- layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
- }
if (drawingWithRenderNode) {
renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha());
} else if (layerType == LAYER_TYPE_NONE) {
+ int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
+ if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0) {
+ layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
+ }
canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(),
multipliedAlpha, layerFlags);
}
@@ -15433,33 +15449,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
}
- if (hasNoCache) {
- boolean layerRendered = false;
- if (layerType == LAYER_TYPE_HARDWARE && !drawingWithRenderNode) {
- final HardwareLayer layer = getHardwareLayer();
- if (layer != null && layer.isValid()) {
- int restoreAlpha = mLayerPaint.getAlpha();
- mLayerPaint.setAlpha((int) (alpha * 255));
- ((DisplayListCanvas) canvas).drawHardwareLayer(layer, 0, 0, mLayerPaint);
- mLayerPaint.setAlpha(restoreAlpha);
- layerRendered = true;
- } else {
- canvas.saveLayer(sx, sy, sx + getWidth(), sy + getHeight(), mLayerPaint);
- }
- }
-
- if (!layerRendered) {
- if (!drawingWithRenderNode) {
- // Fast path for layouts with no backgrounds
- if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
- mPrivateFlags &= ~PFLAG_DIRTY_MASK;
- dispatchDraw(canvas);
- } else {
- draw(canvas);
- }
- } else {
+ if (!drawingWithDrawingCache) {
+ if (drawingWithRenderNode) {
+ mPrivateFlags &= ~PFLAG_DIRTY_MASK;
+ ((DisplayListCanvas) canvas).drawRenderNode(renderNode, parentFlags);
+ } else {
+ // Fast path for layouts with no backgrounds
+ if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
- ((DisplayListCanvas) canvas).drawRenderNode(renderNode, parentFlags);
+ dispatchDraw(canvas);
+ } else {
+ draw(canvas);
}
}
} else if (cache != null) {
@@ -18173,7 +18173,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
// flag not set, setMeasuredDimension() was not invoked, we raise
// an exception to warn the developer
if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) {
- throw new IllegalStateException("onMeasure() did not set the"
+ throw new IllegalStateException("View with id " + getId() + ": "
+ + getClass().getName() + "#onMeasure() did not set the"
+ " measured dimension by calling"
+ " setMeasuredDimension()");
}
@@ -20431,11 +20432,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
static int adjust(int measureSpec, int delta) {
final int mode = getMode(measureSpec);
+ int size = getSize(measureSpec);
if (mode == UNSPECIFIED) {
// No need to adjust size for UNSPECIFIED mode.
- return makeMeasureSpec(0, UNSPECIFIED);
+ return makeMeasureSpec(size, UNSPECIFIED);
}
- int size = getSize(measureSpec) + delta;
+ size += delta;
if (size < 0) {
Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size +
") spec: " + toString(measureSpec) + " delta: " + delta);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 98b895d..8f2be99 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -494,6 +494,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
private int mNestedScrollAxes;
+ // Used to manage the list of transient views, added by addTransientView()
+ private List<Integer> mTransientIndices = null;
+ private List<View> mTransientViews = null;
+
+
/**
* Empty ActionMode used as a sentinel in recursive entries to startActionModeForChild.
*
@@ -2822,6 +2827,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
child.dispatchAttachedToWindow(info,
visibility | (child.mViewFlags & VISIBILITY_MASK));
}
+ final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
+ for (int i = 0; i < transientCount; ++i) {
+ View view = mTransientViews.get(i);
+ view.dispatchAttachedToWindow(info, visibility | (view.mViewFlags & VISIBILITY_MASK));
+ }
}
@Override
@@ -2991,6 +3001,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
children[i].dispatchDetachedFromWindow();
}
clearDisappearingChildren();
+ final int transientCount = mTransientViews == null ? 0 : mTransientIndices.size();
+ for (int i = 0; i < transientCount; ++i) {
+ View view = mTransientViews.get(i);
+ view.dispatchDetachedFromWindow();
+ }
super.dispatchDetachedFromWindow();
}
@@ -3291,6 +3306,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final long drawingTime = getDrawingTime();
if (usingRenderNodeProperties) canvas.insertReorderBarrier();
+ final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
+ int transientIndex = transientCount != 0 ? 0 : -1;
// Only use the preordered list if not HW accelerated, since the HW pipeline will do the
// draw reordering internally
final ArrayList<View> preorderedList = usingRenderNodeProperties
@@ -3298,6 +3315,17 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final boolean customOrder = preorderedList == null
&& isChildrenDrawingOrderEnabled();
for (int i = 0; i < childrenCount; i++) {
+ while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) {
+ final View transientChild = mTransientViews.get(transientIndex);
+ if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
+ transientChild.getAnimation() != null) {
+ more |= drawChild(canvas, transientChild, drawingTime);
+ }
+ transientIndex++;
+ if (transientIndex >= transientCount) {
+ transientIndex = -1;
+ }
+ }
int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
final View child = (preorderedList == null)
? children[childIndex] : preorderedList.get(childIndex);
@@ -3305,6 +3333,18 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
more |= drawChild(canvas, child, drawingTime);
}
}
+ while (transientIndex >= 0) {
+ // there may be additional transient views after the normal views
+ final View transientChild = mTransientViews.get(transientIndex);
+ if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
+ transientChild.getAnimation() != null) {
+ more |= drawChild(canvas, transientChild, drawingTime);
+ }
+ transientIndex++;
+ if (transientIndex >= transientCount) {
+ break;
+ }
+ }
if (preorderedList != null) preorderedList.clear();
// Draw any disappearing views that have animations
@@ -3785,6 +3825,145 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
/**
+ * This method adds a view to this container at the specified index purely for the
+ * purposes of allowing that view to draw even though it is not a normal child of
+ * the container. That is, the view does not participate in layout, focus, accessibility,
+ * input, or other normal view operations; it is purely an item to be drawn during the normal
+ * rendering operation of this container. The index that it is added at is the order
+ * in which it will be drawn, with respect to the other views in the container.
+ * For example, a transient view added at index 0 will be drawn before all other views
+ * in the container because it will be drawn first (including before any real view
+ * at index 0). There can be more than one transient view at any particular index;
+ * these views will be drawn in the order in which they were added to the list of
+ * transient views. The index of transient views can also be greater than the number
+ * of normal views in the container; that just means that they will be drawn after all
+ * other views are drawn.
+ *
+ * <p>Note that since transient views do not participate in layout, they must be sized
+ * manually or, more typically, they should just use the size that they had before they
+ * were removed from their container.</p>
+ *
+ * <p>Transient views are useful for handling animations of views that have been removed
+ * from the container, but which should be animated out after the removal. Adding these
+ * views as transient views allows them to participate in drawing without side-effecting
+ * the layout of the container.</p>
+ *
+ * <p>Transient views must always be explicitly {@link #removeTransientView(View) removed}
+ * from the container when they are no longer needed. For example, a transient view
+ * which is added in order to fade it out in its old location should be removed
+ * once the animation is complete.</p>
+ *
+ * @param view The view to be added
+ * @param index The index at which this view should be drawn, must be >= 0.
+ * This value is relative to the {@link #getChildAt(int) index} values in the normal
+ * child list of this container, where any transient view at a particular index will
+ * be drawn before any normal child at that same index.
+ *
+ * @hide
+ */
+ public void addTransientView(View view, int index) {
+ if (index < 0) {
+ return;
+ }
+ if (mTransientIndices == null) {
+ mTransientIndices = new ArrayList<Integer>();
+ mTransientViews = new ArrayList<View>();
+ }
+ final int oldSize = mTransientIndices.size();
+ if (oldSize > 0) {
+ int insertionIndex;
+ for (insertionIndex = 0; insertionIndex < oldSize; ++insertionIndex) {
+ if (index < mTransientIndices.get(insertionIndex)) {
+ break;
+ }
+ }
+ mTransientIndices.add(insertionIndex, index);
+ mTransientViews.add(insertionIndex, view);
+ } else {
+ mTransientIndices.add(index);
+ mTransientViews.add(view);
+ }
+ view.mParent = this;
+ view.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
+ invalidate(true);
+ }
+
+ /**
+ * Removes a view from the list of transient views in this container. If there is no
+ * such transient view, this method does nothing.
+ *
+ * @param view The transient view to be removed
+ *
+ * @hide
+ */
+ public void removeTransientView(View view) {
+ if (mTransientViews == null) {
+ return;
+ }
+ final int size = mTransientViews.size();
+ for (int i = 0; i < size; ++i) {
+ if (view == mTransientViews.get(i)) {
+ mTransientViews.remove(i);
+ mTransientIndices.remove(i);
+ view.mParent = null;
+ view.dispatchDetachedFromWindow();
+ invalidate(true);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Returns the number of transient views in this container. Specific transient
+ * views and the index at which they were added can be retrieved via
+ * {@link #getTransientView(int)} and {@link #getTransientViewIndex(int)}.
+ *
+ * @see #addTransientView(View, int)
+ * @return The number of transient views in this container
+ *
+ * @hide
+ */
+ public int getTransientViewCount() {
+ return mTransientIndices == null ? 0 : mTransientIndices.size();
+ }
+
+ /**
+ * Given a valid position within the list of transient views, returns the index of
+ * the transient view at that position.
+ *
+ * @param position The position of the index being queried. Must be at least 0
+ * and less than the value returned by {@link #getTransientViewCount()}.
+ * @return The index of the transient view stored in the given position if the
+ * position is valid, otherwise -1
+ *
+ * @hide
+ */
+ public int getTransientViewIndex(int position) {
+ if (position < 0 || mTransientIndices == null || position >= mTransientIndices.size()) {
+ return -1;
+ }
+ return mTransientIndices.get(position);
+ }
+
+ /**
+ * Given a valid position within the list of transient views, returns the
+ * transient view at that position.
+ *
+ * @param position The position of the view being queried. Must be at least 0
+ * and less than the value returned by {@link #getTransientViewCount()}.
+ * @return The transient view stored in the given position if the
+ * position is valid, otherwise null
+ *
+ * @hide
+ */
+ public View getTransientView(int position) {
+ if (mTransientViews == null || position >= mTransientViews.size()) {
+ return null;
+ }
+ return mTransientViews.get(position);
+ }
+
+ /**
* <p>Adds a child view. If no layout parameters are already set on the child, the
* default parameters for this ViewGroup are set on the child.</p>
*
@@ -4096,6 +4275,16 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if (child.getVisibility() != View.GONE) {
notifySubtreeAccessibilityStateChangedIfNeeded();
}
+
+ if (mTransientIndices != null) {
+ final int transientCount = mTransientIndices.size();
+ for (int i = 0; i < transientCount; ++i) {
+ final int oldIndex = mTransientIndices.get(i);
+ if (index <= oldIndex) {
+ mTransientIndices.set(i, oldIndex + 1);
+ }
+ }
+ }
}
private void addInArray(View child, int index) {
@@ -4340,6 +4529,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if (view.getVisibility() != View.GONE) {
notifySubtreeAccessibilityStateChangedIfNeeded();
}
+
+ int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
+ for (int i = 0; i < transientCount; ++i) {
+ final int oldIndex = mTransientIndices.get(i);
+ if (index < oldIndex) {
+ mTransientIndices.set(i, oldIndex - 1);
+ }
+ }
}
/**
@@ -6353,6 +6550,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
public void onStopNestedScroll(View child) {
// Stop any recursive nested scrolling.
stopNestedScroll();
+ mNestedScrollAxes = 0;
}
/**
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 4d8dce1..3340c73 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -76,6 +76,11 @@ public final class WebViewFactory {
private static boolean sAddressSpaceReserved = false;
private static PackageInfo sPackageInfo;
+ private static class MissingWebViewPackageException extends AndroidRuntimeException {
+ public MissingWebViewPackageException(String message) { super(message); }
+ public MissingWebViewPackageException(Exception e) { super(e); }
+ }
+
/** @hide */
public static String[] getWebViewPackageNames() {
return AppGlobals.getInitialApplication().getResources().getStringArray(
@@ -110,9 +115,10 @@ public final class WebViewFactory {
} catch (PackageManager.NameNotFoundException e) {
}
}
- throw new AndroidRuntimeException("Could not find a loadable WebView package");
+ throw new MissingWebViewPackageException("Could not find a loadable WebView package");
}
+ // throws MissingWebViewPackageException
private static ApplicationInfo getWebViewApplicationInfo() {
if (sPackageInfo == null)
return findPreferredWebViewPackage().applicationInfo;
@@ -144,25 +150,7 @@ public final class WebViewFactory {
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()");
try {
- // First fetch the package info so we can log the webview package version.
- sPackageInfo = findPreferredWebViewPackage();
- Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " +
- sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")");
-
- Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
- loadNativeLibrary();
- Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
-
- Class<WebViewFactoryProvider> providerClass;
- Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getFactoryClass()");
- try {
- providerClass = getFactoryClass();
- } catch (ClassNotFoundException e) {
- Log.e(LOGTAG, "error loading provider", e);
- throw new AndroidRuntimeException(e);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
- }
+ Class<WebViewFactoryProvider> providerClass = getProviderClass();
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "providerClass.newInstance()");
@@ -184,7 +172,44 @@ public final class WebViewFactory {
}
}
- private static Class<WebViewFactoryProvider> getFactoryClass() throws ClassNotFoundException {
+ private static Class<WebViewFactoryProvider> getProviderClass() {
+ try {
+ // First fetch the package info so we can log the webview package version.
+ sPackageInfo = findPreferredWebViewPackage();
+ Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " +
+ sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")");
+
+ Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
+ loadNativeLibrary();
+ Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+
+ Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
+ try {
+ return getChromiumProviderClass();
+ } catch (ClassNotFoundException e) {
+ Log.e(LOGTAG, "error loading provider", e);
+ throw new AndroidRuntimeException(e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+ }
+ } catch (MissingWebViewPackageException e) {
+ // If the package doesn't exist, then try loading the null WebView instead.
+ // If that succeeds, then this is a device without WebView support; if it fails then
+ // swallow the failure, complain that the real WebView is missing and rethrow the
+ // original exception.
+ try {
+ return (Class<WebViewFactoryProvider>) Class.forName(NULL_WEBVIEW_FACTORY);
+ } catch (ClassNotFoundException e2) {
+ // Ignore.
+ }
+ Log.e(LOGTAG, "Chromium WebView package does not exist", e);
+ throw new AndroidRuntimeException(e);
+ }
+ }
+
+ // throws MissingWebViewPackageException
+ private static Class<WebViewFactoryProvider> getChromiumProviderClass()
+ throws ClassNotFoundException {
Application initialApplication = AppGlobals.getInitialApplication();
try {
// Construct a package context to load the Java code into the current app.
@@ -202,17 +227,7 @@ public final class WebViewFactory {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
} catch (PackageManager.NameNotFoundException e) {
- // If the package doesn't exist, then try loading the null WebView instead.
- // If that succeeds, then this is a device without WebView support; if it fails then
- // swallow the failure, complain that the real WebView is missing and rethrow the
- // original exception.
- try {
- return (Class<WebViewFactoryProvider>) Class.forName(NULL_WEBVIEW_FACTORY);
- } catch (ClassNotFoundException e2) {
- // Ignore.
- }
- Log.e(LOGTAG, "Chromium WebView package does not exist", e);
- throw new AndroidRuntimeException(e);
+ throw new MissingWebViewPackageException(e);
}
}
@@ -315,8 +330,8 @@ public final class WebViewFactory {
prepareWebViewInSystemServer(nativeLibs);
}
- private static String[] getWebViewNativeLibraryPaths()
- throws PackageManager.NameNotFoundException {
+ // throws MissingWebViewPackageException
+ private static String[] getWebViewNativeLibraryPaths() {
ApplicationInfo ai = getWebViewApplicationInfo();
final String NATIVE_LIB_FILE_NAME = getWebViewLibrary(ai);
@@ -443,7 +458,7 @@ public final class WebViewFactory {
} else if (DEBUG) {
Log.v(LOGTAG, "loaded with relro file");
}
- } catch (PackageManager.NameNotFoundException e) {
+ } catch (MissingWebViewPackageException e) {
Log.e(LOGTAG, "Failed to list WebView package libraries for loadNativeLibrary", e);
}
}
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index d6f9f78..ff74c60 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -703,9 +703,9 @@ public abstract class AbsSeekBar extends ProgressBar {
// fallthrough
case KeyEvent.KEYCODE_DPAD_RIGHT:
increment = isLayoutRtl() ? -increment : increment;
- int progress = getProgress() + increment;
- if (progress > 0 && progress < getMax()) {
- setProgress(progress, true);
+
+ // Let progress bar handle clamping values.
+ if (setProgress(getProgress() + increment, true)) {
onKeyChange();
return true;
}
@@ -729,10 +729,10 @@ public abstract class AbsSeekBar extends ProgressBar {
if (isEnabled()) {
final int progress = getProgress();
if (progress > 0) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
}
if (progress < getMax()) {
- info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
}
}
}
@@ -743,29 +743,26 @@ public abstract class AbsSeekBar extends ProgressBar {
if (super.performAccessibilityActionInternal(action, arguments)) {
return true;
}
+
if (!isEnabled()) {
return false;
}
- final int progress = getProgress();
- final int increment = Math.max(1, Math.round((float) getMax() / 5));
- switch (action) {
- case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
- if (progress <= 0) {
- return false;
- }
- setProgress(progress - increment, true);
- onKeyChange();
- return true;
+
+ if (action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD
+ || action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) {
+ int increment = Math.max(1, Math.round((float) getMax() / 5));
+ if (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) {
+ increment = -increment;
}
- case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
- if (progress >= getMax()) {
- return false;
- }
- setProgress(progress + increment, true);
+
+ // Let progress bar handle clamping values.
+ if (setProgress(getProgress() + increment, true)) {
onKeyChange();
return true;
}
+ return false;
}
+
return false;
}
diff --git a/core/java/android/widget/CalendarViewMaterialDelegate.java b/core/java/android/widget/CalendarViewMaterialDelegate.java
index 7bce756..0ed75d5 100644
--- a/core/java/android/widget/CalendarViewMaterialDelegate.java
+++ b/core/java/android/widget/CalendarViewMaterialDelegate.java
@@ -19,6 +19,7 @@ package android.widget;
import android.annotation.StyleRes;
import android.content.Context;
import android.util.AttributeSet;
+import android.widget.DayPickerView.OnDaySelectedListener;
import java.util.Calendar;
@@ -109,8 +110,7 @@ class CalendarViewMaterialDelegate extends CalendarView.AbstractCalendarViewDele
mOnDateChangeListener = listener;
}
- private final DayPickerView.OnDaySelectedListener mOnDaySelectedListener =
- new DayPickerView.OnDaySelectedListener() {
+ private final OnDaySelectedListener mOnDaySelectedListener = new OnDaySelectedListener() {
@Override
public void onDaySelected(DayPickerView view, Calendar day) {
if (mOnDateChangeListener != null) {
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index 06a5bd2..d38a225 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -34,8 +34,6 @@ import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
import android.widget.DayPickerView.OnDaySelectedListener;
import android.widget.YearPickerView.OnYearSelectedListener;
@@ -549,7 +547,7 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate {
final int listPosition = ss.getListPosition();
if (listPosition != -1) {
if (currentView == VIEW_MONTH_DAY) {
- mDayPickerView.setCurrentItem(listPosition);
+ mDayPickerView.setPosition(listPosition);
} else if (currentView == VIEW_YEAR) {
final int listPositionOffset = ss.getListPositionOffset();
mYearPickerView.setSelectionFromTop(listPosition, listPositionOffset);
diff --git a/core/java/android/widget/DayPickerAdapter.java b/core/java/android/widget/DayPickerPagerAdapter.java
index 9a4b6f5..478fa00 100644
--- a/core/java/android/widget/DayPickerAdapter.java
+++ b/core/java/android/widget/DayPickerPagerAdapter.java
@@ -36,7 +36,7 @@ import java.util.Calendar;
/**
* An adapter for a list of {@link android.widget.SimpleMonthView} items.
*/
-class DayPickerAdapter extends PagerAdapter {
+class DayPickerPagerAdapter extends PagerAdapter {
private static final int MONTHS_IN_YEAR = 12;
private final Calendar mMinDate = Calendar.getInstance();
@@ -63,7 +63,7 @@ class DayPickerAdapter extends PagerAdapter {
private int mCount;
private int mFirstDayOfWeek;
- public DayPickerAdapter(@NonNull Context context, @LayoutRes int layoutResId,
+ public DayPickerPagerAdapter(@NonNull Context context, @LayoutRes int layoutResId,
@IdRes int calendarViewId) {
mInflater = LayoutInflater.from(context);
mLayoutResId = layoutResId;
@@ -200,7 +200,8 @@ class DayPickerAdapter extends PagerAdapter {
final int yearOffset = (day.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR));
final int monthOffset = (day.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH));
- return yearOffset * MONTHS_IN_YEAR + monthOffset;
+ final int position = yearOffset * MONTHS_IN_YEAR + monthOffset;
+ return position;
}
@Override
@@ -253,8 +254,6 @@ class DayPickerAdapter extends PagerAdapter {
v.setMonthParams(selectedDay, month, year, mFirstDayOfWeek,
enabledDayRangeStart, enabledDayRangeEnd);
- v.setPrevEnabled(position > 0);
- v.setNextEnabled(position < mCount - 1);
final ViewHolder holder = new ViewHolder(position, itemView, v);
mItems.put(position, holder);
@@ -298,17 +297,10 @@ class DayPickerAdapter extends PagerAdapter {
setSelectedDay(day);
if (mOnDaySelectedListener != null) {
- mOnDaySelectedListener.onDaySelected(DayPickerAdapter.this, day);
+ mOnDaySelectedListener.onDaySelected(DayPickerPagerAdapter.this, day);
}
}
}
-
- @Override
- public void onNavigationClick(SimpleMonthView view, int direction, boolean animate) {
- if (mOnDaySelectedListener != null) {
- mOnDaySelectedListener.onNavigationClick(DayPickerAdapter.this, direction, animate);
- }
- }
};
private static class ViewHolder {
@@ -324,7 +316,6 @@ class DayPickerAdapter extends PagerAdapter {
}
public interface OnDaySelectedListener {
- public void onDaySelected(DayPickerAdapter view, Calendar day);
- public void onNavigationClick(DayPickerAdapter view, int direction, boolean animate);
+ public void onDaySelected(DayPickerPagerAdapter view, Calendar day);
}
}
diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java
index 0e0b2d3..c6b4d7e 100644
--- a/core/java/android/widget/DayPickerView.java
+++ b/core/java/android/widget/DayPickerView.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -16,37 +16,44 @@
package android.widget;
-import com.android.internal.widget.ViewPager;
import com.android.internal.R;
+import com.android.internal.widget.ViewPager;
+import com.android.internal.widget.ViewPager.OnPageChangeListener;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.MathUtils;
+import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityManager;
-import java.util.ArrayList;
import java.util.Calendar;
import java.util.Locale;
import libcore.icu.LocaleData;
-/**
- * This displays a list of months in a calendar format with selectable days.
- */
-class DayPickerView extends ViewPager {
+class DayPickerView extends ViewGroup {
+ private static final int DEFAULT_LAYOUT = R.layout.day_picker_content_material;
private static final int DEFAULT_START_YEAR = 1900;
private static final int DEFAULT_END_YEAR = 2100;
+ private static final int[] ATTRS_TEXT_COLOR = new int[] { R.attr.textColor };
+
private final Calendar mSelectedDay = Calendar.getInstance();
private final Calendar mMinDate = Calendar.getInstance();
private final Calendar mMaxDate = Calendar.getInstance();
- private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1);
+ private final AccessibilityManager mAccessibilityManager;
+
+ private final ViewPager mViewPager;
+ private final ImageButton mPrevButton;
+ private final ImageButton mNextButton;
- private final DayPickerAdapter mAdapter;
+ private final DayPickerPagerAdapter mAdapter;
/** Temporary calendar used for date calculations. */
private Calendar mTempCalendar;
@@ -57,17 +64,21 @@ class DayPickerView extends ViewPager {
this(context, null);
}
- public DayPickerView(Context context, AttributeSet attrs) {
+ public DayPickerView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, R.attr.calendarViewStyle);
}
- public DayPickerView(Context context, AttributeSet attrs, int defStyleAttr) {
+ public DayPickerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
- public DayPickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ public DayPickerView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ mAccessibilityManager = (AccessibilityManager) context.getSystemService(
+ Context.ACCESSIBILITY_SERVICE);
+
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.CalendarView, defStyleAttr, defStyleRes);
@@ -93,14 +104,44 @@ class DayPickerView extends ViewPager {
a.recycle();
// Set up adapter.
- mAdapter = new DayPickerAdapter(context,
+ mAdapter = new DayPickerPagerAdapter(context,
R.layout.date_picker_month_item_material, R.id.month_view);
mAdapter.setMonthTextAppearance(monthTextAppearanceResId);
mAdapter.setDayOfWeekTextAppearance(dayOfWeekTextAppearanceResId);
mAdapter.setDayTextAppearance(dayTextAppearanceResId);
mAdapter.setDaySelectorColor(daySelectorColor);
- setAdapter(mAdapter);
+ final LayoutInflater inflater = LayoutInflater.from(context);
+ final ViewGroup content = (ViewGroup) inflater.inflate(DEFAULT_LAYOUT, this, false);
+
+ // Transfer all children from content to here.
+ while (content.getChildCount() > 0) {
+ final View child = content.getChildAt(0);
+ content.removeViewAt(0);
+ addView(child);
+ }
+
+ mPrevButton = (ImageButton) findViewById(R.id.prev);
+ mPrevButton.setOnClickListener(mOnClickListener);
+
+ mNextButton = (ImageButton) findViewById(R.id.next);
+ mNextButton.setOnClickListener(mOnClickListener);
+
+ mViewPager = (ViewPager) findViewById(R.id.day_picker_view_pager);
+ mViewPager.setAdapter(mAdapter);
+ mViewPager.setOnPageChangeListener(mOnPageChangedListener);
+
+ // Proxy the month text color into the previous and next buttons.
+ if (monthTextAppearanceResId != 0) {
+ final TypedArray ta = mContext.obtainStyledAttributes(null,
+ ATTRS_TEXT_COLOR, 0, monthTextAppearanceResId);
+ final ColorStateList monthColor = ta.getColorStateList(0);
+ if (monthColor != null) {
+ mPrevButton.setImageTintList(monthColor);
+ mNextButton.setImageTintList(monthColor);
+ }
+ ta.recycle();
+ }
// Set up min and max dates.
final Calendar tempDate = Calendar.getInstance();
@@ -127,109 +168,68 @@ class DayPickerView extends ViewPager {
setDate(setDateMillis, false);
// Proxy selection callbacks to our own listener.
- mAdapter.setOnDaySelectedListener(new DayPickerAdapter.OnDaySelectedListener() {
+ mAdapter.setOnDaySelectedListener(new DayPickerPagerAdapter.OnDaySelectedListener() {
@Override
- public void onDaySelected(DayPickerAdapter adapter, Calendar day) {
+ public void onDaySelected(DayPickerPagerAdapter adapter, Calendar day) {
if (mOnDaySelectedListener != null) {
mOnDaySelectedListener.onDaySelected(DayPickerView.this, day);
}
}
-
- @Override
- public void onNavigationClick(DayPickerAdapter view, int direction, boolean animate) {
- // ViewPager clamps input values, so we don't need to worry
- // about passing invalid indices.
- final int nextItem = getCurrentItem() + direction;
- setCurrentItem(nextItem, animate);
- }
});
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- populate();
-
- // Everything below is mostly copied from FrameLayout.
- int count = getChildCount();
-
- final boolean measureMatchParentChildren =
- MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||
- MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;
-
- int maxHeight = 0;
- int maxWidth = 0;
- int childState = 0;
-
- for (int i = 0; i < count; i++) {
- final View child = getChildAt(i);
- if (child.getVisibility() != GONE) {
- measureChild(child, widthMeasureSpec, heightMeasureSpec);
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
- maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
- maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
- childState = combineMeasuredStates(childState, child.getMeasuredState());
- if (measureMatchParentChildren) {
- if (lp.width == LayoutParams.MATCH_PARENT ||
- lp.height == LayoutParams.MATCH_PARENT) {
- mMatchParentChildren.add(child);
- }
- }
- }
- }
-
- // Account for padding too
- maxWidth += getPaddingLeft() + getPaddingRight();
- maxHeight += getPaddingTop() + getPaddingBottom();
-
- // Check against our minimum height and width
- maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
- maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
-
- // Check against our foreground's minimum height and width
- final Drawable drawable = getForeground();
- if (drawable != null) {
- maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
- maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
- }
-
- setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
- resolveSizeAndState(maxHeight, heightMeasureSpec,
- childState << MEASURED_HEIGHT_STATE_SHIFT));
-
- count = mMatchParentChildren.size();
- if (count > 1) {
- for (int i = 0; i < count; i++) {
- final View child = mMatchParentChildren.get(i);
-
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
- final int childWidthMeasureSpec;
- final int childHeightMeasureSpec;
-
- if (lp.width == LayoutParams.MATCH_PARENT) {
- childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
- getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
- MeasureSpec.EXACTLY);
- } else {
- childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
- getPaddingLeft() + getPaddingRight(),
- lp.width);
- }
-
- if (lp.height == LayoutParams.MATCH_PARENT) {
- childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
- getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),
- MeasureSpec.EXACTLY);
- } else {
- childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
- getPaddingTop() + getPaddingBottom(),
- lp.height);
- }
+ final ViewPager viewPager = mViewPager;
+ measureChild(viewPager, widthMeasureSpec, heightMeasureSpec);
+
+ final int measuredWidthAndState = viewPager.getMeasuredWidthAndState();
+ final int measuredHeightAndState = viewPager.getMeasuredHeightAndState();
+ setMeasuredDimension(measuredWidthAndState, measuredHeightAndState);
+
+ final int pagerWidth = viewPager.getMeasuredWidth();
+ final int pagerHeight = viewPager.getMeasuredHeight();
+ final int buttonWidthSpec = MeasureSpec.makeMeasureSpec(pagerWidth, MeasureSpec.AT_MOST);
+ final int buttonHeightSpec = MeasureSpec.makeMeasureSpec(pagerHeight, MeasureSpec.AT_MOST);
+ mPrevButton.measure(buttonWidthSpec, buttonHeightSpec);
+ mNextButton.measure(buttonWidthSpec, buttonHeightSpec);
+ }
- child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
- }
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ final ImageButton leftButton = mPrevButton;
+ final ImageButton rightButton = mNextButton;
+
+ final int width = right - left;
+ final int height = bottom - top;
+ mViewPager.layout(0, 0, width, height);
+
+ if (mViewPager.getChildCount() < 1) {
+ leftButton.setVisibility(View.INVISIBLE);
+ rightButton.setVisibility(View.INVISIBLE);
+ return;
}
- mMatchParentChildren.clear();
+ final SimpleMonthView monthView = (SimpleMonthView) mViewPager.getChildAt(0);
+ final int monthHeight = monthView.getMonthHeight();
+ final int cellWidth = monthView.getCellWidth();
+
+ // Vertically center the previous/next buttons within the month
+ // header, horizontally center within the day cell.
+ final int leftDW = leftButton.getMeasuredWidth();
+ final int leftDH = leftButton.getMeasuredHeight();
+ final int leftIconTop = monthView.getPaddingTop() + (monthHeight - leftDH) / 2;
+ final int leftIconLeft = monthView.getPaddingLeft() + (cellWidth - leftDW) / 2;
+ leftButton.layout(leftIconLeft, leftIconTop, leftIconLeft + leftDW, leftIconTop + leftDH);
+ leftButton.setVisibility(View.VISIBLE);
+
+ final int rightDW = rightButton.getMeasuredWidth();
+ final int rightDH = rightButton.getMeasuredHeight();
+ final int rightIconTop = monthView.getPaddingTop() + (monthHeight - rightDH) / 2;
+ final int rightIconRight = width - monthView.getPaddingRight() - (cellWidth - rightDW) / 2;
+ rightButton.layout(rightIconRight - rightDW, rightIconTop,
+ rightIconRight, rightIconTop + rightDH);
+ rightButton.setVisibility(View.VISIBLE);
}
public void setDayOfWeekTextAppearance(int resId) {
@@ -284,8 +284,8 @@ class DayPickerView extends ViewPager {
}
final int position = getPositionFromDay(timeInMillis);
- if (position != getCurrentItem()) {
- setCurrentItem(position, animate);
+ if (position != mViewPager.getCurrentItem()) {
+ mViewPager.setCurrentItem(position, animate);
}
mTempCalendar.setTimeInMillis(timeInMillis);
@@ -365,10 +365,57 @@ class DayPickerView extends ViewPager {
* Gets the position of the view that is most prominently displayed within the list view.
*/
public int getMostVisiblePosition() {
- return getCurrentItem();
+ return mViewPager.getCurrentItem();
}
+ public void setPosition(int position) {
+ mViewPager.setCurrentItem(position, false);
+ }
+
+ private final OnPageChangeListener mOnPageChangedListener = new OnPageChangeListener() {
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ final float alpha = Math.abs(0.5f - positionOffset) * 2.0f;
+ mPrevButton.setAlpha(alpha);
+ mNextButton.setAlpha(alpha);
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {}
+
+ @Override
+ public void onPageSelected(int position) {
+ mPrevButton.setVisibility(
+ position > 0 ? View.VISIBLE : View.INVISIBLE);
+ mNextButton.setVisibility(
+ position < (mAdapter.getCount() - 1) ? View.VISIBLE : View.INVISIBLE);
+ }
+ };
+
+ private final OnClickListener mOnClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ final int direction;
+ if (v == mPrevButton) {
+ direction = -1;
+ } else if (v == mNextButton) {
+ direction = 1;
+ } else {
+ return;
+ }
+
+ // Animation is expensive for accessibility services since it sends
+ // lots of scroll and content change events.
+ final boolean animate = !mAccessibilityManager.isEnabled();
+
+ // ViewPager clamps input values, so we don't need to worry
+ // about passing invalid indices.
+ final int nextItem = mViewPager.getCurrentItem() + direction;
+ mViewPager.setCurrentItem(nextItem, animate);
+ }
+ };
+
public interface OnDaySelectedListener {
- public void onDaySelected(DayPickerView view, Calendar day);
+ void onDaySelected(DayPickerView view, Calendar day);
}
}
diff --git a/core/java/android/widget/DayPickerViewPager.java b/core/java/android/widget/DayPickerViewPager.java
new file mode 100644
index 0000000..bb6e3a4
--- /dev/null
+++ b/core/java/android/widget/DayPickerViewPager.java
@@ -0,0 +1,137 @@
+/*
+ * 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.widget;
+
+import com.android.internal.widget.ViewPager;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+
+import java.util.ArrayList;
+
+/**
+ * This displays a list of months in a calendar format with selectable days.
+ */
+class DayPickerViewPager extends ViewPager {
+ private final ArrayList<View> mMatchParentChildren = new ArrayList<>(1);
+
+ public DayPickerViewPager(Context context) {
+ this(context, null);
+ }
+
+ public DayPickerViewPager(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public DayPickerViewPager(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public DayPickerViewPager(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ populate();
+
+ // Everything below is mostly copied from FrameLayout.
+ int count = getChildCount();
+
+ final boolean measureMatchParentChildren =
+ MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||
+ MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;
+
+ int maxHeight = 0;
+ int maxWidth = 0;
+ int childState = 0;
+
+ for (int i = 0; i < count; i++) {
+ final View child = getChildAt(i);
+ if (child.getVisibility() != GONE) {
+ measureChild(child, widthMeasureSpec, heightMeasureSpec);
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
+ maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
+ childState = combineMeasuredStates(childState, child.getMeasuredState());
+ if (measureMatchParentChildren) {
+ if (lp.width == LayoutParams.MATCH_PARENT ||
+ lp.height == LayoutParams.MATCH_PARENT) {
+ mMatchParentChildren.add(child);
+ }
+ }
+ }
+ }
+
+ // Account for padding too
+ maxWidth += getPaddingLeft() + getPaddingRight();
+ maxHeight += getPaddingTop() + getPaddingBottom();
+
+ // Check against our minimum height and width
+ maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
+ maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
+
+ // Check against our foreground's minimum height and width
+ final Drawable drawable = getForeground();
+ if (drawable != null) {
+ maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
+ maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
+ }
+
+ setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
+ resolveSizeAndState(maxHeight, heightMeasureSpec,
+ childState << MEASURED_HEIGHT_STATE_SHIFT));
+
+ count = mMatchParentChildren.size();
+ if (count > 1) {
+ for (int i = 0; i < count; i++) {
+ final View child = mMatchParentChildren.get(i);
+
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ final int childWidthMeasureSpec;
+ final int childHeightMeasureSpec;
+
+ if (lp.width == LayoutParams.MATCH_PARENT) {
+ childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+ getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
+ MeasureSpec.EXACTLY);
+ } else {
+ childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
+ getPaddingLeft() + getPaddingRight(),
+ lp.width);
+ }
+
+ if (lp.height == LayoutParams.MATCH_PARENT) {
+ childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
+ getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),
+ MeasureSpec.EXACTLY);
+ } else {
+ childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
+ getPaddingTop() + getPaddingBottom(),
+ lp.height);
+ }
+
+ child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ }
+ }
+
+ mMatchParentChildren.clear();
+ }
+}
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index 4b5407a..552b274 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -662,7 +662,8 @@ class FastScroller {
final int adjMaxWidth = maxWidth - marginLeft - marginRight;
final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(adjMaxWidth, MeasureSpec.AT_MOST);
- final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(container.height(),
+ MeasureSpec.UNSPECIFIED);
view.measure(widthMeasureSpec, heightMeasureSpec);
// Align to the left or right.
@@ -701,7 +702,8 @@ class FastScroller {
final int containerWidth = container.width();
final int adjMaxWidth = containerWidth - marginLeft - marginRight;
final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(adjMaxWidth, MeasureSpec.AT_MOST);
- final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(container.height(),
+ MeasureSpec.UNSPECIFIED);
preview.measure(widthMeasureSpec, heightMeasureSpec);
// Align at the vertical center, 10% from the top.
@@ -766,7 +768,8 @@ class FastScroller {
final Rect container = mContainerRect;
final int maxWidth = container.width();
final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST);
- final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(container.height(),
+ MeasureSpec.UNSPECIFIED);
track.measure(widthMeasureSpec, heightMeasureSpec);
final int top;
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index be0ca71..9ecdc9c 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1071,7 +1071,8 @@ public class GridView extends AbsListView {
p.forceAdd = true;
int childHeightSpec = getChildMeasureSpec(
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 0, p.height);
+ MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),
+ MeasureSpec.UNSPECIFIED), 0, p.height);
int childWidthSpec = getChildMeasureSpec(
MeasureSpec.makeMeasureSpec(mColumnWidth, MeasureSpec.EXACTLY), 0, p.width);
child.measure(childWidthSpec, childHeightSpec);
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index da15302..72f51c9 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -1058,8 +1058,11 @@ public class LinearLayout extends ViewGroup {
// use as much space as it wants because we can shrink things
// later (and re-measure).
if (baselineAligned) {
- final int freeSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
- child.measure(freeSpec, freeSpec);
+ final int freeWidthSpec = MeasureSpec.makeMeasureSpec(
+ MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.UNSPECIFIED);
+ final int freeHeightSpec = MeasureSpec.makeMeasureSpec(
+ MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.UNSPECIFIED);
+ child.measure(freeWidthSpec, freeHeightSpec);
} else {
skippedMeasure = true;
}
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index def5929..a79c8e8 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1155,7 +1155,7 @@ public class ListView extends AbsListView {
heightMode == MeasureSpec.UNSPECIFIED)) {
final View child = obtainView(0, mIsScrap);
- measureScrapChild(child, 0, widthMeasureSpec);
+ measureScrapChild(child, 0, widthMeasureSpec, heightSize);
childWidth = child.getMeasuredWidth();
childHeight = child.getMeasuredHeight();
@@ -1188,7 +1188,7 @@ public class ListView extends AbsListView {
mWidthMeasureSpec = widthMeasureSpec;
}
- private void measureScrapChild(View child, int position, int widthMeasureSpec) {
+ private void measureScrapChild(View child, int position, int widthMeasureSpec, int heightHint) {
LayoutParams p = (LayoutParams) child.getLayoutParams();
if (p == null) {
p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
@@ -1204,7 +1204,7 @@ public class ListView extends AbsListView {
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
} else {
- childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ childHeightSpec = MeasureSpec.makeMeasureSpec(heightHint, MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
}
@@ -1271,7 +1271,7 @@ public class ListView extends AbsListView {
for (i = startPosition; i <= endPosition; ++i) {
child = obtainView(i, isScrap);
- measureScrapChild(child, i, widthMeasureSpec);
+ measureScrapChild(child, i, widthMeasureSpec, maxHeight);
if (i > 0) {
// Count the divider for all but one child
@@ -1941,7 +1941,8 @@ public class ListView extends AbsListView {
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
} else {
- childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ childHeightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(),
+ MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
} else {
@@ -2695,7 +2696,8 @@ public class ListView extends AbsListView {
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
} else {
- childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ childHeightSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(),
+ MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index c5b5c84..c3ac278 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -94,7 +94,6 @@ public class PopupWindow {
private final int[] mDrawingLocation = new int[2];
private final int[] mScreenLocation = new int[2];
private final Rect mTempRect = new Rect();
- private final Rect mAnchorBounds = new Rect();
private Context mContext;
private WindowManager mWindowManager;
@@ -159,28 +158,6 @@ public class PopupWindow {
private WeakReference<View> mAnchor;
- private final EpicenterCallback mEpicenterCallback = new EpicenterCallback() {
- @Override
- public Rect onGetEpicenter(Transition transition) {
- final View anchor = mAnchor != null ? mAnchor.get() : null;
- final View decor = mDecorView;
- if (anchor == null || decor == null) {
- return null;
- }
-
- final Rect anchorBounds = mAnchorBounds;
- final int[] anchorLocation = anchor.getLocationOnScreen();
- final int[] popupLocation = mDecorView.getLocationOnScreen();
-
- // Compute the position of the anchor relative to the popup.
- anchorBounds.set(0, 0, anchor.getWidth(), anchor.getHeight());
- anchorBounds.offset(anchorLocation[0] - popupLocation[0],
- anchorLocation[1] - popupLocation[1]);
-
- return anchorBounds;
- }
- };
-
private final OnScrollChangedListener mOnScrollChangedListener = new OnScrollChangedListener() {
@Override
public void onScrollChanged() {
@@ -355,18 +332,10 @@ public class PopupWindow {
public void setEnterTransition(Transition enterTransition) {
mEnterTransition = enterTransition;
-
- if (mEnterTransition != null) {
- mEnterTransition.setEpicenterCallback(mEpicenterCallback);
- }
}
public void setExitTransition(Transition exitTransition) {
mExitTransition = exitTransition;
-
- if (mExitTransition != null) {
- mExitTransition.setEpicenterCallback(mEpicenterCallback);
- }
}
private Transition getTransition(int resId) {
@@ -1281,11 +1250,14 @@ public class PopupWindow {
final PopupDecorView decorView = mDecorView;
decorView.setFitsSystemWindows(mLayoutInsetDecor);
- decorView.requestEnterTransition(mEnterTransition);
setLayoutDirectionFromAnchor();
mWindowManager.addView(decorView, p);
+
+ if (mEnterTransition != null) {
+ decorView.requestEnterTransition(mEnterTransition);
+ }
}
private void setLayoutDirectionFromAnchor() {
@@ -1607,13 +1579,25 @@ public class PopupWindow {
// Ensure any ongoing or pending transitions are canceled.
decorView.cancelTransitions();
- unregisterForScrollChanged();
-
mIsShowing = false;
mIsTransitioningToDismiss = true;
- if (mExitTransition != null && decorView.isLaidOut()) {
- decorView.startExitTransition(mExitTransition, new TransitionListenerAdapter() {
+ final Transition exitTransition = mExitTransition;
+ if (exitTransition != null && decorView.isLaidOut()) {
+ // The decor view is non-interactive during exit transitions.
+ final LayoutParams p = (LayoutParams) decorView.getLayoutParams();
+ p.flags |= LayoutParams.FLAG_NOT_TOUCHABLE;
+ p.flags |= LayoutParams.FLAG_NOT_FOCUSABLE;
+ mWindowManager.updateViewLayout(decorView, p);
+
+ final Rect epicenter = getRelativeAnchorBounds();
+ exitTransition.setEpicenterCallback(new EpicenterCallback() {
+ @Override
+ public Rect onGetEpicenter(Transition transition) {
+ return epicenter;
+ }
+ });
+ decorView.startExitTransition(exitTransition, new TransitionListenerAdapter() {
@Override
public void onTransitionEnd(Transition transition) {
dismissImmediate(decorView, contentHolder, contentView);
@@ -1623,11 +1607,30 @@ public class PopupWindow {
dismissImmediate(decorView, contentHolder, contentView);
}
+ // Clears the anchor view.
+ unregisterForScrollChanged();
+
if (mOnDismissListener != null) {
mOnDismissListener.onDismiss();
}
}
+ private Rect getRelativeAnchorBounds() {
+ final View anchor = mAnchor != null ? mAnchor.get() : null;
+ final View decor = mDecorView;
+ if (anchor == null || decor == null) {
+ return null;
+ }
+
+ final int[] anchorLocation = anchor.getLocationOnScreen();
+ final int[] popupLocation = mDecorView.getLocationOnScreen();
+
+ // Compute the position of the anchor relative to the popup.
+ final Rect bounds = new Rect(0, 0, anchor.getWidth(), anchor.getHeight());
+ bounds.offset(anchorLocation[0] - popupLocation[0], anchorLocation[1] - popupLocation[1]);
+ return bounds;
+ }
+
/**
* Removes the popup from the window manager and tears down the supporting
* view hierarchy, if necessary.
@@ -1996,6 +1999,13 @@ public class PopupWindow {
observer.removeOnGlobalLayoutListener(this);
}
+ final Rect epicenter = getRelativeAnchorBounds();
+ enterTransition.setEpicenterCallback(new EpicenterCallback() {
+ @Override
+ public Rect onGetEpicenter(Transition transition) {
+ return epicenter;
+ }
+ });
startEnterTransition(enterTransition);
}
});
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 24e9cbe..b59ae17 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -43,6 +43,7 @@ import android.graphics.drawable.shapes.Shape;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
+import android.util.MathUtils;
import android.util.Pools.SynchronizedPool;
import android.view.Gravity;
import android.view.RemotableViewMethod;
@@ -1341,23 +1342,22 @@ public class ProgressBar extends View {
}
@android.view.RemotableViewMethod
- synchronized void setProgress(int progress, boolean fromUser) {
+ synchronized boolean setProgress(int progress, boolean fromUser) {
if (mIndeterminate) {
- return;
+ // Not applicable.
+ return false;
}
- if (progress < 0) {
- progress = 0;
- }
+ progress = MathUtils.constrain(progress, 0, mMax);
- if (progress > mMax) {
- progress = mMax;
+ if (progress == mProgress) {
+ // No change from current.
+ return false;
}
- if (progress != mProgress) {
- mProgress = progress;
- refreshProgress(R.id.progress, mProgress, fromUser);
- }
+ mProgress = progress;
+ refreshProgress(R.id.progress, mProgress, fromUser);
+ return true;
}
/**
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index b95c27d..2026169 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -1238,7 +1238,8 @@ public class ScrollView extends FrameLayout {
}
@Override
- protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) {
+ protected void measureChild(View child, int parentWidthMeasureSpec,
+ int parentHeightMeasureSpec) {
ViewGroup.LayoutParams lp = child.getLayoutParams();
int childWidthMeasureSpec;
@@ -1247,7 +1248,8 @@ public class ScrollView extends FrameLayout {
childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft
+ mPaddingRight, lp.width);
- childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
+ MeasureSpec.getSize(parentHeightMeasureSpec), MeasureSpec.UNSPECIFIED);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
@@ -1261,7 +1263,7 @@ public class ScrollView extends FrameLayout {
mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
+ widthUsed, lp.width);
final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
- lp.topMargin + lp.bottomMargin, MeasureSpec.UNSPECIFIED);
+ MeasureSpec.getSize(parentHeightMeasureSpec), MeasureSpec.UNSPECIFIED);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index aa7f0b6..0249c22 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -26,7 +26,6 @@ import android.graphics.Paint.Align;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.TextPaint;
import android.text.format.DateFormat;
@@ -60,12 +59,6 @@ class SimpleMonthView extends View {
private static final String DEFAULT_TITLE_FORMAT = "MMMMy";
private static final String DAY_OF_WEEK_FORMAT = "EEEEE";
- /** Virtual view ID for previous button. */
- private static final int ITEM_ID_PREV = 0x101;
-
- /** Virtual view ID for next button. */
- private static final int ITEM_ID_NEXT = 0x100;
-
private final TextPaint mMonthPaint = new TextPaint();
private final TextPaint mDayOfWeekPaint = new TextPaint();
private final TextPaint mDayPaint = new TextPaint();
@@ -87,14 +80,6 @@ class SimpleMonthView extends View {
private final int mDesiredCellWidth;
private final int mDesiredDaySelectorRadius;
- // Next/previous drawables.
- private final Drawable mPrevDrawable;
- private final Drawable mNextDrawable;
- private final Rect mPrevHitArea;
- private final Rect mNextHitArea;
- private final CharSequence mPrevContentDesc;
- private final CharSequence mNextContentDesc;
-
private CharSequence mTitle;
private int mMonth;
@@ -137,9 +122,6 @@ class SimpleMonthView extends View {
/** The day of month for the last (inclusive) enabled day. */
private int mEnabledDayEnd = 31;
- /** The number of week rows needed to display the current month. */
- private int mNumWeeks = MAX_WEEKS_IN_MONTH;
-
/** Optional listener for handling day click actions. */
private OnDayClickListener mOnDayClickListener;
@@ -147,9 +129,6 @@ class SimpleMonthView extends View {
private int mTouchedItem = -1;
- private boolean mPrevEnabled;
- private boolean mNextEnabled;
-
public SimpleMonthView(Context context) {
this(context, null);
}
@@ -170,14 +149,8 @@ class SimpleMonthView extends View {
mDesiredDayOfWeekHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_of_week_height);
mDesiredDayHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_height);
mDesiredCellWidth = res.getDimensionPixelSize(R.dimen.date_picker_day_width);
- mDesiredDaySelectorRadius = res.getDimensionPixelSize(R.dimen.date_picker_day_selector_radius);
-
- mPrevDrawable = context.getDrawable(R.drawable.ic_chevron_left);
- mNextDrawable = context.getDrawable(R.drawable.ic_chevron_right);
- mPrevHitArea = mPrevDrawable != null ? new Rect() : null;
- mNextHitArea = mNextDrawable != null ? new Rect() : null;
- mPrevContentDesc = res.getText(R.string.date_picker_prev_month_button);
- mNextContentDesc = res.getText(R.string.date_picker_next_month_button);
+ mDesiredDaySelectorRadius = res.getDimensionPixelSize(
+ R.dimen.date_picker_day_selector_radius);
// Set up accessibility components.
mTouchHelper = new MonthViewTouchHelper(this);
@@ -193,18 +166,6 @@ class SimpleMonthView extends View {
initPaints(res);
}
- public void setNextEnabled(boolean enabled) {
- mNextEnabled = enabled;
- mTouchHelper.invalidateRoot();
- invalidate();
- }
-
- public void setPrevEnabled(boolean enabled) {
- mPrevEnabled = enabled;
- mTouchHelper.invalidateRoot();
- invalidate();
- }
-
/**
* Applies the specified text appearance resource to a paint, returning the
* text color if one is set in the text appearance.
@@ -236,16 +197,16 @@ class SimpleMonthView extends View {
return textColor;
}
+ public int getMonthHeight() {
+ return mMonthHeight;
+ }
+
+ public int getCellWidth() {
+ return mCellWidth;
+ }
+
public void setMonthTextAppearance(int resId) {
- final ColorStateList monthColor = applyTextAppearance(mMonthPaint, resId);
- if (monthColor != null) {
- if (mPrevDrawable != null) {
- mPrevDrawable.setTintList(monthColor);
- }
- if (mNextDrawable != null) {
- mNextDrawable.setTintList(monthColor);
- }
- }
+ applyTextAppearance(mMonthPaint, resId);
invalidate();
}
@@ -360,7 +321,7 @@ class SimpleMonthView extends View {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
- final int touchedItem = getItemAtLocation(x, y);
+ final int touchedItem = getDayAtLocation(x, y);
if (mTouchedItem != touchedItem) {
mTouchedItem = touchedItem;
invalidate();
@@ -368,8 +329,8 @@ class SimpleMonthView extends View {
break;
case MotionEvent.ACTION_UP:
- final int clickedItem = getItemAtLocation(x, y);
- onItemClicked(clickedItem, true);
+ final int clickedDay = getDayAtLocation(x, y);
+ onDayClicked(clickedDay);
// Fall through.
case MotionEvent.ACTION_CANCEL:
// Reset touched day on stream end.
@@ -389,7 +350,6 @@ class SimpleMonthView extends View {
drawMonth(canvas);
drawDaysOfWeek(canvas);
drawDays(canvas);
- drawButtons(canvas);
canvas.translate(-paddingLeft, -paddingTop);
}
@@ -482,16 +442,6 @@ class SimpleMonthView extends View {
}
}
- private void drawButtons(Canvas canvas) {
- if (mPrevEnabled && mPrevDrawable != null) {
- mPrevDrawable.draw(canvas);
- }
-
- if (mNextEnabled && mNextDrawable != null) {
- mNextDrawable.draw(canvas);
- }
- }
-
private static boolean isValidDayOfWeek(int day) {
return day >= Calendar.SUNDAY && day <= Calendar.SATURDAY;
}
@@ -674,33 +624,6 @@ class SimpleMonthView extends View {
mDaySelectorRadius = Math.min(mDesiredDaySelectorRadius,
Math.min(maxSelectorWidth, maxSelectorHeight));
- // Vertically center the previous/next drawables within the month
- // header, horizontally center within the day cell, then expand the
- // hit area to ensure it's at least 48x48dp.
- final Drawable prevDrawable = mPrevDrawable;
- if (prevDrawable != null) {
- final int dW = prevDrawable.getIntrinsicWidth();
- final int dH = prevDrawable.getIntrinsicHeight();
- final int iconTop = (monthHeight - dH) / 2;
- final int iconLeft = (cellWidth - dW) / 2;
-
- // Button bounds don't include padding, but hit area does.
- prevDrawable.setBounds(iconLeft, iconTop, iconLeft + dW, iconTop + dH);
- mPrevHitArea.set(0, 0, paddingLeft + cellWidth, paddingTop + monthHeight);
- }
-
- final Drawable nextDrawable = mNextDrawable;
- if (nextDrawable != null) {
- final int dW = nextDrawable.getIntrinsicWidth();
- final int dH = nextDrawable.getIntrinsicHeight();
- final int iconTop = (monthHeight - dH) / 2;
- final int iconRight = paddedWidth - (cellWidth - dW) / 2;
-
- // Button bounds don't include padding, but hit area does.
- nextDrawable.setBounds(iconRight - dW, iconTop, iconRight, iconTop + dH);
- mNextHitArea.set(paddedRight - cellWidth, 0, w, paddingTop + monthHeight);
- }
-
// Invalidate cached accessibility information.
mTouchHelper.invalidateRoot();
}
@@ -714,22 +637,15 @@ class SimpleMonthView extends View {
}
/**
- * Calculates the day of the month or item identifier at the specified
- * touch position. Returns the day of the month or -1 if the position
- * wasn't in a valid day.
+ * Calculates the day of the month at the specified touch position. Returns
+ * the day of the month or -1 if the position wasn't in a valid day.
*
* @param x the x position of the touch event
* @param y the y position of the touch event
- * @return the day of the month at (x, y), an item identifier, or -1 if the
- * position wasn't in a valid day or item
+ * @return the day of the month at (x, y), or -1 if the position wasn't in
+ * a valid day
*/
- private int getItemAtLocation(int x, int y) {
- if (mNextEnabled && mNextDrawable != null && mNextHitArea.contains(x, y)) {
- return ITEM_ID_NEXT;
- } else if (mPrevEnabled && mPrevDrawable != null && mPrevHitArea.contains(x, y)) {
- return ITEM_ID_PREV;
- }
-
+ private int getDayAtLocation(int x, int y) {
final int paddedX = x - getPaddingLeft();
if (paddedX < 0 || paddedX >= mPaddedWidth) {
return -1;
@@ -755,22 +671,10 @@ class SimpleMonthView extends View {
/**
* Calculates the bounds of the specified day.
*
- * @param id the day of the month, or an item identifier
+ * @param id the day of the month
* @param outBounds the rect to populate with bounds
*/
- private boolean getBoundsForItem(int id, Rect outBounds) {
- if (mNextEnabled && id == ITEM_ID_NEXT) {
- if (mNextDrawable != null) {
- outBounds.set(mNextHitArea);
- return true;
- }
- } else if (mPrevEnabled && id == ITEM_ID_PREV) {
- if (mPrevDrawable != null) {
- outBounds.set(mPrevHitArea);
- return true;
- }
- }
-
+ private boolean getBoundsForDay(int id, Rect outBounds) {
if (id < 1 || id > mDaysInMonth) {
return false;
}
@@ -789,16 +693,8 @@ class SimpleMonthView extends View {
final int top = getPaddingTop() + headerHeight + row * rowHeight;
outBounds.set(left, top, left + colWidth, top + rowHeight);
- return true;
- }
- /**
- * Called when an item is clicked.
- *
- * @param id the day number or item identifier
- */
- private boolean onItemClicked(int id, boolean animate) {
- return onNavigationClicked(id, animate) || onDayClicked(id);
+ return true;
}
/**
@@ -824,31 +720,6 @@ class SimpleMonthView extends View {
}
/**
- * Called when the user clicks on a navigation button. Handles callbacks to
- * the {@link OnDayClickListener} if one is set.
- *
- * @param id the item identifier
- */
- private boolean onNavigationClicked(int id, boolean animate) {
- final int direction;
- if (id == ITEM_ID_NEXT) {
- direction = 1;
- } else if (id == ITEM_ID_PREV) {
- direction = -1;
- } else {
- return false;
- }
-
- if (mOnDayClickListener != null) {
- mOnDayClickListener.onNavigationClick(this, direction, animate);
- }
-
- // This is a no-op if accessibility is turned off.
- mTouchHelper.sendEventForVirtualView(id, AccessibilityEvent.TYPE_VIEW_CLICKED);
- return true;
- }
-
- /**
* Provides a virtual view hierarchy for interfacing with an accessibility
* service.
*/
@@ -864,7 +735,7 @@ class SimpleMonthView extends View {
@Override
protected int getVirtualViewAt(float x, float y) {
- final int day = getItemAtLocation((int) (x + 0.5f), (int) (y + 0.5f));
+ final int day = getDayAtLocation((int) (x + 0.5f), (int) (y + 0.5f));
if (day >= 0) {
return day;
}
@@ -873,14 +744,6 @@ class SimpleMonthView extends View {
@Override
protected void getVisibleVirtualViews(IntArray virtualViewIds) {
- if (mNextEnabled && mNextDrawable != null) {
- virtualViewIds.add(ITEM_ID_PREV);
- }
-
- if (mPrevEnabled && mPrevDrawable != null) {
- virtualViewIds.add(ITEM_ID_NEXT);
- }
-
for (int day = 1; day <= mDaysInMonth; day++) {
virtualViewIds.add(day);
}
@@ -888,12 +751,12 @@ class SimpleMonthView extends View {
@Override
protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) {
- event.setContentDescription(getItemDescription(virtualViewId));
+ event.setContentDescription(getDayDescription(virtualViewId));
}
@Override
protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfo node) {
- final boolean hasBounds = getBoundsForItem(virtualViewId, mTempRect);
+ final boolean hasBounds = getBoundsForDay(virtualViewId, mTempRect);
if (!hasBounds) {
// The day is invalid, kill the node.
@@ -904,8 +767,8 @@ class SimpleMonthView extends View {
return;
}
- node.setText(getItemText(virtualViewId));
- node.setContentDescription(getItemDescription(virtualViewId));
+ node.setText(getDayText(virtualViewId));
+ node.setContentDescription(getDayDescription(virtualViewId));
node.setBoundsInParent(mTempRect);
node.addAction(AccessibilityAction.ACTION_CLICK);
@@ -921,7 +784,7 @@ class SimpleMonthView extends View {
Bundle arguments) {
switch (action) {
case AccessibilityNodeInfo.ACTION_CLICK:
- return onItemClicked(virtualViewId, false);
+ return onDayClicked(virtualViewId);
}
return false;
@@ -930,15 +793,11 @@ class SimpleMonthView extends View {
/**
* Generates a description for a given virtual view.
*
- * @param id the day or item identifier to generate a description for
+ * @param id the day to generate a description for
* @return a description of the virtual view
*/
- private CharSequence getItemDescription(int id) {
- if (id == ITEM_ID_NEXT) {
- return mNextContentDesc;
- } else if (id == ITEM_ID_PREV) {
- return mPrevContentDesc;
- } else if (id >= 1 && id <= mDaysInMonth) {
+ private CharSequence getDayDescription(int id) {
+ if (id >= 1 && id <= mDaysInMonth) {
mTempCalendar.set(mYear, mMonth, id);
return DateFormat.format(DATE_FORMAT, mTempCalendar.getTimeInMillis());
}
@@ -949,13 +808,11 @@ class SimpleMonthView extends View {
/**
* Generates displayed text for a given virtual view.
*
- * @param id the day or item identifier to generate text for
+ * @param id the day to generate text for
* @return the visible text of the virtual view
*/
- private CharSequence getItemText(int id) {
- if (id == ITEM_ID_NEXT || id == ITEM_ID_PREV) {
- return null;
- } else if (id >= 1 && id <= mDaysInMonth) {
+ private CharSequence getDayText(int id) {
+ if (id >= 1 && id <= mDaysInMonth) {
return Integer.toString(id);
}
@@ -967,7 +824,6 @@ class SimpleMonthView extends View {
* Handles callbacks when the user clicks on a time object.
*/
public interface OnDayClickListener {
- public void onDayClick(SimpleMonthView view, Calendar day);
- public void onNavigationClick(SimpleMonthView view, int direction, boolean animate);
+ void onDayClick(SimpleMonthView view, Calendar day);
}
}
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index 3746ec6..095cc44 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -811,9 +811,9 @@ public class Spinner extends AbsSpinner implements OnClickListener {
View itemView = null;
int itemType = 0;
final int widthMeasureSpec =
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.UNSPECIFIED);
final int heightMeasureSpec =
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.UNSPECIFIED);
// Make sure the number of items we'll measure is capped. If it's a huge data set
// with wildly varying sizes, oh well.
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 9496e62..aa7168c 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -173,11 +173,12 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener {
}
// First, measure with no constraint
- final int unspecifiedWidth = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ final int width = MeasureSpec.getSize(widthMeasureSpec);
+ final int unspecifiedWidth = MeasureSpec.makeMeasureSpec(width, MeasureSpec.UNSPECIFIED);
mImposedTabsHeight = -1;
super.measureHorizontal(unspecifiedWidth, heightMeasureSpec);
- int extraWidth = getMeasuredWidth() - MeasureSpec.getSize(widthMeasureSpec);
+ int extraWidth = getMeasuredWidth() - width;
if (extraWidth > 0) {
final int count = getChildCount();
diff --git a/core/java/android/widget/TableLayout.java b/core/java/android/widget/TableLayout.java
index 093bdcf..6fdd874 100644
--- a/core/java/android/widget/TableLayout.java
+++ b/core/java/android/widget/TableLayout.java
@@ -467,7 +467,7 @@ public class TableLayout extends LinearLayout {
*/
@Override
void measureVertical(int widthMeasureSpec, int heightMeasureSpec) {
- findLargestCells(widthMeasureSpec);
+ findLargestCells(widthMeasureSpec, heightMeasureSpec);
shrinkAndStretchColumns(widthMeasureSpec);
super.measureVertical(widthMeasureSpec, heightMeasureSpec);
@@ -479,7 +479,7 @@ public class TableLayout extends LinearLayout {
*
* @param widthMeasureSpec the measure constraint imposed by our parent
*/
- private void findLargestCells(int widthMeasureSpec) {
+ private void findLargestCells(int widthMeasureSpec, int heightMeasureSpec) {
boolean firstRow = true;
// find the maximum width for each column
@@ -502,7 +502,7 @@ public class TableLayout extends LinearLayout {
final ViewGroup.LayoutParams layoutParams = row.getLayoutParams();
layoutParams.height = LayoutParams.WRAP_CONTENT;
- final int[] widths = row.getColumnsWidths(widthMeasureSpec);
+ final int[] widths = row.getColumnsWidths(widthMeasureSpec, heightMeasureSpec);
final int newLength = widths.length;
// this is the first row, we just need to copy the values
if (firstRow) {
diff --git a/core/java/android/widget/TableRow.java b/core/java/android/widget/TableRow.java
index faf5b84..f73ee49 100644
--- a/core/java/android/widget/TableRow.java
+++ b/core/java/android/widget/TableRow.java
@@ -283,7 +283,7 @@ public class TableRow extends LinearLayout {
* column, in this row
* {@hide}
*/
- int[] getColumnsWidths(int widthMeasureSpec) {
+ int[] getColumnsWidths(int widthMeasureSpec, int heightMeasureSpec) {
final int numColumns = getVirtualChildCount();
if (mColumnWidths == null || numColumns != mColumnWidths.length) {
mColumnWidths = new int[numColumns];
@@ -302,7 +302,9 @@ public class TableRow extends LinearLayout {
spec = getChildMeasureSpec(widthMeasureSpec, 0, LayoutParams.WRAP_CONTENT);
break;
case LayoutParams.MATCH_PARENT:
- spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ spec = MeasureSpec.makeMeasureSpec(
+ MeasureSpec.getSize(heightMeasureSpec),
+ MeasureSpec.UNSPECIFIED);
break;
default:
spec = MeasureSpec.makeMeasureSpec(layoutParams.width, MeasureSpec.EXACTLY);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 7328300..726b89a 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1460,7 +1460,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (isTextEditable()) {
replaceSelectionWithText(result);
} else {
- Toast.makeText(getContext(), String.valueOf(result), Toast.LENGTH_LONG).show();
+ if (result.length() > 0) {
+ Toast.makeText(getContext(), String.valueOf(result), Toast.LENGTH_LONG).show();
+ }
}
}
}
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 4f0e29e..7c5c565 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -95,9 +95,6 @@ interface IBatteryStats {
void noteWifiState(int wifiState, String accessPoint);
void noteWifiSupplicantStateChanged(int supplState, boolean failedAuth);
void noteWifiRssiChanged(int newRssi);
- void noteBluetoothOn();
- void noteBluetoothOff();
- void noteBluetoothState(int bluetoothState);
void noteFullWifiLockAcquired(int uid);
void noteFullWifiLockReleased(int uid);
void noteWifiScanStarted(int uid);
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index 255f1fd..b04ddf4 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -361,7 +361,7 @@ public class PackageHelper {
VolumeInfo bestCandidate = null;
long bestCandidateAvailBytes = Long.MIN_VALUE;
for (VolumeInfo vol : storageManager.getVolumes()) {
- if (vol.type == VolumeInfo.TYPE_PRIVATE && vol.state == VolumeInfo.STATE_MOUNTED) {
+ if (vol.type == VolumeInfo.TYPE_PRIVATE && vol.isMountedWritable()) {
final long availBytes = storageManager.getStorageBytesUntilLow(new File(vol.path));
if (availBytes >= sizeBytes) {
allCandidates.add(vol.fsUuid);
diff --git a/core/java/com/android/internal/logging/EventLogTags.logtags b/core/java/com/android/internal/logging/EventLogTags.logtags
index b9208ff..4364cc3 100644
--- a/core/java/com/android/internal/logging/EventLogTags.logtags
+++ b/core/java/com/android/internal/logging/EventLogTags.logtags
@@ -4,6 +4,6 @@ option java_package com.android.internal.logging;
# interaction logs
524287 sysui_view_visibility (category|1|5),(visible|1|6)
-524288 sysui_action (category|1|5)
+524288 sysui_action (category|1|5),(pkg|3)
524290 sysui_count (name|3),(increment|1)
524291 sysui_histogram (name|3),(bucket|1)
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index 24b5d0d..092c148 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -30,6 +30,7 @@ public class MetricsLogger implements MetricsConstants {
public static final int NOTIFICATION_ZEN_MODE_SCHEDULE_RULE = 144;
public static final int NOTIFICATION_ZEN_MODE_EXTERNAL_RULE = 145;
+ public static final int ACTION_BAN_APP_NOTES = 146;
public static void visible(Context context, int category) throws IllegalArgumentException {
if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
@@ -46,10 +47,14 @@ public class MetricsLogger implements MetricsConstants {
}
public static void action(Context context, int category) {
+ action(context, category, "");
+ }
+
+ public static void action(Context context, int category, String pkg) {
if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
throw new IllegalArgumentException("Must define metric category");
}
- EventLogTags.writeSysuiAction(category);
+ EventLogTags.writeSysuiAction(category, pkg);
}
/** Add an integer value to the monotonically increasing counter with the given name. */
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 59dbec6..a53d46c 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -136,6 +136,14 @@ public final class BatteryStatsHelper {
profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX) != 0;
}
+ public static boolean checkHasBluetoothPowerReporting(BatteryStats stats,
+ PowerProfile profile) {
+ return stats.hasBluetoothActivityReporting() &&
+ profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_IDLE) != 0 &&
+ profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_RX) != 0 &&
+ profile.getAveragePower(PowerProfile.POWER_BLUETOOTH_CONTROLLER_TX) != 0;
+ }
+
public BatteryStatsHelper(Context context) {
this(context, true);
}
@@ -256,7 +264,8 @@ public final class BatteryStatsHelper {
}
public static String makemAh(double power) {
- if (power < .00001) return String.format("%.8f", power);
+ if (power == 0) return "0";
+ else if (power < .00001) return String.format("%.8f", power);
else if (power < .0001) return String.format("%.7f", power);
else if (power < .001) return String.format("%.6f", power);
else if (power < .01) return String.format("%.5f", power);
@@ -342,7 +351,11 @@ public final class BatteryStatsHelper {
mWifiPowerCalculator.reset();
if (mBluetoothPowerCalculator == null) {
- mBluetoothPowerCalculator = new BluetoothPowerCalculator();
+ if (checkHasBluetoothPowerReporting(mStats, mPowerProfile)) {
+ mBluetoothPowerCalculator = new BluetoothPowerCalculator();
+ } else {
+ mBluetoothPowerCalculator = new BluetoothPowerCalculator();
+ }
}
mBluetoothPowerCalculator.reset();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 87605f6..405c861 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -19,8 +19,6 @@ package com.android.internal.os;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.bluetooth.BluetoothActivityEnergyInfo;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
@@ -84,7 +82,6 @@ import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
-import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
@@ -107,7 +104,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 123 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 125 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -176,7 +173,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
public interface ExternalStatsSync {
- void scheduleSync();
+ void scheduleSync(String reason);
}
public final MyHandler mHandler;
@@ -250,6 +247,8 @@ public final class BatteryStatsImpl extends BatteryStats {
int mNumHistoryTagChars = 0;
int mHistoryBufferLastPos = -1;
boolean mHistoryOverflow = false;
+ int mActiveHistoryStates = 0xffffffff;
+ int mActiveHistoryStates2 = 0xffffffff;
long mLastHistoryElapsedRealtime = 0;
long mTrackRunningHistoryElapsedRealtime = 0;
long mTrackRunningHistoryUptime = 0;
@@ -313,7 +312,7 @@ public final class BatteryStatsImpl extends BatteryStats {
int mWakeLockNesting;
boolean mWakeLockImportant;
- boolean mRecordAllHistory;
+ public boolean mRecordAllHistory;
boolean mNoAutoReset;
int mScreenState = Display.STATE_UNKNOWN;
@@ -384,12 +383,6 @@ public final class BatteryStatsImpl extends BatteryStats {
final StopwatchTimer[] mWifiSignalStrengthsTimer =
new StopwatchTimer[NUM_WIFI_SIGNAL_STRENGTH_BINS];
- boolean mBluetoothOn;
- StopwatchTimer mBluetoothOnTimer;
-
- int mBluetoothState = -1;
- final StopwatchTimer[] mBluetoothStateTimer = new StopwatchTimer[NUM_BLUETOOTH_STATES];
-
int mMobileRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
long mMobileRadioActiveStartTime;
StopwatchTimer mMobileRadioActiveTimer;
@@ -398,8 +391,7 @@ public final class BatteryStatsImpl extends BatteryStats {
LongSamplingCounter mMobileRadioActiveUnknownTime;
LongSamplingCounter mMobileRadioActiveUnknownCount;
- /** Bluetooth headset object */
- BluetoothHeadset mBtHeadset;
+ int mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
/**
* These provide time bases that discount the time the device is plugged
@@ -458,9 +450,6 @@ public final class BatteryStatsImpl extends BatteryStats {
long mLastWriteTime = 0; // Milliseconds
- private int mBluetoothPingCount;
- private int mBluetoothPingStart = -1;
-
private int mPhoneServiceState = -1;
private int mPhoneServiceStateRaw = -1;
private int mPhoneSimStateRaw = -1;
@@ -1803,32 +1792,6 @@ public final class BatteryStatsImpl extends BatteryStats {
return kwlt;
}
- private int getCurrentBluetoothPingCount() {
- if (mBtHeadset != null) {
- List<BluetoothDevice> deviceList = mBtHeadset.getConnectedDevices();
- if (deviceList.size() > 0) {
- return mBtHeadset.getBatteryUsageHint(deviceList.get(0));
- }
- }
- return -1;
- }
-
- public int getBluetoothPingCount() {
- if (mBluetoothPingStart == -1) {
- return mBluetoothPingCount;
- } else if (mBtHeadset != null) {
- return getCurrentBluetoothPingCount() - mBluetoothPingStart;
- }
- return 0;
- }
-
- public void setBtHeadset(BluetoothHeadset headset) {
- if (headset != null && mBtHeadset == null && isOnBattery() && mBluetoothPingStart == -1) {
- mBluetoothPingStart = getCurrentBluetoothPingCount();
- }
- mBtHeadset = headset;
- }
-
private int writeHistoryTag(HistoryTag tag) {
Integer idxObj = mHistoryTagPool.get(tag);
int idx;
@@ -2259,8 +2222,8 @@ public final class BatteryStatsImpl extends BatteryStats {
}
final long timeDiff = (mHistoryBaseTime+elapsedRealtimeMs) - mHistoryLastWritten.time;
- final int diffStates = mHistoryLastWritten.states^cur.states;
- final int diffStates2 = mHistoryLastWritten.states2^cur.states2;
+ final int diffStates = mHistoryLastWritten.states^(cur.states&mActiveHistoryStates);
+ final int diffStates2 = mHistoryLastWritten.states2^(cur.states2&mActiveHistoryStates2);
final int lastDiffStates = mHistoryLastWritten.states^mHistoryLastLastWritten.states;
final int lastDiffStates2 = mHistoryLastWritten.states2^mHistoryLastLastWritten.states2;
if (DEBUG) Slog.i(TAG, "ADD: tdelta=" + timeDiff + " diff="
@@ -2325,11 +2288,32 @@ public final class BatteryStatsImpl extends BatteryStats {
return;
}
+ // After overflow, we allow various bit-wise states to settle to 0.
+ boolean writeAnyway = false;
+ final int curStates = cur.states & HistoryItem.SETTLE_TO_ZERO_STATES
+ & mActiveHistoryStates;
+ if (mHistoryLastWritten.states != curStates) {
+ // mActiveHistoryStates keeps track of which bits in .states are now being
+ // forced to 0.
+ int old = mActiveHistoryStates;
+ mActiveHistoryStates &= curStates | ~HistoryItem.SETTLE_TO_ZERO_STATES;
+ writeAnyway |= old != mActiveHistoryStates;
+ }
+ final int curStates2 = cur.states2 & HistoryItem.SETTLE_TO_ZERO_STATES2
+ & mActiveHistoryStates2;
+ if (mHistoryLastWritten.states2 != curStates2) {
+ // mActiveHistoryStates2 keeps track of which bits in .states2 are now being
+ // forced to 0.
+ int old = mActiveHistoryStates2;
+ mActiveHistoryStates2 &= curStates2 | ~HistoryItem.SETTLE_TO_ZERO_STATES2;
+ writeAnyway |= old != mActiveHistoryStates2;
+ }
+
// Once we've reached the maximum number of items, we only
// record changes to the battery level and the most interesting states.
// Once we've reached the maximum maximum number of items, we only
// record changes to the battery level.
- if (mHistoryLastWritten.batteryLevel == cur.batteryLevel &&
+ if (!writeAnyway && mHistoryLastWritten.batteryLevel == cur.batteryLevel &&
(dataSize >= MAX_MAX_HISTORY_BUFFER
|| ((mHistoryLastWritten.states^cur.states)
& HistoryItem.MOST_INTERESTING_STATES) == 0
@@ -2360,6 +2344,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mHistoryBufferLastPos = mHistoryBuffer.dataPosition();
mHistoryLastLastWritten.setTo(mHistoryLastWritten);
mHistoryLastWritten.setTo(mHistoryBaseTime + elapsedRealtimeMs, cmd, cur);
+ mHistoryLastWritten.states &= mActiveHistoryStates;
+ mHistoryLastWritten.states2 &= mActiveHistoryStates2;
writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten);
mLastHistoryElapsedRealtime = elapsedRealtimeMs;
cur.wakelockTag = null;
@@ -2411,8 +2397,8 @@ public final class BatteryStatsImpl extends BatteryStats {
// into one record.
if (mHistoryEnd != null && mHistoryEnd.cmd == HistoryItem.CMD_UPDATE
&& (mHistoryBaseTime+elapsedRealtimeMs) < (mHistoryEnd.time+1000)
- && ((mHistoryEnd.states^cur.states)&mChangedStates) == 0
- && ((mHistoryEnd.states2^cur.states2)&mChangedStates2) == 0) {
+ && ((mHistoryEnd.states^cur.states)&mChangedStates&mActiveHistoryStates) == 0
+ && ((mHistoryEnd.states2^cur.states2)&mChangedStates2&mActiveHistoryStates2) == 0) {
// If the current is the same as the one before, then we no
// longer need the entry.
if (mHistoryLastEnd != null && mHistoryLastEnd.cmd == HistoryItem.CMD_UPDATE
@@ -2424,8 +2410,8 @@ public final class BatteryStatsImpl extends BatteryStats {
mHistoryEnd = mHistoryLastEnd;
mHistoryLastEnd = null;
} else {
- mChangedStates |= mHistoryEnd.states^cur.states;
- mChangedStates2 |= mHistoryEnd.states^cur.states2;
+ mChangedStates |= mHistoryEnd.states^(cur.states&mActiveHistoryStates);
+ mChangedStates2 |= mHistoryEnd.states^(cur.states2&mActiveHistoryStates2);
mHistoryEnd.setTo(mHistoryEnd.time, HistoryItem.CMD_UPDATE, cur);
}
return;
@@ -2447,7 +2433,7 @@ public final class BatteryStatsImpl extends BatteryStats {
if (mHistoryEnd != null && mHistoryEnd.batteryLevel
== cur.batteryLevel &&
(mNumHistoryItems >= MAX_MAX_HISTORY_ITEMS
- || ((mHistoryEnd.states^cur.states)
+ || ((mHistoryEnd.states^(cur.states&mActiveHistoryStates))
& HistoryItem.MOST_INTERESTING_STATES) == 0)) {
return;
}
@@ -2456,7 +2442,7 @@ public final class BatteryStatsImpl extends BatteryStats {
addHistoryRecordLocked(elapsedRealtimeMs, HistoryItem.CMD_UPDATE);
}
- void addHistoryEventLocked(long elapsedRealtimeMs, long uptimeMs, int code,
+ public void addHistoryEventLocked(long elapsedRealtimeMs, long uptimeMs, int code,
String name, int uid) {
mHistoryCur.eventCode = code;
mHistoryCur.eventTag = mHistoryCur.localEventTag;
@@ -2515,23 +2501,15 @@ public final class BatteryStatsImpl extends BatteryStats {
mNumHistoryTagChars = 0;
mHistoryBufferLastPos = -1;
mHistoryOverflow = false;
+ mActiveHistoryStates = 0xffffffff;
+ mActiveHistoryStates2 = 0xffffffff;
mLastRecordedClockTime = 0;
mLastRecordedClockRealtime = 0;
}
public void updateTimeBasesLocked(boolean unplugged, boolean screenOff, long uptime,
long realtime) {
- if (mOnBatteryTimeBase.setRunning(unplugged, uptime, realtime)) {
- if (unplugged) {
- // Track bt headset ping count
- mBluetoothPingStart = getCurrentBluetoothPingCount();
- mBluetoothPingCount = 0;
- } else {
- // Track bt headset ping count
- mBluetoothPingCount = getBluetoothPingCount();
- mBluetoothPingStart = -1;
- }
- }
+ mOnBatteryTimeBase.setRunning(unplugged, uptime, realtime);
boolean unpluggedScreenOff = unplugged && screenOff;
if (unpluggedScreenOff != mOnBatteryScreenOffTimeBase.isRunning()) {
@@ -3396,7 +3374,7 @@ public final class BatteryStatsImpl extends BatteryStats {
if (!mPhoneOn) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
- mHistoryCur.states |= HistoryItem.STATE_PHONE_IN_CALL_FLAG;
+ mHistoryCur.states2 |= HistoryItem.STATE2_PHONE_IN_CALL_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Phone on to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
@@ -3409,7 +3387,7 @@ public final class BatteryStatsImpl extends BatteryStats {
if (mPhoneOn) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
final long uptime = SystemClock.uptimeMillis();
- mHistoryCur.states &= ~HistoryItem.STATE_PHONE_IN_CALL_FLAG;
+ mHistoryCur.states2 &= ~HistoryItem.STATE2_PHONE_IN_CALL_FLAG;
if (DEBUG_HISTORY) Slog.v(TAG, "Phone off to: "
+ Integer.toHexString(mHistoryCur.states));
addHistoryRecordLocked(elapsedRealtime, uptime);
@@ -3626,7 +3604,7 @@ public final class BatteryStatsImpl extends BatteryStats {
addHistoryRecordLocked(elapsedRealtime, uptime);
mWifiOn = true;
mWifiOnTimer.startRunningLocked(elapsedRealtime);
- scheduleSyncExternalStatsLocked();
+ scheduleSyncExternalStatsLocked("wifi-off");
}
}
@@ -3640,7 +3618,7 @@ public final class BatteryStatsImpl extends BatteryStats {
addHistoryRecordLocked(elapsedRealtime, uptime);
mWifiOn = false;
mWifiOnTimer.stopRunningLocked(elapsedRealtime);
- scheduleSyncExternalStatsLocked();
+ scheduleSyncExternalStatsLocked("wifi-on");
}
}
@@ -3788,6 +3766,25 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
+ public void noteWifiRadioPowerState(int powerState, long timestampNs) {
+ final long elapsedRealtime = SystemClock.elapsedRealtime();
+ final long uptime = SystemClock.uptimeMillis();
+ if (mWifiRadioPowerState != powerState) {
+ final boolean active =
+ powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
+ || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
+ if (active) {
+ mHistoryCur.states |= HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG;
+ } else {
+ mHistoryCur.states &= ~HistoryItem.STATE_WIFI_RADIO_ACTIVE_FLAG;
+ }
+ if (DEBUG_HISTORY) Slog.v(TAG, "Wifi network active " + active + " to: "
+ + Integer.toHexString(mHistoryCur.states));
+ addHistoryRecordLocked(elapsedRealtime, uptime);
+ mWifiRadioPowerState = powerState;
+ }
+ }
+
public void noteWifiRunningLocked(WorkSource ws) {
if (!mGlobalWifiRunning) {
final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -3803,7 +3800,7 @@ public final class BatteryStatsImpl extends BatteryStats {
int uid = mapUid(ws.get(i));
getUidStatsLocked(uid).noteWifiRunningLocked(elapsedRealtime);
}
- scheduleSyncExternalStatsLocked();
+ scheduleSyncExternalStatsLocked("wifi-running");
} else {
Log.w(TAG, "noteWifiRunningLocked -- called while WIFI running");
}
@@ -3842,7 +3839,7 @@ public final class BatteryStatsImpl extends BatteryStats {
int uid = mapUid(ws.get(i));
getUidStatsLocked(uid).noteWifiStoppedLocked(elapsedRealtime);
}
- scheduleSyncExternalStatsLocked();
+ scheduleSyncExternalStatsLocked("wifi-stopped");
} else {
Log.w(TAG, "noteWifiStoppedLocked -- called while WIFI not running");
}
@@ -3857,7 +3854,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
mWifiState = wifiState;
mWifiStateTimer[wifiState].startRunningLocked(elapsedRealtime);
- scheduleSyncExternalStatsLocked();
+ scheduleSyncExternalStatsLocked("wifi-state");
}
}
@@ -3919,46 +3916,6 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- public void noteBluetoothOnLocked() {
- if (!mBluetoothOn) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
- mHistoryCur.states |= HistoryItem.STATE_BLUETOOTH_ON_FLAG;
- if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth on to: "
- + Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(elapsedRealtime, uptime);
- mBluetoothOn = true;
- mBluetoothOnTimer.startRunningLocked(elapsedRealtime);
- scheduleSyncExternalStatsLocked();
- }
- }
-
- public void noteBluetoothOffLocked() {
- if (mBluetoothOn) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- final long uptime = SystemClock.uptimeMillis();
- mHistoryCur.states &= ~HistoryItem.STATE_BLUETOOTH_ON_FLAG;
- if (DEBUG_HISTORY) Slog.v(TAG, "Bluetooth off to: "
- + Integer.toHexString(mHistoryCur.states));
- addHistoryRecordLocked(elapsedRealtime, uptime);
- mBluetoothOn = false;
- mBluetoothOnTimer.stopRunningLocked(elapsedRealtime);
- scheduleSyncExternalStatsLocked();
- }
- }
-
- public void noteBluetoothStateLocked(int bluetoothState) {
- if (DEBUG) Log.i(TAG, "Bluetooth state -> " + bluetoothState);
- if (mBluetoothState != bluetoothState) {
- final long elapsedRealtime = SystemClock.elapsedRealtime();
- if (mBluetoothState >= 0) {
- mBluetoothStateTimer[mBluetoothState].stopRunningLocked(elapsedRealtime);
- }
- mBluetoothState = bluetoothState;
- mBluetoothStateTimer[bluetoothState].startRunningLocked(elapsedRealtime);
- }
- }
-
int mWifiFullLockNesting = 0;
public void noteFullWifiLockAcquiredLocked(int uid) {
@@ -4313,20 +4270,6 @@ public final class BatteryStatsImpl extends BatteryStats {
return mWifiSignalStrengthsTimer[strengthBin].getCountLocked(which);
}
- @Override public long getBluetoothOnTime(long elapsedRealtimeUs, int which) {
- return mBluetoothOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
- }
-
- @Override public long getBluetoothStateTime(int bluetoothState,
- long elapsedRealtimeUs, int which) {
- return mBluetoothStateTimer[bluetoothState].getTotalTimeLocked(
- elapsedRealtimeUs, which);
- }
-
- @Override public int getBluetoothStateCount(int bluetoothState, int which) {
- return mBluetoothStateTimer[bluetoothState].getCountLocked(which);
- }
-
@Override public boolean hasBluetoothActivityReporting() {
return mHasBluetoothEnergyReporting;
}
@@ -6780,10 +6723,6 @@ public final class BatteryStatsImpl extends BatteryStats {
mWifiSignalStrengthsTimer[i] = new StopwatchTimer(null, -800-i, null,
mOnBatteryTimeBase);
}
- mBluetoothOnTimer = new StopwatchTimer(null, -6, null, mOnBatteryTimeBase);
- for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
- mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i, null, mOnBatteryTimeBase);
- }
mAudioOnTimer = new StopwatchTimer(null, -7, null, mOnBatteryTimeBase);
mVideoOnTimer = new StopwatchTimer(null, -8, null, mOnBatteryTimeBase);
mFlashlightOnTimer = new StopwatchTimer(null, -9, null, mOnBatteryTimeBase);
@@ -7399,10 +7338,6 @@ public final class BatteryStatsImpl extends BatteryStats {
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
mWifiSignalStrengthsTimer[i].reset(false);
}
- mBluetoothOnTimer.reset(false);
- for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
- mBluetoothStateTimer[i].reset(false);
- }
for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
mBluetoothActivityCounters[i].reset(false);
mWifiActivityCounters[i].reset(false);
@@ -7727,16 +7662,12 @@ public final class BatteryStatsImpl extends BatteryStats {
mWifiActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
info.getControllerIdleTimeMillis());
- final double powerDrainMaMs;
- if (mPowerProfile.getAveragePower(
- PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE) == 0) {
- powerDrainMaMs = 0.0;
- } else {
- powerDrainMaMs = info.getControllerEnergyUsed()
- / mPowerProfile.getAveragePower(
- PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE);
+ final double opVoltage = mPowerProfile.getAveragePower(
+ PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE);
+ if (opVoltage != 0) {
+ mWifiActivityCounters[CONTROLLER_POWER_DRAIN].addCountLocked(
+ (long)(info.getControllerEnergyUsed() / opVoltage));
}
- mWifiActivityCounters[CONTROLLER_POWER_DRAIN].addCountLocked((long) powerDrainMaMs);
}
}
@@ -7824,8 +7755,13 @@ public final class BatteryStatsImpl extends BatteryStats {
info.getControllerTxTimeMillis());
mBluetoothActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
info.getControllerIdleTimeMillis());
- mBluetoothActivityCounters[CONTROLLER_POWER_DRAIN].addCountLocked(
- info.getControllerEnergyUsed());
+
+ final double opVoltage = mPowerProfile.getAveragePower(
+ PowerProfile.POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE);
+ if (opVoltage != 0) {
+ mBluetoothActivityCounters[CONTROLLER_POWER_DRAIN].addCountLocked(
+ (long) (info.getControllerEnergyUsed() / opVoltage));
+ }
}
}
@@ -7871,9 +7807,9 @@ public final class BatteryStatsImpl extends BatteryStats {
if (mCharging != charging) {
mCharging = charging;
if (charging) {
- mHistoryCur.states |= HistoryItem.STATE_CHARGING_FLAG;
+ mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG;
} else {
- mHistoryCur.states &= ~HistoryItem.STATE_CHARGING_FLAG;
+ mHistoryCur.states2 &= ~HistoryItem.STATE2_CHARGING_FLAG;
}
mHandler.sendEmptyMessage(MSG_REPORT_CHARGING);
return true;
@@ -8039,9 +7975,9 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- private void scheduleSyncExternalStatsLocked() {
+ private void scheduleSyncExternalStatsLocked(String reason) {
if (mExternalSync != null) {
- mExternalSync.scheduleSync();
+ mExternalSync.scheduleSync(reason);
}
}
@@ -8067,7 +8003,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
// Always start out assuming charging, that will be updated later.
- mHistoryCur.states |= HistoryItem.STATE_CHARGING_FLAG;
+ mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG;
mHistoryCur.batteryStatus = (byte)status;
mHistoryCur.batteryLevel = (byte)level;
mMaxChargeStepLevel = mMinDischargeStepLevel =
@@ -8109,7 +8045,7 @@ public final class BatteryStatsImpl extends BatteryStats {
// TODO(adamlesinski): Schedule the creation of a HistoryStepDetails record
// which will pull external stats.
- scheduleSyncExternalStatsLocked();
+ scheduleSyncExternalStatsLocked("battery-level");
}
if (mHistoryCur.batteryStatus != status) {
mHistoryCur.batteryStatus = (byte)status;
@@ -8910,6 +8846,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mMobileRadioActiveAdjustedTime.readSummaryFromParcelLocked(in);
mMobileRadioActiveUnknownTime.readSummaryFromParcelLocked(in);
mMobileRadioActiveUnknownCount.readSummaryFromParcelLocked(in);
+ mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
mWifiOn = false;
mWifiOnTimer.readSummaryFromParcelLocked(in);
mGlobalWifiRunning = false;
@@ -8923,16 +8860,9 @@ public final class BatteryStatsImpl extends BatteryStats {
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
mWifiSignalStrengthsTimer[i].readSummaryFromParcelLocked(in);
}
- mBluetoothOn = false;
- mBluetoothOnTimer.readSummaryFromParcelLocked(in);
- for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
- mBluetoothStateTimer[i].readSummaryFromParcelLocked(in);
- }
-
for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
mBluetoothActivityCounters[i].readSummaryFromParcelLocked(in);
}
-
for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
mWifiActivityCounters[i].readSummaryFromParcelLocked(in);
}
@@ -9246,10 +9176,6 @@ public final class BatteryStatsImpl extends BatteryStats {
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
mWifiSignalStrengthsTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
}
- mBluetoothOnTimer.writeSummaryFromParcelLocked(out, NOWREAL_SYS);
- for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
- mBluetoothStateTimer[i].writeSummaryFromParcelLocked(out, NOWREAL_SYS);
- }
for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
mBluetoothActivityCounters[i].writeSummaryFromParcelLocked(out);
}
@@ -9542,6 +9468,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mMobileRadioActiveAdjustedTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
mMobileRadioActiveUnknownTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
mMobileRadioActiveUnknownCount = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ mWifiRadioPowerState = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
mWifiOn = false;
mWifiOnTimer = new StopwatchTimer(null, -4, null, mOnBatteryTimeBase, in);
mGlobalWifiRunning = false;
@@ -9558,17 +9485,9 @@ public final class BatteryStatsImpl extends BatteryStats {
mWifiSignalStrengthsTimer[i] = new StopwatchTimer(null, -800-i,
null, mOnBatteryTimeBase, in);
}
- mBluetoothOn = false;
- mBluetoothOnTimer = new StopwatchTimer(null, -6, null, mOnBatteryTimeBase, in);
- for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
- mBluetoothStateTimer[i] = new StopwatchTimer(null, -500-i,
- null, mOnBatteryTimeBase, in);
- }
-
for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
mBluetoothActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
}
-
for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
mWifiActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
}
@@ -9598,9 +9517,6 @@ public final class BatteryStatsImpl extends BatteryStats {
mChargeStepTracker.readFromParcel(in);
mLastWriteTime = in.readLong();
- mBluetoothPingCount = in.readInt();
- mBluetoothPingStart = -1;
-
mKernelWakelockStats.clear();
int NKW = in.readInt();
for (int ikw = 0; ikw < NKW; ikw++) {
@@ -9718,10 +9634,6 @@ public final class BatteryStatsImpl extends BatteryStats {
for (int i=0; i<NUM_WIFI_SIGNAL_STRENGTH_BINS; i++) {
mWifiSignalStrengthsTimer[i].writeToParcel(out, uSecRealtime);
}
- mBluetoothOnTimer.writeToParcel(out, uSecRealtime);
- for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
- mBluetoothStateTimer[i].writeToParcel(out, uSecRealtime);
- }
for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
mBluetoothActivityCounters[i].writeToParcel(out);
}
@@ -9748,8 +9660,6 @@ public final class BatteryStatsImpl extends BatteryStats {
mChargeStepTracker.writeToParcel(out);
out.writeLong(mLastWriteTime);
- out.writeInt(getBluetoothPingCount());
-
if (inclUids) {
out.writeInt(mKernelWakelockStats.size());
for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
@@ -9851,6 +9761,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mMobileRadioActiveTimer.logState(pr, " ");
pr.println("*** Mobile network active adjusted timer:");
mMobileRadioActiveAdjustedTime.logState(pr, " ");
+ pr.println("*** mWifiRadioPowerState=" + mWifiRadioPowerState);
pr.println("*** Wifi timer:");
mWifiOnTimer.logState(pr, " ");
pr.println("*** WifiRunning timer:");
@@ -9867,12 +9778,6 @@ public final class BatteryStatsImpl extends BatteryStats {
pr.println("*** Wifi signal strength #" + i + ":");
mWifiSignalStrengthsTimer[i].logState(pr, " ");
}
- pr.println("*** Bluetooth timer:");
- mBluetoothOnTimer.logState(pr, " ");
- for (int i=0; i< NUM_BLUETOOTH_STATES; i++) {
- pr.println("*** Bluetooth active type #" + i + ":");
- mBluetoothStateTimer[i].logState(pr, " ");
- }
pr.println("*** Flashlight timer:");
mFlashlightOnTimer.logState(pr, " ");
}
diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java
index 4fb8b55..961b0df 100644
--- a/core/java/com/android/internal/os/WifiPowerCalculator.java
+++ b/core/java/com/android/internal/os/WifiPowerCalculator.java
@@ -71,7 +71,7 @@ public class WifiPowerCalculator extends PowerCalculator {
app.wifiRunningTimeMs = idleTimeMs + rxTimeMs + txTimeMs;
double powerDrain = stats.getWifiControllerActivity(BatteryStats.CONTROLLER_POWER_DRAIN,
- statsType) / (1000*60*60);
+ statsType) / (double)(1000*60*60);
if (powerDrain == 0) {
// Some controllers do not report power drain, so we can calculate it here.
powerDrain = ((idleTimeMs * mIdleCurrentMa) + (txTimeMs * mTxCurrentMa)
diff --git a/core/java/com/android/internal/os/WifiPowerEstimator.java b/core/java/com/android/internal/os/WifiPowerEstimator.java
index 0172367..c4e2ef6 100644
--- a/core/java/com/android/internal/os/WifiPowerEstimator.java
+++ b/core/java/com/android/internal/os/WifiPowerEstimator.java
@@ -63,7 +63,7 @@ public class WifiPowerEstimator extends PowerCalculator {
mTotalAppWifiRunningTimeMs += app.wifiRunningTimeMs;
final double wifiLockPower = (app.wifiRunningTimeMs * mWifiPowerOn) / (1000*60*60);
- final long wifiScanTimeMs = u.getWifiScanTime(rawRealtimeUs, statsType);
+ final long wifiScanTimeMs = u.getWifiScanTime(rawRealtimeUs, statsType) / 1000;
final double wifiScanPower = (wifiScanTimeMs * mWifiPowerScan) / (1000*60*60);
double wifiBatchScanPower = 0;
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 3ad4f1c..48f0e71 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -269,7 +269,12 @@ public class ZygoteInit {
if (false) {
Log.v(TAG, "Preloading " + line + "...");
}
- Class.forName(line);
+ // Load and explicitly initialize the given class. Use the tree-argument version
+ // of forName to avoid repeated stack lookups (to derive the caller's
+ // class-loader). Use true to force initialization, and null for the boot
+ // classpath class-loader (could as well cache the class-loader of this class in
+ // a variable).
+ Class.forName(line, true, null);
count++;
} catch (ClassNotFoundException e) {
Log.w(TAG, "Class not found for preloading: " + line);
diff --git a/core/java/com/android/internal/transition/EpicenterClipReveal.java b/core/java/com/android/internal/transition/EpicenterClipReveal.java
index abb50c1..1a6736a 100644
--- a/core/java/com/android/internal/transition/EpicenterClipReveal.java
+++ b/core/java/com/android/internal/transition/EpicenterClipReveal.java
@@ -17,15 +17,23 @@ package com.android.internal.transition;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.RectEvaluator;
+import android.animation.TimeInterpolator;
import android.content.Context;
+import android.content.res.TypedArray;
import android.graphics.Rect;
import android.transition.TransitionValues;
import android.transition.Visibility;
import android.util.AttributeSet;
+import android.util.Property;
import android.view.View;
import android.view.ViewGroup;
+import android.view.animation.AnimationUtils;
+import android.view.animation.PathInterpolator;
+
+import com.android.internal.R;
/**
* EpicenterClipReveal captures the {@link View#getClipBounds()} before and
@@ -36,10 +44,39 @@ public class EpicenterClipReveal extends Visibility {
private static final String PROPNAME_CLIP = "android:epicenterReveal:clip";
private static final String PROPNAME_BOUNDS = "android:epicenterReveal:bounds";
- public EpicenterClipReveal() {}
+ private final TimeInterpolator mInterpolatorX;
+ private final TimeInterpolator mInterpolatorY;
+ private final boolean mCenterClipBounds;
+
+ public EpicenterClipReveal() {
+ mInterpolatorX = null;
+ mInterpolatorY = null;
+ mCenterClipBounds = false;
+ }
public EpicenterClipReveal(Context context, AttributeSet attrs) {
super(context, attrs);
+
+ final TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.EpicenterClipReveal, 0, 0);
+
+ mCenterClipBounds = a.getBoolean(R.styleable.EpicenterClipReveal_centerClipBounds, false);
+
+ final int interpolatorX = a.getResourceId(R.styleable.EpicenterClipReveal_interpolatorX, 0);
+ if (interpolatorX != 0) {
+ mInterpolatorX = AnimationUtils.loadInterpolator(context, interpolatorX);
+ } else {
+ mInterpolatorX = TransitionConstants.LINEAR_OUT_SLOW_IN;
+ }
+
+ final int interpolatorY = a.getResourceId(R.styleable.EpicenterClipReveal_interpolatorY, 0);
+ if (interpolatorY != 0) {
+ mInterpolatorY = AnimationUtils.loadInterpolator(context, interpolatorY);
+ } else {
+ mInterpolatorY = TransitionConstants.FAST_OUT_SLOW_IN;
+ }
+
+ a.recycle();
}
@Override
@@ -82,7 +119,7 @@ public class EpicenterClipReveal extends Visibility {
// Prepare the view.
view.setClipBounds(start);
- return createRectAnimator(view, start, end, endValues);
+ return createRectAnimator(view, start, end, endValues, mInterpolatorX, mInterpolatorY);
}
@Override
@@ -98,17 +135,23 @@ public class EpicenterClipReveal extends Visibility {
// Prepare the view.
view.setClipBounds(start);
- return createRectAnimator(view, start, end, endValues);
+ return createRectAnimator(view, start, end, endValues, mInterpolatorX, mInterpolatorY);
}
private Rect getEpicenterOrCenter(Rect bestRect) {
final Rect epicenter = getEpicenter();
if (epicenter != null) {
+ // Translate the clip bounds to be centered within the target bounds.
+ if (mCenterClipBounds) {
+ final int offsetX = bestRect.centerX() - epicenter.centerX();
+ final int offsetY = bestRect.centerY() - epicenter.centerY();
+ epicenter.offset(offsetX, offsetY);
+ }
return epicenter;
}
- int centerX = bestRect.centerX();
- int centerY = bestRect.centerY();
+ final int centerX = bestRect.centerX();
+ final int centerY = bestRect.centerY();
return new Rect(centerX, centerY, centerX, centerY);
}
@@ -120,17 +163,71 @@ public class EpicenterClipReveal extends Visibility {
return clipRect;
}
- private Animator createRectAnimator(final View view, Rect start, Rect end,
- TransitionValues endValues) {
- final Rect terminalClip = (Rect) endValues.values.get(PROPNAME_CLIP);
+ private static Animator createRectAnimator(final View view, Rect start, Rect end,
+ TransitionValues endValues, TimeInterpolator interpolatorX,
+ TimeInterpolator interpolatorY) {
final RectEvaluator evaluator = new RectEvaluator(new Rect());
- ObjectAnimator anim = ObjectAnimator.ofObject(view, "clipBounds", evaluator, start, end);
- anim.addListener(new AnimatorListenerAdapter() {
+ final Rect terminalClip = (Rect) endValues.values.get(PROPNAME_CLIP);
+
+ final ClipDimenProperty propX = new ClipDimenProperty(ClipDimenProperty.TARGET_X);
+ final ObjectAnimator animX = ObjectAnimator.ofObject(view, propX, evaluator, start, end);
+ if (interpolatorX != null) {
+ animX.setInterpolator(interpolatorX);
+ }
+
+ final ClipDimenProperty propY = new ClipDimenProperty(ClipDimenProperty.TARGET_Y);
+ final ObjectAnimator animY = ObjectAnimator.ofObject(view, propY, evaluator, start, end);
+ if (interpolatorY != null) {
+ animY.setInterpolator(interpolatorY);
+ }
+
+ final AnimatorSet animSet = new AnimatorSet();
+ animSet.playTogether(animX, animY);
+ animSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
view.setClipBounds(terminalClip);
}
});
- return anim;
+ return animSet;
+ }
+
+ private static class ClipDimenProperty extends Property<View, Rect> {
+ public static final char TARGET_X = 'x';
+ public static final char TARGET_Y = 'y';
+
+ private final Rect mTempRect = new Rect();
+
+ private final int mTargetDimension;
+
+ public ClipDimenProperty(char targetDimension) {
+ super(Rect.class, "clip_bounds_" + targetDimension);
+
+ mTargetDimension = targetDimension;
+ }
+
+ @Override
+ public Rect get(View object) {
+ final Rect tempRect = mTempRect;
+ if (!object.getClipBounds(tempRect)) {
+ tempRect.setEmpty();
+ }
+ return tempRect;
+ }
+
+ @Override
+ public void set(View object, Rect value) {
+ final Rect tempRect = mTempRect;
+ if (object.getClipBounds(tempRect)) {
+ if (mTargetDimension == TARGET_X) {
+ tempRect.left = value.left;
+ tempRect.right = value.right;
+ } else {
+ tempRect.top = value.top;
+ tempRect.bottom = value.bottom;
+ }
+ object.setClipBounds(tempRect);
+ }
+ }
}
}
diff --git a/core/java/com/android/internal/transition/EpicenterTranslate.java b/core/java/com/android/internal/transition/EpicenterTranslate.java
new file mode 100644
index 0000000..eac3ff8
--- /dev/null
+++ b/core/java/com/android/internal/transition/EpicenterTranslate.java
@@ -0,0 +1,191 @@
+/*
+ * 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.internal.transition;
+
+import com.android.internal.R;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
+import android.transition.TransitionValues;
+import android.transition.Visibility;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AnimationUtils;
+
+/**
+ * EpicenterTranslate captures the {@link View#getTranslationX()} and
+ * {@link View#getTranslationY()} before and after the scene change and
+ * animates between those and the epicenter's center during a visibility
+ * transition.
+ */
+public class EpicenterTranslate extends Visibility {
+ private static final String PROPNAME_BOUNDS = "android:epicenterReveal:bounds";
+ private static final String PROPNAME_TRANSLATE_X = "android:epicenterReveal:translateX";
+ private static final String PROPNAME_TRANSLATE_Y = "android:epicenterReveal:translateY";
+ private static final String PROPNAME_TRANSLATE_Z = "android:epicenterReveal:translateZ";
+ private static final String PROPNAME_Z = "android:epicenterReveal:z";
+
+ private final TimeInterpolator mInterpolatorX;
+ private final TimeInterpolator mInterpolatorY;
+ private final TimeInterpolator mInterpolatorZ;
+
+ public EpicenterTranslate() {
+ mInterpolatorX = null;
+ mInterpolatorY = null;
+ mInterpolatorZ = null;
+ }
+
+ public EpicenterTranslate(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ final TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.EpicenterTranslate, 0, 0);
+
+ final int interpolatorX = a.getResourceId(R.styleable.EpicenterTranslate_interpolatorX, 0);
+ if (interpolatorX != 0) {
+ mInterpolatorX = AnimationUtils.loadInterpolator(context, interpolatorX);
+ } else {
+ mInterpolatorX = TransitionConstants.FAST_OUT_SLOW_IN;
+ }
+
+ final int interpolatorY = a.getResourceId(R.styleable.EpicenterTranslate_interpolatorY, 0);
+ if (interpolatorY != 0) {
+ mInterpolatorY = AnimationUtils.loadInterpolator(context, interpolatorY);
+ } else {
+ mInterpolatorY = TransitionConstants.FAST_OUT_SLOW_IN;
+ }
+
+ final int interpolatorZ = a.getResourceId(R.styleable.EpicenterTranslate_interpolatorZ, 0);
+ if (interpolatorZ != 0) {
+ mInterpolatorZ = AnimationUtils.loadInterpolator(context, interpolatorZ);
+ } else {
+ mInterpolatorZ = TransitionConstants.FAST_OUT_SLOW_IN;
+ }
+
+ a.recycle();
+ }
+
+ @Override
+ public void captureStartValues(TransitionValues transitionValues) {
+ super.captureStartValues(transitionValues);
+ captureValues(transitionValues);
+ }
+
+ @Override
+ public void captureEndValues(TransitionValues transitionValues) {
+ super.captureEndValues(transitionValues);
+ captureValues(transitionValues);
+ }
+
+ private void captureValues(TransitionValues values) {
+ final View view = values.view;
+ if (view.getVisibility() == View.GONE) {
+ return;
+ }
+
+ final Rect bounds = new Rect(0, 0, view.getWidth(), view.getHeight());
+ values.values.put(PROPNAME_BOUNDS, bounds);
+ values.values.put(PROPNAME_TRANSLATE_X, view.getTranslationX());
+ values.values.put(PROPNAME_TRANSLATE_Y, view.getTranslationY());
+ values.values.put(PROPNAME_TRANSLATE_Z, view.getTranslationZ());
+ values.values.put(PROPNAME_Z, view.getZ());
+ }
+
+ @Override
+ public Animator onAppear(ViewGroup sceneRoot, View view,
+ TransitionValues startValues, TransitionValues endValues) {
+ if (endValues == null) {
+ return null;
+ }
+
+ final Rect end = (Rect) endValues.values.get(PROPNAME_BOUNDS);
+ final Rect start = getEpicenterOrCenter(end);
+ final float startX = start.centerX() - end.centerX();
+ final float startY = start.centerY() - end.centerY();
+ final float startZ = 0 - (float) endValues.values.get(PROPNAME_Z);
+
+ // Translate the view to be centered on the epicenter.
+ view.setTranslationX(startX);
+ view.setTranslationY(startY);
+ view.setTranslationZ(startZ);
+
+ final float endX = (float) endValues.values.get(PROPNAME_TRANSLATE_X);
+ final float endY = (float) endValues.values.get(PROPNAME_TRANSLATE_Y);
+ final float endZ = (float) endValues.values.get(PROPNAME_TRANSLATE_Z);
+ return createAnimator(view, startX, startY, startZ, endX, endY, endZ,
+ mInterpolatorX, mInterpolatorY, mInterpolatorZ);
+ }
+
+ @Override
+ public Animator onDisappear(ViewGroup sceneRoot, View view,
+ TransitionValues startValues, TransitionValues endValues) {
+ if (startValues == null) {
+ return null;
+ }
+
+ final Rect start = (Rect) endValues.values.get(PROPNAME_BOUNDS);
+ final Rect end = getEpicenterOrCenter(start);
+ final float endX = end.centerX() - start.centerX();
+ final float endY = end.centerY() - start.centerY();
+ final float endZ = 0 - (float) startValues.values.get(PROPNAME_Z);
+
+ final float startX = (float) endValues.values.get(PROPNAME_TRANSLATE_X);
+ final float startY = (float) endValues.values.get(PROPNAME_TRANSLATE_Y);
+ final float startZ = (float) endValues.values.get(PROPNAME_TRANSLATE_Z);
+ return createAnimator(view, startX, startY, startZ, endX, endY, endZ,
+ mInterpolatorX, mInterpolatorY, mInterpolatorZ);
+ }
+
+ private Rect getEpicenterOrCenter(Rect bestRect) {
+ final Rect epicenter = getEpicenter();
+ if (epicenter != null) {
+ return epicenter;
+ }
+
+ final int centerX = bestRect.centerX();
+ final int centerY = bestRect.centerY();
+ return new Rect(centerX, centerY, centerX, centerY);
+ }
+
+ private static Animator createAnimator(final View view, float startX, float startY,
+ float startZ, float endX, float endY, float endZ, TimeInterpolator interpolatorX,
+ TimeInterpolator interpolatorY, TimeInterpolator interpolatorZ) {
+ final ObjectAnimator animX = ObjectAnimator.ofFloat(view, View.TRANSLATION_X, startX, endX);
+ if (interpolatorX != null) {
+ animX.setInterpolator(interpolatorX);
+ }
+
+ final ObjectAnimator animY = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, startY, endY);
+ if (interpolatorY != null) {
+ animY.setInterpolator(interpolatorY);
+ }
+
+ final ObjectAnimator animZ = ObjectAnimator.ofFloat(view, View.TRANSLATION_Z, startZ, endZ);
+ if (interpolatorZ != null) {
+ animZ.setInterpolator(interpolatorZ);
+ }
+
+ final AnimatorSet animSet = new AnimatorSet();
+ animSet.playTogether(animX, animY, animZ);
+ return animSet;
+ }
+}
diff --git a/core/java/com/android/internal/transition/TransitionConstants.java b/core/java/com/android/internal/transition/TransitionConstants.java
new file mode 100644
index 0000000..e9015e6
--- /dev/null
+++ b/core/java/com/android/internal/transition/TransitionConstants.java
@@ -0,0 +1,24 @@
+/*
+ * 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.internal.transition;
+
+import android.animation.TimeInterpolator;
+import android.view.animation.PathInterpolator;
+
+class TransitionConstants {
+ static final TimeInterpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0, 0, 0.2f, 1);
+ static final TimeInterpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0, 0.2f, 1);
+}
diff --git a/core/java/com/android/internal/widget/ActionBarContainer.java b/core/java/com/android/internal/widget/ActionBarContainer.java
index a5efa82..1961b4b 100644
--- a/core/java/com/android/internal/widget/ActionBarContainer.java
+++ b/core/java/com/android/internal/widget/ActionBarContainer.java
@@ -251,12 +251,6 @@ public class ActionBarContainer extends FrameLayout {
}
@Override
- public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
- // No starting an action mode for an action bar child! (Where would it go?)
- return null;
- }
-
- @Override
public ActionMode startActionModeForChild(
View child, ActionMode.Callback callback, int type) {
if (type != ActionMode.TYPE_PRIMARY) {
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 42d875d..2946456 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -367,7 +367,8 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi
if (mTitleLayout != null && mCustomView == null) {
if (mTitleOptional) {
- final int titleWidthSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ final int titleWidthSpec = MeasureSpec.makeMeasureSpec(contentWidth,
+ MeasureSpec.UNSPECIFIED);
mTitleLayout.measure(titleWidthSpec, childSpecHeight);
final int titleWidth = mTitleLayout.getMeasuredWidth();
final boolean titleFits = titleWidth <= availableWidth;
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 0b1e0e5..a14e98d 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -108,8 +108,7 @@ public final class FloatingToolbar {
}
/**
- * Sets the custom listener for invocation of menu items in this floating
- * toolbar.
+ * Sets the custom listener for invocation of menu items in this floating toolbar.
*/
public FloatingToolbar setOnMenuItemClickListener(
MenuItem.OnMenuItemClickListener menuItemClickListener) {
@@ -188,13 +187,28 @@ public final class FloatingToolbar {
}
/**
- * Returns {@code true} if this popup is currently showing. {@code false} otherwise.
+ * Hides this floating toolbar. This is a no-op if the toolbar is not showing.
+ * Use {@link #isHidden()} to distinguish between a hidden and a dismissed toolbar.
+ */
+ public void hide() {
+ mPopup.hide();
+ }
+
+ /**
+ * Returns {@code true} if this toolbar is currently showing. {@code false} otherwise.
*/
public boolean isShowing() {
return mPopup.isShowing();
}
/**
+ * Returns {@code true} if this toolbar is currently hidden. {@code false} otherwise.
+ */
+ public boolean isHidden() {
+ return mPopup.isHidden();
+ }
+
+ /**
* Refreshes {@link #mCoordinates} with values based on {@link #mContentRect}.
*/
private void refreshCoordinates() {
@@ -274,13 +288,8 @@ public final class FloatingToolbar {
@Override
public void onAnimationEnd(Animation animation) {
- // This animation should never be run if the overflow panel has not been
- // initialized.
- Preconditions.checkNotNull(mOverflowPanel);
- mContentContainer.removeAllViews();
- mContentContainer.addView(mOverflowPanel.getView());
+ setOverflowPanelAsContent();
mOverflowPanel.fadeIn(true);
- setContentAreaAsTouchableSurface();
}
@Override
@@ -293,21 +302,35 @@ public final class FloatingToolbar {
@Override
public void onAnimationEnd(Animation animation) {
- // This animation should never be run if the main panel has not been
- // initialized.
- Preconditions.checkNotNull(mMainPanel);
- mContentContainer.removeAllViews();
- mContentContainer.addView(mMainPanel.getView());
+ setMainPanelAsContent();
mMainPanel.fadeIn(true);
- setContentAreaAsTouchableSurface();
}
@Override
public void onAnimationRepeat(Animation animation) {
}
};
- private final AnimatorSet mGrowFadeInFromBottomAnimation;
- private final AnimatorSet mShrinkFadeOutFromBottomAnimation;
+ private final AnimatorSet mShowAnimation;
+ private final AnimatorSet mDismissAnimation;
+ private final AnimatorSet mHideAnimation;
+ private final AnimationSet mOpenOverflowAnimation = new AnimationSet(true) {
+ @Override
+ public void cancel() {
+ if (hasStarted() && !hasEnded()) {
+ super.cancel();
+ setOverflowPanelAsContent();
+ }
+ }
+ };
+ private final AnimationSet mCloseOverflowAnimation = new AnimationSet(true) {
+ @Override
+ public void cancel() {
+ if (hasStarted() && !hasEnded()) {
+ super.cancel();
+ setMainPanelAsContent();
+ }
+ }
+ };
private final Runnable mOpenOverflow = new Runnable() {
@Override
@@ -324,7 +347,8 @@ public final class FloatingToolbar {
private final Region mTouchableRegion = new Region();
- private boolean mDismissAnimating;
+ private boolean mDismissed = true; // tracks whether this popup is dismissed or dismissing.
+ private boolean mHidden; // tracks whether this popup is hidden or hiding.
private FloatingToolbarOverflowPanel mOverflowPanel;
private FloatingToolbarMainPanel mMainPanel;
@@ -340,15 +364,22 @@ public final class FloatingToolbar {
mParent = Preconditions.checkNotNull(parent);
mContentContainer = createContentContainer(parent.getContext());
mPopupWindow = createPopupWindow(mContentContainer);
- mGrowFadeInFromBottomAnimation = createGrowFadeInFromBottom(mContentContainer);
- mShrinkFadeOutFromBottomAnimation = createShrinkFadeOutFromBottomAnimation(
+ mShowAnimation = createGrowFadeInFromBottom(mContentContainer);
+ mDismissAnimation = createShrinkFadeOutFromBottomAnimation(
+ mContentContainer,
+ new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mPopupWindow.dismiss();
+ mContentContainer.removeAllViews();
+ }
+ });
+ mHideAnimation = createShrinkFadeOutFromBottomAnimation(
mContentContainer,
new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mPopupWindow.dismiss();
- mDismissAnimating = false;
- setMainPanelAsContent();
}
});
// Make the touchable area of this popup be the area specified by mTouchableRegion.
@@ -404,10 +435,19 @@ public final class FloatingToolbar {
return;
}
- stopDismissAnimation();
+ mHidden = false;
+ mDismissed = false;
+ cancelAllAnimations();
+ // Make sure a panel is set as the content.
+ if (mContentContainer.getChildCount() == 0) {
+ setMainPanelAsContent();
+ }
preparePopupContent();
+ // If we're yet to show the popup, set the container visibility to zero.
+ // The "show" animation will make this visible.
+ mContentContainer.setAlpha(0);
mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, x, y);
- growFadeInFromBottom();
+ runShowAnimation();
}
/**
@@ -418,8 +458,23 @@ public final class FloatingToolbar {
return;
}
- mDismissAnimating = true;
- shrinkFadeOutFromBottom();
+ mHidden = false;
+ mDismissed = true;
+ runDismissAnimation();
+ setZeroTouchableSurface();
+ }
+
+ /**
+ * Hides this popup. This is a no-op if this popup is not showing.
+ * Use {@link #isHidden()} to distinguish between a hidden and a dismissed popup.
+ */
+ public void hide() {
+ if (!isShowing()) {
+ return;
+ }
+
+ mHidden = true;
+ runHideAnimation();
setZeroTouchableSurface();
}
@@ -427,19 +482,27 @@ public final class FloatingToolbar {
* Returns {@code true} if this popup is currently showing. {@code false} otherwise.
*/
public boolean isShowing() {
- return mPopupWindow.isShowing() && !mDismissAnimating;
+ return mPopupWindow.isShowing() && !mDismissed && !mHidden;
+ }
+
+ /**
+ * Returns {@code true} if this popup is currently hidden. {@code false} otherwise.
+ */
+ public boolean isHidden() {
+ return mHidden;
}
/**
* Updates the coordinates of this popup.
* The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
+ * This is a no-op if this popup is not showing.
*/
public void updateCoordinates(int x, int y) {
- if (mDismissAnimating) {
- // Already being dismissed. Ignore.
+ if (!isShowing()) {
return;
}
+ cancelAllAnimations();
preparePopupContent();
mPopupWindow.update(x, y, getWidth(), getHeight());
}
@@ -483,34 +546,44 @@ public final class FloatingToolbar {
}
/**
- * Performs the "grow and fade in from the bottom" animation on the floating popup.
+ * Performs the "show" animation on the floating popup.
+ */
+ private void runShowAnimation() {
+ mShowAnimation.start();
+ }
+
+ /**
+ * Performs the "dismiss" animation on the floating popup.
*/
- private void growFadeInFromBottom() {
- mGrowFadeInFromBottomAnimation.start();
+ private void runDismissAnimation() {
+ mDismissAnimation.start();
}
/**
- * Performs the "shrink and fade out from bottom" animation on the floating popup.
+ * Performs the "hide" animation on the floating popup.
*/
- private void shrinkFadeOutFromBottom() {
- mShrinkFadeOutFromBottomAnimation.start();
+ private void runHideAnimation() {
+ mHideAnimation.start();
}
- private void stopDismissAnimation() {
- mDismissAnimating = false;
- mShrinkFadeOutFromBottomAnimation.cancel();
+ private void cancelAllAnimations() {
+ mShowAnimation.cancel();
+ mDismissAnimation.cancel();
+ mHideAnimation.cancel();
+ mOpenOverflowAnimation.cancel();
+ mCloseOverflowAnimation.cancel();
}
/**
* Opens the floating toolbar overflow.
* This method should not be called if menu items have not been laid out with
- * {@link #layoutMenuItems(List, MenuItem.OnMenuItemClickListener, int)}.
+ * {@link #layoutMenuItems(java.util.List, MenuItem.OnMenuItemClickListener, int)}.
*
* @throws IllegalStateException if called when menu items have not been laid out.
*/
private void openOverflow() {
- Preconditions.checkNotNull(mMainPanel);
- Preconditions.checkNotNull(mOverflowPanel);
+ Preconditions.checkState(mMainPanel != null);
+ Preconditions.checkState(mOverflowPanel != null);
mMainPanel.fadeOut(true);
Size overflowPanelSize = mOverflowPanel.measure();
@@ -547,11 +620,11 @@ public final class FloatingToolbar {
widthAnimation.setDuration(240);
heightAnimation.setDuration(180);
heightAnimation.setStartOffset(60);
- AnimationSet animation = new AnimationSet(true);
- animation.setAnimationListener(mOnOverflowOpened);
- animation.addAnimation(widthAnimation);
- animation.addAnimation(heightAnimation);
- mContentContainer.startAnimation(animation);
+ mOpenOverflowAnimation.getAnimations().clear();
+ mOpenOverflowAnimation.setAnimationListener(mOnOverflowOpened);
+ mOpenOverflowAnimation.addAnimation(widthAnimation);
+ mOpenOverflowAnimation.addAnimation(heightAnimation);
+ mContentContainer.startAnimation(mOpenOverflowAnimation);
}
/**
@@ -559,11 +632,11 @@ public final class FloatingToolbar {
* This method should not be called if menu items have not been laid out with
* {@link #layoutMenuItems(java.util.List, MenuItem.OnMenuItemClickListener, int)}.
*
- * @throws IllegalStateException
+ * @throws IllegalStateException if called when menu items have not been laid out.
*/
private void closeOverflow() {
- Preconditions.checkNotNull(mMainPanel);
- Preconditions.checkNotNull(mOverflowPanel);
+ Preconditions.checkState(mMainPanel != null);
+ Preconditions.checkState(mOverflowPanel != null);
mOverflowPanel.fadeOut(true);
Size mainPanelSize = mMainPanel.measure();
@@ -599,58 +672,42 @@ public final class FloatingToolbar {
widthAnimation.setDuration(150);
widthAnimation.setStartOffset(150);
heightAnimation.setDuration(210);
- AnimationSet animation = new AnimationSet(true);
- animation.setAnimationListener(mOnOverflowClosed);
- animation.addAnimation(widthAnimation);
- animation.addAnimation(heightAnimation);
- mContentContainer.startAnimation(animation);
+ mCloseOverflowAnimation.getAnimations().clear();
+ mCloseOverflowAnimation.setAnimationListener(mOnOverflowClosed);
+ mCloseOverflowAnimation.addAnimation(widthAnimation);
+ mCloseOverflowAnimation.addAnimation(heightAnimation);
+ mContentContainer.startAnimation(mCloseOverflowAnimation);
}
/**
* Prepares the content container for show and update calls.
*/
private void preparePopupContent() {
- // Do not call this method if main view panel has not been initialized.
- Preconditions.checkNotNull(mMainPanel);
-
- // If we're yet to show the popup, set the container visibility to zero.
- // The "show" animation will make this visible.
- if (!mPopupWindow.isShowing()) {
- mContentContainer.setAlpha(0);
+ // Reset visibility.
+ if (mMainPanel != null) {
+ mMainPanel.fadeIn(false);
}
-
- // Make sure panels are visible.
- mMainPanel.fadeIn(false);
if (mOverflowPanel != null) {
mOverflowPanel.fadeIn(false);
}
- // Make sure a panel is set as the content.
- if (mContentContainer.getChildCount() == 0) {
- mContentContainer.addView(mMainPanel.getView());
+ // Reset position.
+ if (mMainPanel != null
+ && mContentContainer.getChildAt(0) == mMainPanel.getView()) {
+ positionMainPanel();
}
-
- // Make sure the main panel is at the correct position.
- if (mContentContainer.getChildAt(0) == mMainPanel.getView()) {
- float x = mPopupWindow.getWidth()
- - (mMainPanel.getView().getMeasuredWidth() + mMarginHorizontal);
- mContentContainer.setX(x);
-
- float y = mMarginVertical;
- if (mOverflowDirection == OVERFLOW_DIRECTION_UP) {
- y = getHeight()
- - (mMainPanel.getView().getMeasuredHeight() + mMarginVertical);
- }
- mContentContainer.setY(y);
+ if (mOverflowPanel != null
+ && mContentContainer.getChildAt(0) == mOverflowPanel.getView()) {
+ positionOverflowPanel();
}
-
- setContentAreaAsTouchableSurface();
}
/**
* Sets the current content to be the main view panel.
*/
private void setMainPanelAsContent() {
+ // This should never be called if the main panel has not been initialized.
+ Preconditions.checkNotNull(mMainPanel);
mContentContainer.removeAllViews();
Size mainPanelSize = mMainPanel.measure();
ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
@@ -658,6 +715,53 @@ public final class FloatingToolbar {
params.height = mainPanelSize.getHeight();
mContentContainer.setLayoutParams(params);
mContentContainer.addView(mMainPanel.getView());
+ setContentAreaAsTouchableSurface();
+ }
+
+ /**
+ * Sets the current content to be the overflow view panel.
+ */
+ private void setOverflowPanelAsContent() {
+ // This should never be called if the overflow panel has not been initialized.
+ Preconditions.checkNotNull(mOverflowPanel);
+ mContentContainer.removeAllViews();
+ Size overflowPanelSize = mOverflowPanel.measure();
+ ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
+ params.width = overflowPanelSize.getWidth();
+ params.height = overflowPanelSize.getHeight();
+ mContentContainer.setLayoutParams(params);
+ mContentContainer.addView(mOverflowPanel.getView());
+ setContentAreaAsTouchableSurface();
+ }
+
+ /**
+ * Places the main view panel at the appropriate resting coordinates.
+ */
+ private void positionMainPanel() {
+ Preconditions.checkNotNull(mMainPanel);
+ float x = mPopupWindow.getWidth()
+ - (mMainPanel.getView().getMeasuredWidth() + mMarginHorizontal);
+ mContentContainer.setX(x);
+
+ float y = mMarginVertical;
+ if (mOverflowDirection == OVERFLOW_DIRECTION_UP) {
+ y = getHeight()
+ - (mMainPanel.getView().getMeasuredHeight() + mMarginVertical);
+ }
+ mContentContainer.setY(y);
+ setContentAreaAsTouchableSurface();
+ }
+
+ /**
+ * Places the main view panel at the appropriate resting coordinates.
+ */
+ private void positionOverflowPanel() {
+ Preconditions.checkNotNull(mOverflowPanel);
+ float x = mPopupWindow.getWidth()
+ - (mOverflowPanel.getView().getMeasuredWidth() + mMarginHorizontal);
+ mContentContainer.setX(x);
+ mContentContainer.setY(mMarginVertical);
+ setContentAreaAsTouchableSurface();
}
private void updatePopupSize() {
@@ -1026,6 +1130,7 @@ public final class FloatingToolbar {
}
public void fadeIn(boolean animate) {
+ cancelFadeAnimations();
if (animate) {
mFadeInAnimation.start();
} else {
@@ -1034,12 +1139,18 @@ public final class FloatingToolbar {
}
public void fadeOut(boolean animate) {
+ cancelFadeAnimations();
if (animate) {
mFadeOutAnimation.start();
} else {
mView.setAlpha(0);
}
}
+
+ private void cancelFadeAnimations() {
+ mFadeInAnimation.cancel();
+ mFadeOutAnimation.cancel();
+ }
}
@@ -1070,7 +1181,8 @@ public final class FloatingToolbar {
private static PopupWindow createPopupWindow(View content) {
ViewGroup popupContentHolder = new LinearLayout(content.getContext());
PopupWindow popupWindow = new PopupWindow(popupContentHolder);
- popupWindow.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
+ popupWindow.setWindowLayoutType(
+ WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL);
popupWindow.setAnimationStyle(0);
popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
content.setLayoutParams(new ViewGroup.LayoutParams(
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 123d1ac..1096e34 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -24,7 +24,6 @@ import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
import android.os.AsyncTask;
import android.os.IBinder;
import android.os.RemoteException;
@@ -32,7 +31,6 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
-import android.os.UserManager;
import android.os.storage.IMountService;
import android.os.storage.StorageManager;
import android.provider.Settings;
@@ -472,6 +470,8 @@ public class LockPatternUtils {
updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
}
+ setCredentialRequiredToDecrypt(false);
+
getDevicePolicyManager().setActivePasswordState(
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, userHandle);
@@ -542,8 +542,7 @@ public class LockPatternUtils {
// Update the device encryption password.
if (userId == UserHandle.USER_OWNER
&& LockPatternUtils.isDeviceEncryptionEnabled()) {
- final boolean required = isCredentialRequiredToDecrypt(true);
- if (!required) {
+ if (!shouldEncryptWithCredentials(true)) {
clearEncryptionPassword();
} else {
String stringPattern = patternToString(pattern);
@@ -757,7 +756,7 @@ public class LockPatternUtils {
// Update the device encryption password.
if (userHandle == UserHandle.USER_OWNER
&& LockPatternUtils.isDeviceEncryptionEnabled()) {
- if (!isCredentialRequiredToDecrypt(true)) {
+ if (!shouldEncryptWithCredentials(true)) {
clearEncryptionPassword();
} else {
boolean numeric = computedQuality
@@ -1236,4 +1235,12 @@ public class LockPatternUtils {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0);
}
+
+ private boolean isDoNotAskCredentialsOnBootSet() {
+ return mDevicePolicyManager.getDoNotAskCredentialsOnBoot();
+ }
+
+ private boolean shouldEncryptWithCredentials(boolean defaultValue) {
+ return isCredentialRequiredToDecrypt(defaultValue) && !isDoNotAskCredentialsOnBootSet();
+ }
}
diff --git a/core/java/com/android/internal/widget/SlidingTab.java b/core/java/com/android/internal/widget/SlidingTab.java
index 65feab1..0066ed0 100644
--- a/core/java/com/android/internal/widget/SlidingTab.java
+++ b/core/java/com/android/internal/widget/SlidingTab.java
@@ -400,11 +400,13 @@ public class SlidingTab extends ViewGroup {
/**
* Ensure all the dependent widgets are measured.
*/
- public void measure() {
- tab.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
- View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
- text.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
- View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
+ public void measure(int widthMeasureSpec, int heightMeasureSpec) {
+ int width = MeasureSpec.getSize(widthMeasureSpec);
+ int height = MeasureSpec.getSize(heightMeasureSpec);
+ tab.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.UNSPECIFIED),
+ View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.UNSPECIFIED));
+ text.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.UNSPECIFIED),
+ View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.UNSPECIFIED));
}
/**
@@ -491,8 +493,8 @@ public class SlidingTab extends ViewGroup {
}
}
- mLeftSlider.measure();
- mRightSlider.measure();
+ mLeftSlider.measure(widthMeasureSpec, heightMeasureSpec);
+ mRightSlider.measure(widthMeasureSpec, heightMeasureSpec);
final int leftTabWidth = mLeftSlider.getTabWidth();
final int rightTabWidth = mRightSlider.getTabWidth();
final int leftTabHeight = mLeftSlider.getTabHeight();
diff --git a/core/java/com/android/server/backup/NotificationBackupHelper.java b/core/java/com/android/server/backup/NotificationBackupHelper.java
new file mode 100644
index 0000000..6f5c7e8
--- /dev/null
+++ b/core/java/com/android/server/backup/NotificationBackupHelper.java
@@ -0,0 +1,76 @@
+/*
+ * 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.server.backup;
+
+import android.app.INotificationManager;
+import android.app.backup.BlobBackupHelper;
+import android.content.Context;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+
+public class NotificationBackupHelper extends BlobBackupHelper {
+ static final String TAG = "NotifBackupHelper"; // must be < 23 chars
+ static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ // Current version of the blob schema
+ static final int BLOB_VERSION = 1;
+
+ // Key under which the payload blob is stored
+ static final String KEY_NOTIFICATIONS = "notifications";
+
+ public NotificationBackupHelper(Context context) {
+ super(BLOB_VERSION, KEY_NOTIFICATIONS);
+ // context is currently unused
+ }
+
+ @Override
+ protected byte[] getBackupPayload(String key) {
+ byte[] newPayload = null;
+ if (KEY_NOTIFICATIONS.equals(key)) {
+ try {
+ INotificationManager nm = INotificationManager.Stub.asInterface(
+ ServiceManager.getService("notification"));
+ newPayload = nm.getBackupPayload(UserHandle.USER_OWNER);
+ } catch (Exception e) {
+ // Treat as no data
+ Slog.e(TAG, "Couldn't communicate with notification manager");
+ newPayload = null;
+ }
+ }
+ return newPayload;
+ }
+
+ @Override
+ protected void applyRestoredPayload(String key, byte[] payload) {
+ if (DEBUG) {
+ Slog.v(TAG, "Got restore of " + key);
+ }
+
+ if (KEY_NOTIFICATIONS.equals(key)) {
+ try {
+ INotificationManager nm = INotificationManager.Stub.asInterface(
+ ServiceManager.getService("notification"));
+ nm.applyRestore(payload, UserHandle.USER_OWNER);
+ } catch (Exception e) {
+ Slog.e(TAG, "Couldn't communicate with notification manager");
+ }
+ }
+ }
+
+}
diff --git a/core/java/com/android/server/backup/PreferredActivityBackupHelper.java b/core/java/com/android/server/backup/PreferredActivityBackupHelper.java
index 6ac0d89..26f5bf4 100644
--- a/core/java/com/android/server/backup/PreferredActivityBackupHelper.java
+++ b/core/java/com/android/server/backup/PreferredActivityBackupHelper.java
@@ -17,159 +17,58 @@
package com.android.server.backup;
import android.app.AppGlobals;
-import android.app.backup.BackupDataInputStream;
-import android.app.backup.BackupDataOutput;
-import android.app.backup.BackupHelper;
-import android.content.Context;
+import android.app.backup.BlobBackupHelper;
import android.content.pm.IPackageManager;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.Slog;
-import android.util.Xml;
-import com.android.internal.util.FastXmlSerializer;
-import com.android.org.bouncycastle.util.Arrays;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.EOFException;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-public class PreferredActivityBackupHelper implements BackupHelper {
+public class PreferredActivityBackupHelper extends BlobBackupHelper {
private static final String TAG = "PreferredBackup";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
// current schema of the backup state blob
- private static final int STATE_VERSION = 1;
+ private static final int STATE_VERSION = 2;
// key under which the preferred-activity state blob is committed to backup
private static final String KEY_PREFERRED = "preferred-activity";
- final Context mContext;
-
- public PreferredActivityBackupHelper(Context context) {
- mContext = context;
- }
-
- // The fds passed here are shared among all helpers, so we mustn't close them
- private void writeState(ParcelFileDescriptor stateFile, byte[] payload) {
- try {
- FileOutputStream fos = new FileOutputStream(stateFile.getFileDescriptor());
-
- // We explicitly don't close 'out' because we must not close the backing fd.
- // The FileOutputStream will not close it implicitly.
- @SuppressWarnings("resource")
- DataOutputStream out = new DataOutputStream(fos);
-
- out.writeInt(STATE_VERSION);
- if (payload == null) {
- out.writeInt(0);
- } else {
- out.writeInt(payload.length);
- out.write(payload);
- }
- } catch (IOException e) {
- Slog.e(TAG, "Unable to write updated state", e);
- }
- }
-
- private byte[] readState(ParcelFileDescriptor oldStateFd) {
- FileInputStream fis = new FileInputStream(oldStateFd.getFileDescriptor());
- BufferedInputStream bis = new BufferedInputStream(fis);
-
- @SuppressWarnings("resource")
- DataInputStream in = new DataInputStream(bis);
-
- byte[] oldState = null;
- try {
- int version = in.readInt();
- if (version == STATE_VERSION) {
- int size = in.readInt();
- if (size > 0) {
- if (size > 200*1024) {
- Slog.w(TAG, "Suspiciously large state blog; ignoring. N=" + size);
- } else {
- // size looks okay; make the return buffer and fill it
- oldState = new byte[size];
- in.read(oldState);
- }
- }
- } else {
- Slog.w(TAG, "Prior state from unrecognized version " + version);
- }
- } catch (EOFException e) {
- // Empty file is expected on first backup, so carry on. If the state
- // is truncated we just treat it the same way.
- oldState = null;
- } catch (Exception e) {
- Slog.w(TAG, "Error examing prior backup state " + e.getMessage());
- oldState = null;
- }
-
- return oldState;
+ public PreferredActivityBackupHelper() {
+ super(STATE_VERSION, KEY_PREFERRED);
}
@Override
- public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
- ParcelFileDescriptor newState) {
- byte[] payload = null;
- try {
- byte[] oldPayload = readState(oldState);
-
+ protected byte[] getBackupPayload(String key) {
+ if (KEY_PREFERRED.equals(key)) {
+ if (DEBUG) {
+ Slog.v(TAG, "Checking whether to back up");
+ }
IPackageManager pm = AppGlobals.getPackageManager();
- byte[] newPayload = pm.getPreferredActivityBackup(UserHandle.USER_OWNER);
- if (!Arrays.areEqual(oldPayload, newPayload)) {
- if (DEBUG) {
- Slog.i(TAG, "State has changed => writing new preferred app payload");
- }
- data.writeEntityHeader(KEY_PREFERRED, newPayload.length);
- data.writeEntityData(newPayload, newPayload.length);
- } else {
- if (DEBUG) {
- Slog.i(TAG, "No change to state => not writing to wire");
- }
+ try {
+ return pm.getPreferredActivityBackup(UserHandle.USER_OWNER);
+ } catch (Exception e) {
+ Slog.e(TAG, "Unable to store backup payload", e);
+ // fall through to report null state
}
-
- // Always need to re-record the state, even if nothing changed
- payload = newPayload;
- } catch (Exception e) {
- // On failures we'll wind up committing a zero-size state payload. This is
- // a forward-safe situation because we know we commit the entire new payload
- // on prior-state mismatch.
- Slog.w(TAG, "Unable to record preferred activities", e);
- } finally {
- writeState(newState, payload);
+ } else {
+ Slog.w(TAG, "Unexpected backup key " + key);
}
+ return null;
}
@Override
- public void restoreEntity(BackupDataInputStream data) {
- IPackageManager pm = AppGlobals.getPackageManager();
- try {
- byte[] payload = new byte[data.size()];
- data.read(payload);
+ protected void applyRestoredPayload(String key, byte[] payload) {
+ if (KEY_PREFERRED.equals(key)) {
if (DEBUG) {
- Slog.i(TAG, "Restoring preferred activities; size=" + payload.length);
+ Slog.v(TAG, "Restoring");
}
- pm.restorePreferredActivities(payload, UserHandle.USER_OWNER);
- } catch (Exception e) {
- Slog.e(TAG, "Exception reading restore data", e);
+ IPackageManager pm = AppGlobals.getPackageManager();
+ try {
+ pm.restorePreferredActivities(payload, UserHandle.USER_OWNER);
+ } catch (Exception e) {
+ Slog.e(TAG, "Unable to restore", e);
+ }
+ } else {
+ Slog.w(TAG, "Unexpected restore key " + key);
}
}
-
- @Override
- public void writeNewStateDescription(ParcelFileDescriptor newState) {
- writeState(newState, null);
- }
-
}
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index 19d9e29..a80abce 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -48,6 +48,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
private static final String RECENTS_HELPER = "recents";
private static final String SYNC_SETTINGS_HELPER = "account_sync_settings";
private static final String PREFERRED_HELPER = "preferred_activities";
+ private static final String NOTIFICATION_HELPER = "notifications";
// These paths must match what the WallpaperManagerService uses. The leaf *_FILENAME
// are also used in the full-backup file format, so must not change unless steps are
@@ -93,7 +94,8 @@ public class SystemBackupAgent extends BackupAgentHelper {
addHelper(WALLPAPER_HELPER, new WallpaperBackupHelper(this, files, keys));
addHelper(RECENTS_HELPER, new RecentsBackupHelper(this));
addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this));
- addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper(this));
+ addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper());
+ addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this));
super.onBackup(oldState, data, newState);
}
@@ -127,7 +129,8 @@ public class SystemBackupAgent extends BackupAgentHelper {
new String[] { WALLPAPER_IMAGE_KEY} ));
addHelper(RECENTS_HELPER, new RecentsBackupHelper(this));
addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this));
- addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper(this));
+ addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper());
+ addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this));
try {
super.onRestore(data, appVersionCode, newState);