summaryrefslogtreecommitdiffstats
path: root/core/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android')
-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
89 files changed, 2119 insertions, 890 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();
+ }
}
}
}