Merge "Fix QS FBE-ness" into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index f50fc30..a5d8a93 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -944,6 +944,8 @@
field public static final int popupBackground = 16843126; // 0x1010176
field public static final int popupCharacters = 16843332; // 0x1010244
field public static final int popupElevation = 16843916; // 0x101048c
+ field public static final int popupEnterTransition = 16844065; // 0x1010521
+ field public static final int popupExitTransition = 16844066; // 0x1010522
field public static final int popupKeyboard = 16843331; // 0x1010243
field public static final int popupLayout = 16843323; // 0x101023b
field public static final int popupMenuStyle = 16843520; // 0x1010300
@@ -2754,14 +2756,10 @@
}
public final class GestureDescription {
- method public static android.accessibilityservice.GestureDescription createClick(int, int);
- method public static android.accessibilityservice.GestureDescription createLongClick(int, int);
- method public static android.accessibilityservice.GestureDescription createPinch(int, int, int, int, float, long);
- method public static android.accessibilityservice.GestureDescription createSwipe(int, int, int, int, long);
+ method public static long getMaxGestureDuration();
+ method public static int getMaxStrokeCount();
method public android.accessibilityservice.GestureDescription.StrokeDescription getStroke(int);
method public int getStrokeCount();
- field public static final long MAX_GESTURE_DURATION_MS = 60000L; // 0xea60L
- field public static final int MAX_STROKE_COUNT = 10; // 0xa
}
public static class GestureDescription.Builder {
@@ -8019,8 +8017,6 @@
method public abstract java.lang.String getPackageResourcePath();
method public abstract android.content.res.Resources getResources();
method public abstract android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
- method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
- method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
method public final java.lang.String getString(int);
method public final java.lang.String getString(int, java.lang.Object...);
method public abstract java.lang.Object getSystemService(java.lang.String);
@@ -29598,6 +29594,7 @@
method public java.lang.String getMountedObbPath(java.lang.String);
method public android.os.storage.StorageVolume getPrimaryVolume();
method public android.os.storage.StorageVolume[] getVolumeList();
+ method public boolean isEncrypted(java.io.File);
method public boolean isObbMounted(java.lang.String);
method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
@@ -47197,6 +47194,8 @@
method public android.graphics.drawable.Drawable getBackground();
method public android.view.View getContentView();
method public float getElevation();
+ method public android.transition.Transition getEnterTransition();
+ method public android.transition.Transition getExitTransition();
method public int getHeight();
method public int getInputMethodMode();
method public int getMaxAvailableHeight(android.view.View);
@@ -50690,6 +50689,7 @@
method public float floatValue();
method public static int hashCode(double);
method public int intValue();
+ method public static boolean isFinite(double);
method public static boolean isInfinite(double);
method public boolean isInfinite();
method public static boolean isNaN(double);
@@ -50771,6 +50771,7 @@
method public float floatValue();
method public static float intBitsToFloat(int);
method public int intValue();
+ method public static boolean isFinite(float);
method public static boolean isInfinite(float);
method public boolean isInfinite();
method public static boolean isNaN(float);
diff --git a/api/removed.txt b/api/removed.txt
index 9b5d3ab..36c8ce5 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -22,6 +22,8 @@
public abstract class Context {
method public deprecated android.content.Context createCredentialEncryptedStorageContext();
method public deprecated android.content.Context createDeviceEncryptedStorageContext();
+ method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
+ method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
method public deprecated boolean isCredentialEncryptedStorage();
method public deprecated boolean isDeviceEncryptedStorage();
method public deprecated boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
diff --git a/api/system-current.txt b/api/system-current.txt
index 00603bb..97b7710 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1039,6 +1039,8 @@
field public static final int popupBackground = 16843126; // 0x1010176
field public static final int popupCharacters = 16843332; // 0x1010244
field public static final int popupElevation = 16843916; // 0x101048c
+ field public static final int popupEnterTransition = 16844065; // 0x1010521
+ field public static final int popupExitTransition = 16844066; // 0x1010522
field public static final int popupKeyboard = 16843331; // 0x1010243
field public static final int popupLayout = 16843323; // 0x101023b
field public static final int popupMenuStyle = 16843520; // 0x1010300
@@ -2856,14 +2858,10 @@
}
public final class GestureDescription {
- method public static android.accessibilityservice.GestureDescription createClick(int, int);
- method public static android.accessibilityservice.GestureDescription createLongClick(int, int);
- method public static android.accessibilityservice.GestureDescription createPinch(int, int, int, int, float, long);
- method public static android.accessibilityservice.GestureDescription createSwipe(int, int, int, int, long);
+ method public static long getMaxGestureDuration();
+ method public static int getMaxStrokeCount();
method public android.accessibilityservice.GestureDescription.StrokeDescription getStroke(int);
method public int getStrokeCount();
- field public static final long MAX_GESTURE_DURATION_MS = 60000L; // 0xea60L
- field public static final int MAX_STROKE_COUNT = 10; // 0xa
}
public static class GestureDescription.Builder {
@@ -8318,8 +8316,6 @@
method public abstract java.lang.String getPackageResourcePath();
method public abstract android.content.res.Resources getResources();
method public abstract android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
- method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
- method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
method public final java.lang.String getString(int);
method public final java.lang.String getString(int, java.lang.Object...);
method public abstract java.lang.Object getSystemService(java.lang.String);
@@ -31911,6 +31907,7 @@
method public java.lang.String getMountedObbPath(java.lang.String);
method public android.os.storage.StorageVolume getPrimaryVolume();
method public android.os.storage.StorageVolume[] getVolumeList();
+ method public boolean isEncrypted(java.io.File);
method public boolean isObbMounted(java.lang.String);
method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
@@ -50261,6 +50258,8 @@
method public android.graphics.drawable.Drawable getBackground();
method public android.view.View getContentView();
method public float getElevation();
+ method public android.transition.Transition getEnterTransition();
+ method public android.transition.Transition getExitTransition();
method public int getHeight();
method public int getInputMethodMode();
method public int getMaxAvailableHeight(android.view.View);
@@ -53754,6 +53753,7 @@
method public float floatValue();
method public static int hashCode(double);
method public int intValue();
+ method public static boolean isFinite(double);
method public static boolean isInfinite(double);
method public boolean isInfinite();
method public static boolean isNaN(double);
@@ -53835,6 +53835,7 @@
method public float floatValue();
method public static float intBitsToFloat(int);
method public int intValue();
+ method public static boolean isFinite(float);
method public static boolean isInfinite(float);
method public boolean isInfinite();
method public static boolean isNaN(float);
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 8bf59df..d48b9b3 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -20,6 +20,8 @@
public abstract class Context {
method public deprecated android.content.Context createCredentialEncryptedStorageContext();
method public deprecated android.content.Context createDeviceEncryptedStorageContext();
+ method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
+ method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
method public deprecated boolean isCredentialEncryptedStorage();
method public deprecated boolean isDeviceEncryptedStorage();
method public deprecated boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
diff --git a/api/test-current.txt b/api/test-current.txt
index c4b01db..fa2669c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -944,6 +944,8 @@
field public static final int popupBackground = 16843126; // 0x1010176
field public static final int popupCharacters = 16843332; // 0x1010244
field public static final int popupElevation = 16843916; // 0x101048c
+ field public static final int popupEnterTransition = 16844065; // 0x1010521
+ field public static final int popupExitTransition = 16844066; // 0x1010522
field public static final int popupKeyboard = 16843331; // 0x1010243
field public static final int popupLayout = 16843323; // 0x101023b
field public static final int popupMenuStyle = 16843520; // 0x1010300
@@ -2754,14 +2756,10 @@
}
public final class GestureDescription {
- method public static android.accessibilityservice.GestureDescription createClick(int, int);
- method public static android.accessibilityservice.GestureDescription createLongClick(int, int);
- method public static android.accessibilityservice.GestureDescription createPinch(int, int, int, int, float, long);
- method public static android.accessibilityservice.GestureDescription createSwipe(int, int, int, int, long);
+ method public static long getMaxGestureDuration();
+ method public static int getMaxStrokeCount();
method public android.accessibilityservice.GestureDescription.StrokeDescription getStroke(int);
method public int getStrokeCount();
- field public static final long MAX_GESTURE_DURATION_MS = 60000L; // 0xea60L
- field public static final int MAX_STROKE_COUNT = 10; // 0xa
}
public static class GestureDescription.Builder {
@@ -8024,8 +8022,6 @@
method public abstract java.lang.String getPackageResourcePath();
method public abstract android.content.res.Resources getResources();
method public abstract android.content.SharedPreferences getSharedPreferences(java.lang.String, int);
- method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
- method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
method public final java.lang.String getString(int);
method public final java.lang.String getString(int, java.lang.Object...);
method public abstract java.lang.Object getSystemService(java.lang.String);
@@ -29664,6 +29660,7 @@
method public java.lang.String getMountedObbPath(java.lang.String);
method public android.os.storage.StorageVolume getPrimaryVolume();
method public android.os.storage.StorageVolume[] getVolumeList();
+ method public boolean isEncrypted(java.io.File);
method public boolean isObbMounted(java.lang.String);
method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
@@ -47270,6 +47267,8 @@
method public android.graphics.drawable.Drawable getBackground();
method public android.view.View getContentView();
method public float getElevation();
+ method public android.transition.Transition getEnterTransition();
+ method public android.transition.Transition getExitTransition();
method public int getHeight();
method public int getInputMethodMode();
method public int getMaxAvailableHeight(android.view.View);
@@ -50763,6 +50762,7 @@
method public float floatValue();
method public static int hashCode(double);
method public int intValue();
+ method public static boolean isFinite(double);
method public static boolean isInfinite(double);
method public boolean isInfinite();
method public static boolean isNaN(double);
@@ -50844,6 +50844,7 @@
method public float floatValue();
method public static float intBitsToFloat(int);
method public int intValue();
+ method public static boolean isFinite(float);
method public static boolean isInfinite(float);
method public boolean isInfinite();
method public static boolean isNaN(float);
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 9b5d3ab..36c8ce5 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -22,6 +22,8 @@
public abstract class Context {
method public deprecated android.content.Context createCredentialEncryptedStorageContext();
method public deprecated android.content.Context createDeviceEncryptedStorageContext();
+ method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
+ method public abstract java.io.File getSharedPreferencesPath(java.lang.String);
method public deprecated boolean isCredentialEncryptedStorage();
method public deprecated boolean isDeviceEncryptedStorage();
method public deprecated boolean migrateDatabaseFrom(android.content.Context, java.lang.String);
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index ac3b8e3..ddc5b0c 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -851,6 +851,7 @@
return connection.getMagnificationScale();
} catch (RemoteException re) {
Log.w(LOG_TAG, "Failed to obtain scale", re);
+ re.rethrowFromSystemServer();
}
}
return 1.0f;
@@ -879,6 +880,7 @@
return connection.getMagnificationCenterX();
} catch (RemoteException re) {
Log.w(LOG_TAG, "Failed to obtain center X", re);
+ re.rethrowFromSystemServer();
}
}
return 0.0f;
@@ -907,6 +909,7 @@
return connection.getMagnificationCenterY();
} catch (RemoteException re) {
Log.w(LOG_TAG, "Failed to obtain center Y", re);
+ re.rethrowFromSystemServer();
}
}
return 0.0f;
@@ -933,6 +936,7 @@
return connection.getMagnifiedRegion();
} catch (RemoteException re) {
Log.w(LOG_TAG, "Failed to obtain magnified region", re);
+ re.rethrowFromSystemServer();
}
}
return Region.obtain();
@@ -961,6 +965,7 @@
return connection.resetMagnification(animate);
} catch (RemoteException re) {
Log.w(LOG_TAG, "Failed to reset", re);
+ re.rethrowFromSystemServer();
}
}
return false;
@@ -989,6 +994,7 @@
scale, Float.NaN, Float.NaN, animate);
} catch (RemoteException re) {
Log.w(LOG_TAG, "Failed to set scale", re);
+ re.rethrowFromSystemServer();
}
}
return false;
@@ -1020,6 +1026,7 @@
Float.NaN, centerX, centerY, animate);
} catch (RemoteException re) {
Log.w(LOG_TAG, "Failed to set center", re);
+ re.rethrowFromSystemServer();
}
}
return false;
@@ -1254,10 +1261,7 @@
Log.w(LOG_TAG, "Failed to set soft keyboard behavior", re);
re.rethrowFromSystemServer();
}
- } else {
- throw new RuntimeException("AccessibilityServiceConnection is null");
}
-
return false;
}
@@ -1301,6 +1305,7 @@
return connection.performGlobalAction(action);
} catch (RemoteException re) {
Log.w(LOG_TAG, "Error while calling performGlobalAction", re);
+ re.rethrowFromSystemServer();
}
}
return false;
@@ -1349,6 +1354,7 @@
return connection.getServiceInfo();
} catch (RemoteException re) {
Log.w(LOG_TAG, "Error while getting AccessibilityServiceInfo", re);
+ re.rethrowFromSystemServer();
}
}
return null;
@@ -1382,6 +1388,7 @@
AccessibilityInteractionClient.getInstance().clearCache();
} catch (RemoteException re) {
Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfo", re);
+ re.rethrowFromSystemServer();
}
}
}
diff --git a/core/java/android/accessibilityservice/GestureDescription.java b/core/java/android/accessibilityservice/GestureDescription.java
index 14aabcf..7a0c89b 100644
--- a/core/java/android/accessibilityservice/GestureDescription.java
+++ b/core/java/android/accessibilityservice/GestureDescription.java
@@ -43,135 +43,32 @@
*/
public final class GestureDescription {
/** Gestures may contain no more than this many strokes */
- public static final int MAX_STROKE_COUNT = 10;
+ private static final int MAX_STROKE_COUNT = 10;
/**
* Upper bound on total gesture duration. Nearly all gestures will be much shorter.
*/
- public static final long MAX_GESTURE_DURATION_MS = 60 * 1000;
+ private static final long MAX_GESTURE_DURATION_MS = 60 * 1000;
private final List<StrokeDescription> mStrokes = new ArrayList<>();
private final float[] mTempPos = new float[2];
/**
- * Create a description of a click gesture
+ * Get the upper limit for the number of strokes a gesture may contain.
*
- * @param x The x coordinate to click. Must not be negative.
- * @param y The y coordinate to click. Must not be negative.
- *
- * @return A description of a click at (x, y)
+ * @return The maximum number of strokes.
*/
- public static GestureDescription createClick(@IntRange(from = 0) int x,
- @IntRange(from = 0) int y) {
- Path clickPath = new Path();
- clickPath.moveTo(x, y);
- clickPath.lineTo(x + 1, y);
- return new GestureDescription(
- new StrokeDescription(clickPath, 0, ViewConfiguration.getTapTimeout()));
+ public static int getMaxStrokeCount() {
+ return MAX_STROKE_COUNT;
}
/**
- * Create a description of a long click gesture
+ * Get the upper limit on a gesture's duration.
*
- * @param x The x coordinate to click. Must not be negative.
- * @param y The y coordinate to click. Must not be negative.
- *
- * @return A description of a click at (x, y)
+ * @return The maximum duration in milliseconds.
*/
- public static GestureDescription createLongClick(@IntRange(from = 0) int x,
- @IntRange(from = 0) int y) {
- Path clickPath = new Path();
- clickPath.moveTo(x, y);
- clickPath.lineTo(x + 1, y);
- int longPressTime = ViewConfiguration.getLongPressTimeout();
- return new GestureDescription(
- new StrokeDescription(clickPath, 0, longPressTime + (longPressTime / 2)));
- }
-
- /**
- * Create a description of a swipe gesture
- *
- * @param startX The x coordinate of the starting point. Must not be negative.
- * @param startY The y coordinate of the starting point. Must not be negative.
- * @param endX The x coordinate of the ending point. Must not be negative.
- * @param endY The y coordinate of the ending point. Must not be negative.
- * @param duration The time, in milliseconds, to complete the gesture. Must not be negative.
- *
- * @return A description of a swipe from ({@code startX}, {@code startY}) to
- * ({@code endX}, {@code endY}) that takes {@code duration} milliseconds. Returns {@code null}
- * if the path specified for the swipe is invalid.
- */
- public static GestureDescription createSwipe(@IntRange(from = 0) int startX,
- @IntRange(from = 0) int startY,
- @IntRange(from = 0) int endX,
- @IntRange(from = 0) int endY,
- @IntRange(from = 0, to = MAX_GESTURE_DURATION_MS) long duration) {
- Path swipePath = new Path();
- swipePath.moveTo(startX, startY);
- swipePath.lineTo(endX, endY);
- return new GestureDescription(new StrokeDescription(swipePath, 0, duration));
- }
-
- /**
- * Create a description for a pinch (or zoom) gesture.
- *
- * @param centerX The x coordinate of the center of the pinch. Must not be negative.
- * @param centerY The y coordinate of the center of the pinch. Must not be negative.
- * @param startSpacing The spacing of the touch points at the beginning of the gesture. Must not
- * be negative.
- * @param endSpacing The spacing of the touch points at the end of the gesture. Must not be
- * negative.
- * @param orientation The angle, in degrees, of the gesture. 0 represents a horizontal pinch
- * @param duration The time, in milliseconds, to complete the gesture. Must not be negative.
- *
- * @return A description of a pinch centered at ({code centerX}, {@code centerY}) that starts
- * with the touch points spaced by {@code startSpacing} and ends with them spaced by
- * {@code endSpacing} that lasts {@code duration} ms. Returns {@code null} if either path
- * specified for the pinch is invalid.
- */
- public static GestureDescription createPinch(@IntRange(from = 0) int centerX,
- @IntRange(from = 0) int centerY,
- @IntRange(from = 0) int startSpacing,
- @IntRange(from = 0) int endSpacing,
- float orientation,
- @IntRange(from = 0, to = MAX_GESTURE_DURATION_MS) long duration) {
- if ((startSpacing < 0) || (endSpacing < 0)) {
- throw new IllegalArgumentException("Pinch spacing cannot be negative");
- }
- float[] startPoint1 = new float[2];
- float[] endPoint1 = new float[2];
- float[] startPoint2 = new float[2];
- float[] endPoint2 = new float[2];
-
- /* Build points for a horizontal gesture centered at the origin */
- startPoint1[0] = startSpacing / 2;
- startPoint1[1] = 0;
- endPoint1[0] = endSpacing / 2;
- endPoint1[1] = 0;
- startPoint2[0] = -startSpacing / 2;
- startPoint2[1] = 0;
- endPoint2[0] = -endSpacing / 2;
- endPoint2[1] = 0;
-
- /* Rotate and translate the points */
- Matrix matrix = new Matrix();
- matrix.setRotate(orientation);
- matrix.postTranslate(centerX, centerY);
- matrix.mapPoints(startPoint1);
- matrix.mapPoints(endPoint1);
- matrix.mapPoints(startPoint2);
- matrix.mapPoints(endPoint2);
-
- Path path1 = new Path();
- path1.moveTo(startPoint1[0], startPoint1[1]);
- path1.lineTo(endPoint1[0], endPoint1[1]);
- Path path2 = new Path();
- path2.moveTo(startPoint2[0], startPoint2[1]);
- path2.lineTo(endPoint2[0], endPoint2[1]);
-
- return new GestureDescription(Arrays.asList(
- new StrokeDescription(path1, 0, duration),
- new StrokeDescription(path2, 0, duration)));
+ public static long getMaxGestureDuration() {
+ return MAX_GESTURE_DURATION_MS;
}
private GestureDescription() {}
@@ -180,10 +77,6 @@
mStrokes.addAll(strokes);
}
- private GestureDescription(StrokeDescription stroke) {
- mStrokes.add(stroke);
- }
-
/**
* Get the number of stroke in the gesture.
*
@@ -278,21 +171,23 @@
*/
public Builder addStroke(@NonNull StrokeDescription strokeDescription) {
if (mStrokes.size() >= MAX_STROKE_COUNT) {
- throw new RuntimeException("Attempting to add too many strokes to a gesture");
+ throw new IllegalStateException(
+ "Attempting to add too many strokes to a gesture");
}
mStrokes.add(strokeDescription);
if (getTotalDuration(mStrokes) > MAX_GESTURE_DURATION_MS) {
mStrokes.remove(strokeDescription);
- throw new RuntimeException("Gesture would exceed maximum duration with new stroke");
+ throw new IllegalStateException(
+ "Gesture would exceed maximum duration with new stroke");
}
return this;
}
public GestureDescription build() {
if (mStrokes.size() == 0) {
- throw new RuntimeException("Gestures must have at least one stroke");
+ throw new IllegalStateException("Gestures must have at least one stroke");
}
return new GestureDescription(mStrokes);
}
@@ -317,8 +212,8 @@
* Must not be negative.
*/
public StrokeDescription(@NonNull Path path,
- @IntRange(from = 0, to = MAX_GESTURE_DURATION_MS) long startTime,
- @IntRange(from = 0, to = MAX_GESTURE_DURATION_MS) long duration) {
+ @IntRange(from = 0) long startTime,
+ @IntRange(from = 0) long duration) {
if (duration <= 0) {
throw new IllegalArgumentException("Duration must be positive");
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 33fd1db..13e8e75 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.IntDef;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
@@ -49,6 +50,8 @@
import com.android.internal.content.ReferrerIntent;
import java.io.File;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
@@ -78,7 +81,15 @@
public static final String REPORT_KEY_STREAMRESULT = "stream";
private static final String TAG = "Instrumentation";
-
+
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({0, UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES})
+ public @interface UiAutomationFlags {};
+
+
private final Object mSync = new Object();
private ActivityThread mThread = null;
private MessageQueue mMessageQueue = null;
@@ -1876,7 +1887,7 @@
*
* @see UiAutomation
*/
- public UiAutomation getUiAutomation(int flags) {
+ public UiAutomation getUiAutomation(@UiAutomationFlags int flags) {
if (mUiAutomationConnection != null) {
if ((mUiAutomation == null) || (mUiAutomation.isDestroyed())) {
mUiAutomation = new UiAutomation(getTargetContext().getMainLooper(),
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ca19b9b..15cc17d 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -691,6 +691,7 @@
*
* @see #getSharedPreferencesPath(String)
* @see #MODE_PRIVATE
+ * @removed
*/
public abstract SharedPreferences getSharedPreferences(File file, int mode);
@@ -813,17 +814,16 @@
* to get a path.
* @return An absolute path to the given file.
* @see #getSharedPreferences(String, int)
+ * @removed
*/
public abstract File getSharedPreferencesPath(String name);
/**
* Returns the absolute path to the directory on the filesystem where all
- * private files belonging to this app are stored. This is the top-level
- * directory under which {@link #getFilesDir()}, {@link #getCacheDir()}, etc
- * are contained. Apps should <em>not</em> create any files or directories
- * as direct children of this directory, since it's a reserved namespace
- * belonging to the platform. Instead, use {@link #getDir(String, int)} or
- * other storage APIs.
+ * private files belonging to this app are stored. Apps should not use this
+ * path directly; they should instead use {@link #getFilesDir()},
+ * {@link #getCacheDir()}, {@link #getDir(String, int)}, or other storage
+ * APIs on this class.
* <p>
* The returned path may change over time if the calling app is moved to an
* adopted storage device, so only relative paths should be persisted.
@@ -831,7 +831,7 @@
* No additional permissions are required for the calling app to read or
* write files under the returned path.
*
- * @see #getDir(String, int)
+ * @see ApplicationInfo#dataDir
*/
public abstract File getDataDir();
@@ -4168,7 +4168,7 @@
* Return a new Context object for the current Context but whose storage
* APIs are backed by device-protected storage.
* <p>
- * When a device is encrypted, data stored in this location is encrypted
+ * On devices with direct boot, data stored in this location is encrypted
* with a key tied to the physical device, and it can be accessed
* immediately after the device has booted successfully, both
* <em>before and after</em> the user has authenticated with their
@@ -4206,7 +4206,7 @@
* storage area for apps unless
* {@link android.R.attr#defaultToDeviceProtectedStorage} was requested.
* <p>
- * When a device is encrypted, data stored in this location is encrypted
+ * On devices with direct boot, data stored in this location is encrypted
* with a key tied to user credentials, which can be accessed
* <em>only after</em> the user has entered their credentials (such as a
* lock pattern or PIN).
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 09aad3b..57ab7a2 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -23,12 +23,14 @@
import android.annotation.SystemApi;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
@@ -1946,31 +1948,48 @@
public static final String ACTION_ALARM_CHANGED = "android.intent.action.ALARM_CHANGED";
/**
- * Broadcast Action: This is broadcast once, after the system has finished
- * booting and the user is in a "locked" state. A user is locked when their
- * credential-encrypted private app data storage is unavailable. Once the
- * user has entered their credentials (such as a lock pattern or PIN) for
- * the first time, the {@link #ACTION_BOOT_COMPLETED} broadcast will be
- * sent.
+ * Broadcast Action: This is broadcast once, after the user has finished
+ * booting, but while still in the "locked" state. It can be used to perform
+ * application-specific initialization, such as installing alarms. You must
+ * hold the {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED}
+ * permission in order to receive this broadcast.
* <p>
- * You must hold the
- * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission in
- * order to receive this broadcast.
+ * This broadcast is sent immediately at boot by all devices (regardless of
+ * direct boot support) running {@link android.os.Build.VERSION_CODES#N} or
+ * higher. Upon receipt of this broadcast, the user is still locked and only
+ * device-protected storage can be accessed safely. If you want to access
+ * credential-protected storage, you need to wait for the user to be
+ * unlocked (typically by entering their lock pattern or PIN for the first
+ * time), after which the {@link #ACTION_USER_UNLOCKED} and
+ * {@link #ACTION_BOOT_COMPLETED} broadcasts are sent.
+ * <p>
+ * To receive this broadcast, your receiver component must be marked as
+ * being {@link ComponentInfo#directBootAware}.
* <p class="note">
* This is a protected intent that can only be sent by the system.
+ *
+ * @see Context#createDeviceProtectedStorageContext()
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_LOCKED_BOOT_COMPLETED = "android.intent.action.LOCKED_BOOT_COMPLETED";
/**
- * Broadcast Action: This is broadcast once, after the system has finished
- * booting. It can be used to perform application-specific initialization,
- * such as installing alarms. You must hold the
- * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission
- * in order to receive this broadcast.
- *
- * <p class="note">This is a protected intent that can only be sent
- * by the system.
+ * Broadcast Action: This is broadcast once, after the user has finished
+ * booting. It can be used to perform application-specific initialization,
+ * such as installing alarms. You must hold the
+ * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission in
+ * order to receive this broadcast.
+ * <p>
+ * This broadcast is sent at boot by all devices (both with and without
+ * direct boot support). Upon receipt of this broadcast, the user is
+ * unlocked and both device-protected and credential-protected storage can
+ * accessed safely.
+ * <p>
+ * If you need to run while the user is still locked (before they've entered
+ * their lock pattern or PIN for the first time), you can listen for the
+ * {@link #ACTION_LOCKED_BOOT_COMPLETED} broadcast.
+ * <p class="note">
+ * This is a protected intent that can only be sent by the system.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 1079f97..e89cbd7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2593,12 +2593,15 @@
public abstract Intent getLeanbackLaunchIntentForPackage(String packageName);
/**
- * Return an array of all of the secondary group-ids that have been assigned
- * to a package.
+ * Return an array of all of the POSIX secondary group IDs that have been
+ * assigned to the given package.
+ * <p>
+ * Note that the same package may have different GIDs under different
+ * {@link UserHandle} on the same device.
*
* @param packageName The full name (i.e. com.google.apps.contacts) of the
- * desired package.
- * @return Returns an int array of the assigned gids, or null if there are
+ * desired package.
+ * @return Returns an int array of the assigned GIDs, or null if there are
* none.
* @throws NameNotFoundException if a package with the given name cannot be
* found on the system.
@@ -2607,8 +2610,11 @@
throws NameNotFoundException;
/**
- * Return an array of all of the secondary group-ids that have been assigned
- * to a package.
+ * Return an array of all of the POSIX secondary group IDs that have been
+ * assigned to the given package.
+ * <p>
+ * Note that the same package may have different GIDs under different
+ * {@link UserHandle} on the same device.
*
* @param packageName The full name (i.e. com.google.apps.contacts) of the
* desired package.
@@ -2622,6 +2628,9 @@
/**
* Return the UID associated with the given package name.
+ * <p>
+ * Note that the same package will have different UIDs under different
+ * {@link UserHandle} on the same device.
*
* @param packageName The full name (i.e. com.google.apps.contacts) of the
* desired package.
@@ -2634,6 +2643,9 @@
/**
* Return the UID associated with the given package name.
+ * <p>
+ * Note that the same package will have different UIDs under different
+ * {@link UserHandle} on the same device.
*
* @param packageName The full name (i.e. com.google.apps.contacts) of the
* desired package.
@@ -2648,6 +2660,9 @@
/**
* Return the UID associated with the given package name.
+ * <p>
+ * Note that the same package will have different UIDs under different
+ * {@link UserHandle} on the same device.
*
* @param packageName The full name (i.e. com.google.apps.contacts) of the
* desired package.
diff --git a/core/java/android/os/DeadSystemException.java b/core/java/android/os/DeadSystemException.java
index 595365c..8fb53e2 100644
--- a/core/java/android/os/DeadSystemException.java
+++ b/core/java/android/os/DeadSystemException.java
@@ -18,7 +18,7 @@
/**
* The core Android system has died and is going through a runtime restart. All
- * running apps will be promptly be killed.
+ * running apps will be promptly killed.
*/
public class DeadSystemException extends DeadObjectException {
public DeadSystemException() {
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 307bd2d..f6e8940 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -34,6 +34,7 @@
private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE";
private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT";
private static final String ENV_ANDROID_DATA = "ANDROID_DATA";
+ private static final String ENV_ANDROID_EXPAND = "ANDROID_EXPAND";
private static final String ENV_ANDROID_STORAGE = "ANDROID_STORAGE";
private static final String ENV_DOWNLOAD_CACHE = "DOWNLOAD_CACHE";
private static final String ENV_OEM_ROOT = "OEM_ROOT";
@@ -54,6 +55,7 @@
private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system");
private static final File DIR_ANDROID_DATA = getDirectory(ENV_ANDROID_DATA, "/data");
+ private static final File DIR_ANDROID_EXPAND = getDirectory(ENV_ANDROID_EXPAND, "/mnt/expand");
private static final File DIR_ANDROID_STORAGE = getDirectory(ENV_ANDROID_STORAGE, "/storage");
private static final File DIR_DOWNLOAD_CACHE = getDirectory(ENV_DOWNLOAD_CACHE, "/cache");
private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem");
@@ -229,6 +231,11 @@
}
/** {@hide} */
+ public static File getExpandDirectory() {
+ return DIR_ANDROID_EXPAND;
+ }
+
+ /** {@hide} */
public static File getDataSystemDirectory() {
return new File(getDataDirectory(), "system");
}
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index dd10df3..1d464c0 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -50,6 +50,7 @@
boolean isLightDeviceIdleMode();
void reboot(boolean confirm, String reason, boolean wait);
+ void rebootSafeMode(boolean confirm, boolean wait);
void shutdown(boolean confirm, String reason, boolean wait);
void crash(String message);
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index cb4caea..8bc903b 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -426,6 +426,12 @@
public static final String REBOOT_REQUESTED_BY_DEVICE_OWNER = "deviceowner";
/**
+ * The 'reason' value used when rebooting in safe mode
+ * @hide
+ */
+ public static final String REBOOT_SAFE_MODE = "safemode";
+
+ /**
* The value to pass as the 'reason' argument to android_reboot().
* @hide
*/
@@ -903,6 +909,21 @@
}
/**
+ * Reboot the device. Will not return if the reboot is successful.
+ * <p>
+ * Requires the {@link android.Manifest.permission#REBOOT} permission.
+ * </p>
+ * @hide
+ */
+ public void rebootSafeMode() {
+ try {
+ mService.rebootSafeMode(false, true);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns true if the device is currently in power save mode. When in this mode,
* applications should reduce their functionality in order to conserve battery as
* much as possible. You can monitor for changes to this state with
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 92e1862..0ff0154 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -918,11 +918,15 @@
}
/**
- * Return whether the calling user is running in an "unlocked" state. A user
- * is unlocked only after they've entered their credentials (such as a lock
- * pattern or PIN), and credential-encrypted private app data storage is
- * available. When a user is locked, only device-protected data storage is
- * available.
+ * Return whether the calling user is running in an "unlocked" state.
+ * <p>
+ * On devices with direct boot, a user is unlocked only after they've
+ * entered their credentials (such as a lock pattern or PIN). On devices
+ * without direct boot, a user is unlocked as soon as it starts.
+ * <p>
+ * When a user is locked, only device-protected data storage is available.
+ * When a user is unlocked, both device-protected and credential-protected
+ * private app data storage is available.
*
* @see Intent#ACTION_USER_UNLOCKED
* @see Context#createDeviceProtectedStorageContext()
@@ -932,11 +936,15 @@
}
/**
- * Return whether the given user is running in an "unlocked" state. A user
- * is unlocked only after they've entered their credentials (such as a lock
- * pattern or PIN), and credential-protected private app data storage is
- * available. When a user is locked, only device-protected data storage is
- * available.
+ * Return whether the given user is running in an "unlocked" state.
+ * <p>
+ * On devices with direct boot, a user is unlocked only after they've
+ * entered their credentials (such as a lock pattern or PIN). On devices
+ * without direct boot, a user is unlocked as soon as it starts.
+ * <p>
+ * When a user is locked, only device-protected data storage is available.
+ * When a user is unlocked, both device-protected and credential-protected
+ * private app data storage is available.
*
* @param user to retrieve the unlocked state for.
* @see Intent#ACTION_USER_UNLOCKED
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 61e6b95..22aec63 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -35,6 +35,7 @@
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.provider.Settings;
+import android.security.KeyStore;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
@@ -1025,6 +1026,20 @@
}
}
+ /**
+ * Return if data stored at the given path will be encrypted while at rest.
+ * This can help apps avoid the overhead of double-encrypting data.
+ */
+ public boolean isEncrypted(File file) {
+ if (FileUtils.contains(Environment.getDataDirectory(), file)) {
+ return isEncrypted();
+ } else if (FileUtils.contains(Environment.getExpandDirectory(), file)) {
+ return true;
+ }
+ // TODO: extend to support shared storage
+ return false;
+ }
+
/** {@hide}
* Is this device encryptable or already encrypted?
* @return true for encryptable or encrypted
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index c36680c..47dc6c3 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -362,8 +362,7 @@
* Explicitly set the storage location used internally by this class to be
* device-protected storage.
* <p>
- * <p>
- * When a device is encrypted, data stored in this location is encrypted
+ * On devices with direct boot, data stored in this location is encrypted
* with a key tied to the physical device, and it can be accessed
* immediately after the device has booted successfully, both
* <em>before and after</em> the user has authenticated with their
@@ -392,7 +391,7 @@
* credential-protected storage. This is the default storage area for apps
* unless {@code forceDeviceProtectedStorage} was requested.
* <p>
- * When a device is encrypted, data stored in this location is encrypted
+ * On devices with direct boot, data stored in this location is encrypted
* with a key tied to user credentials, which can be accessed
* <em>only after</em> the user has entered their credentials (such as a
* lock pattern or PIN).
diff --git a/core/java/android/webkit/IWebViewUpdateService.aidl b/core/java/android/webkit/IWebViewUpdateService.aidl
index 5697dfc..9434f0c 100644
--- a/core/java/android/webkit/IWebViewUpdateService.aidl
+++ b/core/java/android/webkit/IWebViewUpdateService.aidl
@@ -54,6 +54,11 @@
WebViewProviderInfo[] getValidWebViewPackages();
/**
+ * Fetch all packages that could potentially implement WebView.
+ */
+ WebViewProviderInfo[] getAllWebViewPackages();
+
+ /**
* Used by DevelopmentSetting to get the name of the WebView provider currently in use.
*/
String getCurrentWebViewPackageName();
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index c280b81..f1bf890 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -128,98 +128,9 @@
public MissingWebViewPackageException(Exception e) { super(e); }
}
- private static String TAG_START = "webviewproviders";
- private static String TAG_WEBVIEW_PROVIDER = "webviewprovider";
- private static String TAG_PACKAGE_NAME = "packageName";
- private static String TAG_DESCRIPTION = "description";
- // Whether or not the provider must be explicitly chosen by the user to be used.
- private static String TAG_AVAILABILITY = "availableByDefault";
- private static String TAG_SIGNATURE = "signature";
- private static String TAG_FALLBACK = "isFallback";
-
- /**
- * Reads all signatures at the current depth (within the current provider) from the XML parser.
- */
- private static String[] readSignatures(XmlResourceParser parser) throws IOException,
- XmlPullParserException {
- List<String> signatures = new ArrayList<String>();
- int outerDepth = parser.getDepth();
- while(XmlUtils.nextElementWithin(parser, outerDepth)) {
- if (parser.getName().equals(TAG_SIGNATURE)) {
- // Parse the value within the signature tag
- String signature = parser.nextText();
- signatures.add(signature);
- } else {
- Log.e(LOGTAG, "Found an element in a webview provider that is not a signature");
- }
- }
- return signatures.toArray(new String[signatures.size()]);
- }
-
- /**
- * Returns all packages declared in the framework resources as potential WebView providers.
- * @hide
- * */
- public static WebViewProviderInfo[] getWebViewPackages() {
- int numFallbackPackages = 0;
- XmlResourceParser parser = null;
- List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>();
- try {
- parser = AppGlobals.getInitialApplication().getResources().getXml(
- com.android.internal.R.xml.config_webview_packages);
- XmlUtils.beginDocument(parser, TAG_START);
- while(true) {
- XmlUtils.nextElement(parser);
- String element = parser.getName();
- if (element == null) {
- break;
- }
- if (element.equals(TAG_WEBVIEW_PROVIDER)) {
- String packageName = parser.getAttributeValue(null, TAG_PACKAGE_NAME);
- if (packageName == null) {
- throw new MissingWebViewPackageException(
- "WebView provider in framework resources missing package name");
- }
- String description = parser.getAttributeValue(null, TAG_DESCRIPTION);
- if (description == null) {
- throw new MissingWebViewPackageException(
- "WebView provider in framework resources missing description");
- }
- boolean availableByDefault = "true".equals(
- parser.getAttributeValue(null, TAG_AVAILABILITY));
- boolean isFallback = "true".equals(
- parser.getAttributeValue(null, TAG_FALLBACK));
- WebViewProviderInfo currentProvider =
- new WebViewProviderInfo(packageName, description, availableByDefault,
- isFallback, readSignatures(parser));
- if (currentProvider.isFallbackPackage()) {
- numFallbackPackages++;
- if (numFallbackPackages > 1) {
- throw new AndroidRuntimeException(
- "There can be at most one webview fallback package.");
- }
- }
- webViewProviders.add(currentProvider);
- }
- else {
- Log.e(LOGTAG, "Found an element that is not a webview provider");
- }
- }
- } catch(XmlPullParserException e) {
- throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
- } catch(IOException e) {
- throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
- } finally {
- if (parser != null) parser.close();
- }
- return webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
- }
-
-
// TODO (gsennton) remove when committing webview xts test change
public static String getWebViewPackageName() {
- WebViewProviderInfo[] providers = getWebViewPackages();
- return providers[0].packageName;
+ return null;
}
/**
diff --git a/core/java/android/webkit/WebViewProviderInfo.java b/core/java/android/webkit/WebViewProviderInfo.java
index 64c2caa..75ccf35 100644
--- a/core/java/android/webkit/WebViewProviderInfo.java
+++ b/core/java/android/webkit/WebViewProviderInfo.java
@@ -150,6 +150,8 @@
private WebViewProviderInfo(Parcel in) {
packageName = in.readString();
description = in.readString();
+ availableByDefault = (in.readInt() > 0);
+ isFallback = (in.readInt() > 0);
signatures = in.createStringArray();
packageInfo = null;
}
@@ -163,6 +165,8 @@
public void writeToParcel(Parcel out, int flags) {
out.writeString(packageName);
out.writeString(description);
+ out.writeInt(availableByDefault ? 1 : 0);
+ out.writeInt(isFallback ? 1 : 0);
out.writeStringArray(signatures);
}
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index e0ef86c..9e8f778 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -869,10 +869,10 @@
// Either expand children with weight to take up available space or
// shrink them if they extend beyond our current bounds. If we skipped
// measurement on any children, we need to measure them now.
- final int delta = heightSize - mTotalLength
+ int remainingExcess = heightSize - mTotalLength
+ (mAllowInconsistentMeasurement ? 0 : consumedExcessSpace);
- if (skippedMeasure || delta != 0 && totalWeight > 0.0f) {
- final float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
+ if (skippedMeasure || remainingExcess != 0 && totalWeight > 0.0f) {
+ float remainingWeightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
mTotalLength = 0;
@@ -883,9 +883,12 @@
}
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
- final float childExtra = lp.weight;
- if (childExtra > 0) {
- final int share = (int) (childExtra * delta / weightSum);
+ final float childWeight = lp.weight;
+ if (childWeight > 0) {
+ final int share = (int) (childWeight * remainingExcess / remainingWeightSum);
+ remainingExcess -= share;
+ remainingWeightSum -= childWeight;
+
final int childHeight;
if (lp.height == 0 && (!mAllowInconsistentMeasurement
|| heightMode == MeasureSpec.EXACTLY)) {
@@ -1244,10 +1247,10 @@
// Either expand children with weight to take up available space or
// shrink them if they extend beyond our current bounds. If we skipped
// measurement on any children, we need to measure them now.
- final int delta = widthSize - mTotalLength
+ int remainingExcess = widthSize - mTotalLength
+ (mAllowInconsistentMeasurement ? 0 : usedExcessSpace);
- if (skippedMeasure || delta != 0 && totalWeight > 0.0f) {
- final float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
+ if (skippedMeasure || remainingExcess != 0 && totalWeight > 0.0f) {
+ float remainingWeightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;
@@ -1262,9 +1265,12 @@
}
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
- final float childExtra = lp.weight;
- if (childExtra > 0) {
- final int share = (int) (childExtra * delta / weightSum);
+ final float childWeight = lp.weight;
+ if (childWeight > 0) {
+ final int share = (int) (childWeight * remainingExcess / remainingWeightSum);
+ remainingExcess -= share;
+ remainingWeightSum -= childWeight;
+
final int childWidth;
if (lp.width == 0 && (!mAllowInconsistentMeasurement
|| widthMode == MeasureSpec.EXACTLY)) {
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index dcadb6a..36e0c77 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -879,12 +879,13 @@
/**
* Filter key down events. By forwarding key down events to this function,
* views using non-modal ListPopupWindow can have it handle key selection of items.
- *
+ *
* @param keyCode keyCode param passed to the host view's onKeyDown
* @param event event param passed to the host view's onKeyDown
* @return true if the event was handled, false if it was ignored.
- *
+ *
* @see #setModal(boolean)
+ * @see #onKeyUp(int, KeyEvent)
*/
public boolean onKeyDown(int keyCode, @NonNull KeyEvent event) {
// when the drop down is shown, we drive it directly
@@ -972,14 +973,15 @@
}
/**
- * Filter key down events. By forwarding key up events to this function,
+ * Filter key up events. By forwarding key up events to this function,
* views using non-modal ListPopupWindow can have it handle key selection of items.
- *
+ *
* @param keyCode keyCode param passed to the host view's onKeyUp
* @param event event param passed to the host view's onKeyUp
* @return true if the event was handled, false if it was ignored.
- *
+ *
* @see #setModal(boolean)
+ * @see #onKeyDown(int, KeyEvent)
*/
public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) {
if (isShowing() && mDropDownList.getSelectedItemPosition() >= 0) {
@@ -998,11 +1000,11 @@
* Filter pre-IME key events. By forwarding {@link View#onKeyPreIme(int, KeyEvent)}
* events to this function, views using ListPopupWindow can have it dismiss the popup
* when the back key is pressed.
- *
+ *
* @param keyCode keyCode param passed to the host view's onKeyPreIme
* @param event event param passed to the host view's onKeyPreIme
* @return true if the event was handled, false if it was ignored.
- *
+ *
* @see #setModal(boolean)
*/
public boolean onKeyPreIme(int keyCode, @NonNull KeyEvent event) {
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index dd6a41f..a1417f0 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -16,12 +16,10 @@
package android.widget;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
-
import com.android.internal.R;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.PixelFormat;
@@ -54,10 +52,46 @@
import java.lang.ref.WeakReference;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
+
/**
- * <p>A popup window that can be used to display an arbitrary view. The popup
- * window is a floating container that appears on top of the current
- * activity.</p>
+ * <p>
+ * This class represents a popup window that can be used to display an
+ * arbitrary view. The popup window is a floating container that appears on top
+ * of the current activity.
+ * </p>
+ * <a name="Animation"></a>
+ * <h3>Animation</h3>
+ * <p>
+ * On all versions of Android, popup window enter and exit animations may be
+ * specified by calling {@link #setAnimationStyle(int)} and passing the
+ * resource ID for an animation style that defines {@code windowEnterAnimation}
+ * and {@code windowExitAnimation}. For example, passing
+ * {@link android.R.style#Animation_Dialog} will give a scale and alpha
+ * animation.
+ * </br>
+ * A window animation style may also be specified in the popup window's style
+ * XML via the {@link android.R.styleable#PopupWindow_popupAnimationStyle popupAnimationStyle}
+ * attribute.
+ * </p>
+ * <p>
+ * Starting with API 23, more complex popup window enter and exit transitions
+ * may be specified by calling either {@link #setEnterTransition(Transition)}
+ * or {@link #setExitTransition(Transition)} and passing a {@link Transition}.
+ * </br>
+ * Popup enter and exit transitions may also be specified in the popup window's
+ * style XML via the {@link android.R.styleable#PopupWindow_popupEnterTransition popupEnterTransition}
+ * and {@link android.R.styleable#PopupWindow_popupExitTransition popupExitTransition}
+ * attributes, respectively.
+ * </p>
+ *
+ * @attr ref android.R.styleable#PopupWindow_overlapAnchor
+ * @attr ref android.R.styleable#PopupWindow_popupAnimationStyle
+ * @attr ref android.R.styleable#PopupWindow_popupBackground
+ * @attr ref android.R.styleable#PopupWindow_popupElevation
+ * @attr ref android.R.styleable#PopupWindow_popupEnterTransition
+ * @attr ref android.R.styleable#PopupWindow_popupExitTransition
*
* @see android.widget.AutoCompleteTextView
* @see android.widget.Spinner
@@ -351,15 +385,54 @@
setFocusable(focusable);
}
- public void setEnterTransition(Transition enterTransition) {
+ /**
+ * Sets the enter transition to be used when the popup window is shown.
+ *
+ * @param enterTransition the enter transition, or {@code null} to clear
+ * @see #getEnterTransition()
+ * @attr ref android.R.styleable#PopupWindow_popupEnterTransition
+ */
+ public void setEnterTransition(@Nullable Transition enterTransition) {
mEnterTransition = enterTransition;
}
- public void setExitTransition(Transition exitTransition) {
+ /**
+ * Returns the enter transition to be used when the popup window is shown.
+ *
+ * @return the enter transition, or {@code null} if not set
+ * @see #setEnterTransition(Transition)
+ * @attr ref android.R.styleable#PopupWindow_popupEnterTransition
+ */
+ @Nullable
+ public Transition getEnterTransition() {
+ return mEnterTransition;
+ }
+
+ /**
+ * Sets the exit transition to be used when the popup window is dismissed.
+ *
+ * @param exitTransition the exit transition, or {@code null} to clear
+ * @see #getExitTransition()
+ * @attr ref android.R.styleable#PopupWindow_popupExitTransition
+ */
+ public void setExitTransition(@Nullable Transition exitTransition) {
mExitTransition = exitTransition;
}
/**
+ * Returns the exit transition to be used when the popup window is
+ * dismissed.
+ *
+ * @return the exit transition, or {@code null} if not set
+ * @see #setExitTransition(Transition)
+ * @attr ref android.R.styleable#PopupWindow_popupExitTransition
+ */
+ @Nullable
+ public Transition getExitTransition() {
+ return mExitTransition;
+ }
+
+ /**
* Sets the bounds used as the epicenter of the enter and exit transitions.
* <p>
* Transitions use a point or Rect, referred to as the epicenter, to orient
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 9897b12..80e1db0 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -128,8 +128,8 @@
com.android.internal.R.string.whichSendApplication,
com.android.internal.R.string.whichSendApplicationNamed),
SENDTO(Intent.ACTION_SENDTO,
- com.android.internal.R.string.whichSendApplication,
- com.android.internal.R.string.whichSendApplicationNamed),
+ com.android.internal.R.string.whichSendToApplication,
+ com.android.internal.R.string.whichSendToApplicationNamed),
SEND_MULTIPLE(Intent.ACTION_SEND_MULTIPLE,
com.android.internal.R.string.whichSendApplication,
com.android.internal.R.string.whichSendApplicationNamed),
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 919254a..66cc975 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -149,6 +149,12 @@
native private static int nativeForkSystemServer(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
+ /**
+ * Zygote unmount storage space on initializing.
+ * This method is called once.
+ */
+ native protected static void nativeUnmountStorageOnInit();
+
private static void callPostForkChildHooks(int debugFlags, boolean isSystemServer,
String instructionSet) {
VM_HOOKS.postForkChild(debugFlags, isSystemServer, instructionSet);
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 3abea26..b658f87 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -643,6 +643,9 @@
// Zygote.
Trace.setTracingEnabled(false);
+ // Zygote process unmounts root storage spaces.
+ Zygote.nativeUnmountStorageOnInit();
+
if (startSystemServer) {
startSystemServer(abiList, socketName);
}
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index ce03bb8..8682030 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -308,9 +308,6 @@
private static final int MIN_OVERFLOW_SIZE = 2;
private static final int MAX_OVERFLOW_SIZE = 4;
- /* The duration of the overflow button vector animation duration. */
- private static final int OVERFLOW_BUTTON_ANIMATION_DELAY = 400;
-
private final Context mContext;
private final View mParent; // Parent for the popup window.
private final PopupWindow mPopupWindow;
@@ -377,18 +374,6 @@
}
};
- /* Runnable to reset the overflow button's drawable after an overflow transition. */
- private final Runnable mResetOverflowButtonDrawable = new Runnable() {
- @Override
- public void run() {
- if (mIsOverflowOpen) {
- mOverflowButton.setImageDrawable(mArrow);
- } else {
- mOverflowButton.setImageDrawable(mOverflow);
- }
- }
- };
-
private boolean mDismissed = true; // tracks whether this popup is dismissed or dismissing.
private boolean mHidden; // tracks whether this popup is hidden or hiding.
@@ -902,7 +887,9 @@
final Size containerSize = mOverflowPanelSize;
setSize(mContentContainer, containerSize);
mMainPanel.setAlpha(0);
+ mMainPanel.setVisibility(View.INVISIBLE);
mOverflowPanel.setAlpha(1);
+ mOverflowPanel.setVisibility(View.VISIBLE);
mOverflowButton.setImageDrawable(mArrow);
// Update x-coordinates depending on RTL state.
@@ -941,7 +928,9 @@
final Size containerSize = mMainPanelSize;
setSize(mContentContainer, containerSize);
mMainPanel.setAlpha(1);
+ mMainPanel.setVisibility(View.VISIBLE);
mOverflowPanel.setAlpha(0);
+ mOverflowPanel.setVisibility(View.INVISIBLE);
mOverflowButton.setImageDrawable(mOverflow);
if (hasOverflow()) {
@@ -1327,8 +1316,6 @@
mToArrow.start();
openOverflow();
}
- overflowButton.postDelayed(
- mResetOverflowButtonDrawable, OVERFLOW_BUTTON_ANIMATION_DELAY);
}
});
return overflowButton;
@@ -1389,6 +1376,10 @@
// Disable the overflow button while it's animating.
// It will be re-enabled when the animation stops.
mOverflowButton.setEnabled(false);
+ // Ensure both panels have visibility turned on when the overflow animation
+ // starts.
+ mMainPanel.setVisibility(View.VISIBLE);
+ mOverflowPanel.setVisibility(View.VISIBLE);
}
@Override
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 612f4df..3f4b2a6 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -302,9 +302,6 @@
return false;
}
- // Unmount storage provided by root namespace and mount requested view
- UnmountTree("/storage");
-
String8 storageSource;
if (mount_mode == MOUNT_EXTERNAL_DEFAULT) {
storageSource = "/mnt/runtime/default";
@@ -667,12 +664,24 @@
return pid;
}
+static void com_android_internal_os_Zygote_nativeUnmountStorageOnInit(JNIEnv* env, jclass) {
+ // Zygote process unmount root storage space initially before every child processes are forked.
+ // Every forked child processes (include SystemServer) only mount their own root storage space
+ // And no need unmount storage operation in MountEmulatedStorage method.
+ // Zygote process does not utilize root storage spaces and unshared its mount namespace from the ART.
+
+ UnmountTree("/storage");
+ return;
+}
+
static const JNINativeMethod gMethods[] = {
{ "nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I",
(void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
{ "nativeForkSystemServer", "(II[II[[IJJ)I",
- (void *) com_android_internal_os_Zygote_nativeForkSystemServer }
+ (void *) com_android_internal_os_Zygote_nativeForkSystemServer },
+ { "nativeUnmountStorageOnInit", "()V",
+ (void *) com_android_internal_os_Zygote_nativeUnmountStorageOnInit }
};
int register_com_android_internal_os_Zygote(JNIEnv* env) {
diff --git a/core/res/res/anim/progress_indeterminate_rotation_material.xml b/core/res/res/anim/progress_indeterminate_rotation_material.xml
index 5d3ba22..6e12105 100644
--- a/core/res/res/anim/progress_indeterminate_rotation_material.xml
+++ b/core/res/res/anim/progress_indeterminate_rotation_material.xml
@@ -16,7 +16,7 @@
-->
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
- android:duration="6665"
+ android:duration="4444"
android:interpolator="@android:anim/linear_interpolator"
android:propertyName="rotation"
android:repeatCount="-1"
diff --git a/core/res/res/drawable/vector_drawable_progress_bar_large.xml b/core/res/res/drawable/vector_drawable_progress_bar_large.xml
index cd678f1..6448f3b 100644
--- a/core/res/res/drawable/vector_drawable_progress_bar_large.xml
+++ b/core/res/res/drawable/vector_drawable_progress_bar_large.xml
@@ -16,22 +16,22 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="76dp"
android:width="76dp"
- android:viewportHeight="48"
- android:viewportWidth="48"
+ android:viewportHeight="76"
+ android:viewportWidth="76"
android:tint="?attr/colorControlActivated">
<group
android:name="root"
- android:translateX="24.0"
- android:translateY="24.0" >
+ android:translateX="38.0"
+ android:translateY="38.0" >
<path
android:name="progressBar"
android:fillColor="#00000000"
- android:pathData="M0, 0 m 0, -19 a 19,19 0 1,1 0,38 a 19,19 0 1,1 0,-38"
+ android:pathData="M0, 0 m 0, -29 a 29,29 0 1,1 0,58 a 29,29 0 1,1 0,-58"
android:strokeColor="@color/white"
android:strokeLineCap="square"
android:strokeLineJoin="miter"
- android:strokeWidth="4"
+ android:strokeWidth="6"
android:trimPathEnd="0"
android:trimPathOffset="0"
android:trimPathStart="0" />
diff --git a/core/res/res/drawable/vector_drawable_progress_bar_medium.xml b/core/res/res/drawable/vector_drawable_progress_bar_medium.xml
index 7f038f4..80e3355 100644
--- a/core/res/res/drawable/vector_drawable_progress_bar_medium.xml
+++ b/core/res/res/drawable/vector_drawable_progress_bar_medium.xml
@@ -27,7 +27,7 @@
<path
android:name="progressBar"
android:fillColor="#00000000"
- android:pathData="M0, 0 m 0, -19 a 19,19 0 1,1 0,38 a 19,19 0 1,1 0,-38"
+ android:pathData="M0, 0 m 0, -18 a 18,18 0 1,1 0,36 a 18,18 0 1,1 0,-36"
android:strokeColor="@color/white"
android:strokeLineCap="square"
android:strokeLineJoin="miter"
diff --git a/core/res/res/drawable/vector_drawable_progress_bar_small.xml b/core/res/res/drawable/vector_drawable_progress_bar_small.xml
index 5625788..ebb632a 100644
--- a/core/res/res/drawable/vector_drawable_progress_bar_small.xml
+++ b/core/res/res/drawable/vector_drawable_progress_bar_small.xml
@@ -16,22 +16,22 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="16dp"
android:width="16dp"
- android:viewportHeight="48"
- android:viewportWidth="48"
+ android:viewportHeight="16"
+ android:viewportWidth="16"
android:tint="?attr/colorControlActivated">
<group
android:name="root"
- android:translateX="24.0"
- android:translateY="24.0" >
+ android:translateX="8.0"
+ android:translateY="8.0" >
<path
android:name="progressBar"
android:fillColor="#00000000"
- android:pathData="M0, 0 m 0, -19 a 19,19 0 1,1 0,38 a 19,19 0 1,1 0,-38"
+ android:pathData="M0, 0 m 0, -5.9375 a 5.9375,5.9375 0 1,1 0,11.875 a 5.9375,5.9375 0 1,1 0,-11.875"
android:strokeColor="@color/white"
android:strokeLineCap="square"
android:strokeLineJoin="miter"
- android:strokeWidth="4"
+ android:strokeWidth="2.125"
android:trimPathEnd="0"
android:trimPathOffset="0"
android:trimPathStart="0" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 3c5b4c0..7b85c7e 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2707,6 +2707,8 @@
<public type="attr" name="tunerCount" />
<public type="attr" name="nfcAntennaPositionDrawable" />
<public type="attr" name="fillType" />
+ <public type="attr" name="popupEnterTransition" />
+ <public type="attr" name="popupExitTransition" />
<public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
<public type="style" name="Widget.Material.SeekBar.Discrete" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 5d083d7..ba9bcaa 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2567,6 +2567,13 @@
<!-- Title of intent resolver dialog when selecting a sharing application to run
and a previously used application is known. -->
<string name="whichSendApplicationNamed">Share with %1$s</string>
+ <!-- Title of intent resolver dialog when selecting an application to run to
+ send content to a specific recipient. Often used for email. -->
+ <string name="whichSendToApplication">Send using</string>
+ <!-- Title of intent resolver dialog when selecting an application to run to
+ send content to a specific recipient and a previously used application is known.
+ Often used for email. -->
+ <string name="whichSendToApplicationNamed">Send using %1$s</string>
<!-- Title of intent resolver dialog when selecting a HOME application to run. -->
<string name="whichHomeApplication">Select a Home app</string>
<!-- Title of intent resolver dialog when selecting a HOME application to run
@@ -2936,8 +2943,8 @@
<!-- Title of the pop-up dialog in which the user switches keyboard, also known as input method. -->
<string name="select_input_method">Change keyboard</string>
- <!-- Title of a button to open the settings to enable or disable keyboards, also known as input methods [CHAR LIMIT=30] -->
- <string name="configure_input_methods">Choose keyboards</string>
+ <!-- Title of a button to open the settings to enable or disable other soft keyboards (also known as input methods) [CHAR LIMIT=30] -->
+ <string name="configure_input_methods">Other keyboards</string>
<!-- Summary text of a toggle switch to enable/disable use of the IME while a physical
keyboard is connected -->
<string name="show_ime">Keep it on screen while physical keyboard is active</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f01cce3..8b78183 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2213,6 +2213,8 @@
<java-symbol type="string" name="whichEditApplicationNamed" />
<java-symbol type="string" name="whichSendApplication" />
<java-symbol type="string" name="whichSendApplicationNamed" />
+ <java-symbol type="string" name="whichSendToApplication" />
+ <java-symbol type="string" name="whichSendToApplicationNamed" />
<java-symbol type="attr" name="lightY" />
<java-symbol type="attr" name="lightZ" />
<java-symbol type="attr" name="lightRadius" />
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
index 7a6aad6..2d3935b 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -870,39 +870,56 @@
// AsyncCommand.AsyncCommandHandler#handleMessage
if (isFailed()) {
if (DEBUG) {
- Log.i(LOG_TAG, "[CALLBACK] on canceled layout command");
+ Log.i(LOG_TAG, "[CALLBACK] on failed layout command");
}
return;
- } else {
- if (message.what != MSG_ON_LAYOUT_STARTED) {
- // No need to force cancel anymore if layout finished
- removeForceCancel();
- }
}
- switch (message.what) {
+ int sequence;
+ int what = message.what;
+ switch (what) {
+ case MSG_ON_LAYOUT_FINISHED:
+ removeForceCancel();
+ sequence = message.arg2;
+ break;
+ case MSG_ON_LAYOUT_FAILED:
+ case MSG_ON_LAYOUT_CANCELED:
+ removeForceCancel();
+ // $FALL-THROUGH - message uses the same format as "started"
+ case MSG_ON_LAYOUT_STARTED:
+ // Don't remote force-cancel as command is still running and might need to
+ // be canceled later
+ sequence = message.arg1;
+ break;
+ default:
+ // not reached
+ sequence = -1;
+ }
+
+ // If we are canceling any result is treated as a cancel
+ if (isCanceling() && what != MSG_ON_LAYOUT_STARTED) {
+ what = MSG_ON_LAYOUT_CANCELED;
+ }
+
+ switch (what) {
case MSG_ON_LAYOUT_STARTED: {
ICancellationSignal cancellation = (ICancellationSignal) message.obj;
- final int sequence = message.arg1;
handleOnLayoutStarted(cancellation, sequence);
} break;
case MSG_ON_LAYOUT_FINISHED: {
PrintDocumentInfo info = (PrintDocumentInfo) message.obj;
final boolean changed = (message.arg1 == 1);
- final int sequence = message.arg2;
handleOnLayoutFinished(info, changed, sequence);
} break;
case MSG_ON_LAYOUT_FAILED: {
CharSequence error = (CharSequence) message.obj;
- final int sequence = message.arg1;
handleOnLayoutFailed(error, sequence);
} break;
case MSG_ON_LAYOUT_CANCELED: {
- final int sequence = message.arg1;
handleOnLayoutCanceled(sequence);
} break;
}
@@ -1142,18 +1159,30 @@
// AsyncCommand.AsyncCommandHandler#handleMessage
if (isFailed()) {
if (DEBUG) {
- Log.i(LOG_TAG, "[CALLBACK] on canceled write command");
+ Log.i(LOG_TAG, "[CALLBACK] on failed write command");
}
return;
- } else {
- if (message.what != MSG_ON_WRITE_STARTED) {
- // No need to force cancel anymore if write finished
- removeForceCancel();
- }
}
- switch (message.what) {
+ int what = message.what;
+ switch (what) {
+ case MSG_ON_WRITE_FINISHED:
+ case MSG_ON_WRITE_FAILED:
+ case MSG_ON_WRITE_CANCELED:
+ removeForceCancel();
+ case MSG_ON_WRITE_STARTED:
+ // Don't remote force-cancel as command is still running and might need to
+ // be canceled later
+ break;
+ }
+
+ // If we are canceling any result is treated as a cancel
+ if (isCanceling() && what != MSG_ON_WRITE_STARTED) {
+ what = MSG_ON_WRITE_CANCELED;
+ }
+
+ switch (what) {
case MSG_ON_WRITE_STARTED: {
ICancellationSignal cancellation = (ICancellationSignal) message.obj;
final int sequence = message.arg1;
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index ad4823e..4e1180d 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -159,6 +159,7 @@
private static final int STATE_PRINTER_UNAVAILABLE = 6;
private static final int STATE_UPDATE_SLOW = 7;
private static final int STATE_PRINT_COMPLETED = 8;
+ private static final int STATE_FINISHING = 9;
private static final int UI_STATE_PREVIEW = 0;
private static final int UI_STATE_ERROR = 1;
@@ -2029,11 +2030,17 @@
}
private void doFinish() {
- if (mPrintedDocument.isUpdating()) {
+ if (mPrintedDocument != null && mPrintedDocument.isUpdating()) {
// The printedDocument will call doFinish() when the current command finishes
return;
}
+ if (mState == STATE_FINISHING) {
+ return;
+ }
+
+ mState = STATE_FINISHING;
+
if (mPrinterRegistry != null) {
mPrinterRegistry.setTrackedPrinter(null);
}
diff --git a/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
index 5a6553f..9c2c0ab 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
@@ -27,29 +27,19 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingEnd="12dp"
- android:background="@android:color/white"
- android:textColor="#D9000000"
+ android:textColor="@color/ksh_keyword_color"
android:textSize="16sp"
android:maxLines="5"
android:singleLine="false"
android:scrollHorizontally="false"
- android:layout_alignParentStart="true"
- android:minWidth="100dp"
- android:maxWidth="260dp"/>
- <!--TODO: introduce and use a layout that allows wrapping and right align -->
- <LinearLayout
+ android:layout_alignParentStart="true"/>
+ <com.android.systemui.statusbar.KeyboardShortcutKeysLayout
android:id="@+id/keyboard_shortcuts_item_container"
android:layout_toEndOf="@+id/keyboard_shortcuts_keyword"
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:background="@android:color/white"
android:layout_alignParentEnd="true"
- android:gravity="end"
android:textSize="14sp"
- android:paddingStart="0dp"
- android:paddingEnd="0dp"
- android:scrollHorizontally="false"
- android:minWidth="100dp"
- android:maxWidth="260dp"/>
+ android:scrollHorizontally="false"/>
</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
index 80a478a..6cb8470 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
@@ -22,4 +22,4 @@
android:paddingStart="24dp"
android:paddingTop="20dp"
android:paddingEnd="24dp"
- android:paddingBottom="13dp" />
+ android:paddingBottom="13dp"/>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
index f73ee15..7aba1cf 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
@@ -17,7 +17,7 @@
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="488dp"
+ android:layout_width="@dimen/ksh_layout_width"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index a2fa3b9..66963c4 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -104,4 +104,7 @@
<!-- The side padding for the task stack. -->
<dimen name="recents_stack_left_right_padding">64dp</dimen>
+
+ <!-- Keyboard shortcuts helper -->
+ <dimen name="ksh_layout_width">488dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index eeed0cf..a3f8b85 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -167,6 +167,7 @@
<!-- Keyboard shortcuts colors -->
<color name="ksh_system_group_color">#ff00bcd4</color>
<color name="ksh_application_group_color">#fff44336</color>
+ <color name="ksh_keyword_color">#d9000000</color>
<!-- Background color of edit overflow -->
<color name="qs_edit_overflow_bg">#455A64</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 6a9f456..8b433f9 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -639,4 +639,7 @@
<dimen name="battery_detail_graph_space_top">27dp</dimen>
<dimen name="battery_detail_graph_space_bottom">27dp</dimen>
+
+ <!-- Keyboard shortcuts helper -->
+ <dimen name="ksh_layout_width">@dimen/match_parent</dimen>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index f33ef65..aab45b5d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -749,7 +749,7 @@
public final void onBusEvent(AllTaskViewsDismissedEvent event) {
SystemServicesProxy ssp = Recents.getSystemServices();
if (ssp.hasDockedTask()) {
- mRecentsView.showEmptyView(R.string.recents_empty_message_dismissed_all);
+ mRecentsView.showEmptyView(event.msgResId);
} else {
// Just go straight home (no animation necessary because there are no more task views)
dismissRecentsToHome(false /* animateTaskViews */);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/AllTaskViewsDismissedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/AllTaskViewsDismissedEvent.java
index cf74519..0352161 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/AllTaskViewsDismissedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/AllTaskViewsDismissedEvent.java
@@ -22,5 +22,10 @@
* This is sent whenever all the task views in a stack have been dismissed.
*/
public class AllTaskViewsDismissedEvent extends EventBus.Event {
- // Simple event
+
+ public final int msgResId;
+
+ public AllTaskViewsDismissedEvent(int msgResId) {
+ this.msgResId = msgResId;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
index 5eeda72..16385c9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
@@ -245,7 +245,7 @@
if (row.getViewType() == TASK_ROW_VIEW_TYPE) {
TaskRow taskRow = (TaskRow) row;
Task task = taskRow.task;
- mStack.removeTask(task, AnimationProps.IMMEDIATE);
+ mStack.removeTask(task, AnimationProps.IMMEDIATE, false /* fromDockGesture */);
EventBus.getDefault().send(new DeleteTaskDataEvent(task));
i = removeTaskRow(i);
}
@@ -326,7 +326,7 @@
public void onTaskRemoved(Task task, int position) {
// Since this is removed from the history, we need to update the stack as well to ensure
// that the model is correct. Since the stack is hidden, we can update it immediately.
- mStack.removeTask(task, AnimationProps.IMMEDIATE);
+ mStack.removeTask(task, AnimationProps.IMMEDIATE, false /* fromDockGesture */);
removeTaskRow(position);
if (mRows.isEmpty()) {
dismissHistory();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 4d1c552..193bfff 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -219,7 +219,7 @@
* Notifies when a task has been removed from the stack.
*/
void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
- Task newFrontMostTask, AnimationProps animation);
+ Task newFrontMostTask, AnimationProps animation, boolean fromDockGesture);
/**
* Notifies when a task has been removed from the history.
@@ -513,14 +513,15 @@
* Removes a task from the stack, with an additional {@param animation} hint to the callbacks on
* how they should update themselves.
*/
- public void removeTask(Task t, AnimationProps animation) {
+ public void removeTask(Task t, AnimationProps animation, boolean fromDockGesture) {
if (mStackTaskList.contains(t)) {
boolean wasFrontMostTask = (getStackFrontMostTask(false /* includeFreeform */) == t);
removeTaskImpl(mStackTaskList, t);
Task newFrontMostTask = getStackFrontMostTask(false /* includeFreeform */);
if (mCb != null) {
// Notify that a task has been removed
- mCb.onStackTaskRemoved(this, t, wasFrontMostTask, newFrontMostTask, animation);
+ mCb.onStackTaskRemoved(this, t, wasFrontMostTask, newFrontMostTask, animation,
+ fromDockGesture);
}
} else if (mHistoryTaskList.contains(t)) {
removeTaskImpl(mHistoryTaskList, t);
@@ -558,9 +559,9 @@
if (notifyStackChanges) {
// If we are notifying, then remove the task now, otherwise the raw task list
// will be reset at the end of this method
- removeTask(task, AnimationProps.IMMEDIATE);
+ removeTask(task, AnimationProps.IMMEDIATE, false /* fromDockGesture */);
mCb.onStackTaskRemoved(this, task, i == (taskCount - 1), null,
- AnimationProps.IMMEDIATE);
+ AnimationProps.IMMEDIATE, false /* fromDockGesture */);
}
}
task.setGroup(null);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
index 4458639..cf8c9bb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
@@ -135,7 +135,7 @@
@Override
public void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
- Task newFrontMostTask, AnimationProps animation) {
+ Task newFrontMostTask, AnimationProps animation, boolean fromDockGesture) {
getAdapter().notifyItemRemoved(stack.getStackTasks().indexOf(removedTask));
if (mFocusedTask == removedTask) {
resetFocusedTask(removedTask);
@@ -144,7 +144,9 @@
if (mStack.getStackTaskCount() == 0) {
boolean shouldFinishActivity = (mStack.getStackTaskCount() == 0);
if (shouldFinishActivity) {
- EventBus.getDefault().send(new AllTaskViewsDismissedEvent());
+ EventBus.getDefault().send(new AllTaskViewsDismissedEvent(fromDockGesture
+ ? R.string.recents_empty_message
+ : R.string.recents_empty_message_dismissed_all));
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 9235673..db97e8f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -632,7 +632,8 @@
AnimationProps stackAnim = new AnimationProps(
TaskStackView.DEFAULT_SYNC_STACK_DURATION,
Interpolators.FAST_OUT_SLOW_IN);
- mTaskStackView.getStack().removeTask(event.task, stackAnim);
+ mTaskStackView.getStack().removeTask(event.task, stackAnim,
+ true /* fromDockGesture */);
}
}));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index 84590f2..33d5bb7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -150,8 +150,7 @@
mTaskView.setTranslationY(y);
mVisibleDockStates.clear();
- if (ActivityManager.supportsMultiWindow() &&
- !ssp.hasDockedTask() && mRv.getTaskStack().getTaskCount() > 1) {
+ if (ActivityManager.supportsMultiWindow() && !ssp.hasDockedTask()) {
if (!event.task.isDockable) {
Toast.makeText(mRv.getContext(), R.string.recents_drag_non_dockable_task_message,
Toast.LENGTH_SHORT).show();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 93b5b6c..0b20d21 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -1395,7 +1395,7 @@
*/
@Override
public void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
- Task newFrontMostTask, AnimationProps animation) {
+ Task newFrontMostTask, AnimationProps animation, boolean fromDockGesture) {
if (mFocusedTask == removedTask) {
resetFocusedTask(removedTask);
}
@@ -1426,7 +1426,9 @@
// If there are no remaining tasks, then just close recents
if (mStack.getTaskCount() == 0) {
- EventBus.getDefault().send(new AllTaskViewsDismissedEvent());
+ EventBus.getDefault().send(new AllTaskViewsDismissedEvent(fromDockGesture
+ ? R.string.recents_empty_message
+ : R.string.recents_empty_message_dismissed_all));
}
}
@@ -1599,7 +1601,7 @@
tv.dismissTask();
} else {
// Otherwise, remove the task from the stack immediately
- mStack.removeTask(t, AnimationProps.IMMEDIATE);
+ mStack.removeTask(t, AnimationProps.IMMEDIATE, false /* fromDockGesture */);
}
}
}
@@ -1937,7 +1939,7 @@
// Remove the task from the stack
mStack.removeTask(task, new AnimationProps(DEFAULT_SYNC_STACK_DURATION,
- Interpolators.FAST_OUT_SLOW_IN));
+ Interpolators.FAST_OUT_SLOW_IN), false /* fromDockGesture */);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutKeysLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutKeysLayout.java
new file mode 100644
index 0000000..ba3e774
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutKeysLayout.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Layout used as a container for keyboard shortcut keys. It's children are wrapped and right
+ * aligned.
+ */
+public final class KeyboardShortcutKeysLayout extends ViewGroup {
+ private int mLineHeight;
+
+ public KeyboardShortcutKeysLayout(Context context) {
+ super(context);
+ }
+
+ public KeyboardShortcutKeysLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
+ int childCount = getChildCount();
+ int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();
+ int lineHeight = 0;
+ int xPos = getPaddingLeft();
+ int yPos = getPaddingTop();
+
+ int childHeightMeasureSpec;
+ if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
+ childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
+ } else {
+ childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ }
+
+ for (int i = 0; i < childCount; i++) {
+ View child = getChildAt(i);
+ if (child.getVisibility() != GONE) {
+ LayoutParams layoutParams = (LayoutParams) child.getLayoutParams();
+ child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
+ childHeightMeasureSpec);
+ int childWidth = child.getMeasuredWidth();
+ lineHeight = Math.max(lineHeight,
+ child.getMeasuredHeight() + layoutParams.mVerticalSpacing);
+
+ if (xPos + childWidth > width) {
+ xPos = getPaddingLeft();
+ yPos += lineHeight;
+ }
+ xPos += childWidth + layoutParams.mHorizontalSpacing;
+ }
+ }
+ this.mLineHeight = lineHeight;
+
+ if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) {
+ height = yPos + lineHeight;
+ } else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
+ if (yPos + lineHeight < height) {
+ height = yPos + lineHeight;
+ }
+ }
+ setMeasuredDimension(width, height);
+ }
+
+ @Override
+ protected LayoutParams generateDefaultLayoutParams() {
+ int spacing = getHorizontalVerticalSpacing();
+ return new LayoutParams(spacing, spacing);
+ }
+
+ @Override
+ protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams layoutParams) {
+ int spacing = getHorizontalVerticalSpacing();
+ return new LayoutParams(spacing, spacing, layoutParams);
+ }
+
+ @Override
+ protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+ return (p instanceof LayoutParams);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ int childCount = getChildCount();
+ int fullRowWidth = r - l;
+ int xPos = getPaddingLeft();
+ int yPos = getPaddingTop();
+ int lastHorizontalSpacing = 0;
+ // The index of the child which starts the current row.
+ int rowStartIdx = 0;
+
+ // Go through all the children.
+ for (int i = 0; i < childCount; i++) {
+ View currentChild = getChildAt(i);
+ if (currentChild.getVisibility() != GONE) {
+ int currentChildWidth = currentChild.getMeasuredWidth();
+ LayoutParams lp = (LayoutParams) currentChild.getLayoutParams();
+
+ // If the current child does not fit on this row.
+ if (xPos + currentChildWidth > fullRowWidth) {
+ // Layout all the children on this row but the current one.
+ layoutChildrenOnRow(rowStartIdx, i, fullRowWidth, xPos, yPos,
+ lastHorizontalSpacing);
+ // Update the positions for starting on the new row.
+ xPos = getPaddingLeft();
+ yPos += mLineHeight;
+ rowStartIdx = i;
+ }
+
+ xPos += currentChildWidth + lp.mHorizontalSpacing;
+ lastHorizontalSpacing = lp.mHorizontalSpacing;
+ }
+ }
+
+ // Lay out the children on the last row.
+ if (rowStartIdx < childCount) {
+ layoutChildrenOnRow(rowStartIdx, childCount, fullRowWidth, xPos, yPos,
+ lastHorizontalSpacing);
+ }
+ }
+
+ private int getHorizontalVerticalSpacing() {
+ DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
+ return (int) TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, 4, displayMetrics);
+ }
+
+ private void layoutChildrenOnRow(int startIndex, int endIndex, int fullRowWidth, int xPos,
+ int yPos, int lastHorizontalSpacing) {
+ int freeSpace = fullRowWidth - xPos + lastHorizontalSpacing;
+ xPos = getPaddingLeft() + freeSpace;
+
+ for (int j = startIndex; j < endIndex; ++j) {
+ View currentChild = getChildAt(j);
+ currentChild.layout(
+ xPos,
+ yPos,
+ xPos + currentChild.getMeasuredWidth(),
+ yPos + currentChild.getMeasuredHeight());
+ xPos += currentChild.getMeasuredWidth()
+ + ((LayoutParams) currentChild.getLayoutParams()).mHorizontalSpacing;
+ }
+ }
+
+ public static class LayoutParams extends ViewGroup.LayoutParams {
+ public final int mHorizontalSpacing;
+ public final int mVerticalSpacing;
+
+ public LayoutParams(int horizontalSpacing, int verticalSpacing,
+ ViewGroup.LayoutParams viewGroupLayout) {
+ super(viewGroupLayout);
+ this.mHorizontalSpacing = horizontalSpacing;
+ this.mVerticalSpacing = verticalSpacing;
+ }
+
+ public LayoutParams(int mHorizontalSpacing, int verticalSpacing) {
+ super(0, 0);
+ this.mHorizontalSpacing = mHorizontalSpacing;
+ this.mVerticalSpacing = verticalSpacing;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index 0b7bfa8..60c2fa6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -29,6 +29,7 @@
import android.view.KeyboardShortcutInfo;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager.KeyboardShortcutsReceiver;
import android.widget.LinearLayout;
@@ -153,7 +154,7 @@
.findViewById(R.id.keyboard_shortcuts_keyword);
textView.setText(info.getLabel());
- LinearLayout shortcutItemsContainer = (LinearLayout) shortcutView
+ ViewGroup shortcutItemsContainer = (ViewGroup) shortcutView
.findViewById(R.id.keyboard_shortcuts_item_container);
List<String> shortcutKeys = getHumanReadableShortcutKeys(info);
final int shortcutKeysSize = shortcutKeys.size();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 575de16..d526ef5 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1852,6 +1852,12 @@
}
private boolean checkPolicyAccess(String pkg) {
+ if (mAudioManagerInternal != null) {
+ final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
+ if (vcuid > 0 && Binder.getCallingUid() == vcuid) {
+ return true;
+ }
+ }
return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 91d8671..cbd77d4 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.power;
import android.Manifest;
+import android.annotation.IntDef;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -74,6 +75,8 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
@@ -162,6 +165,14 @@
// Default setting for double tap to wake.
private static final int DEFAULT_DOUBLE_TAP_TO_WAKE = 0;
+ /** Constants for {@link #shutdownOrRebootInternal} */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({HALT_MODE_SHUTDOWN, HALT_MODE_REBOOT, HALT_MODE_REBOOT_SAFE_MODE})
+ public @interface HaltMode {}
+ private static final int HALT_MODE_SHUTDOWN = 0;
+ private static final int HALT_MODE_REBOOT = 1;
+ private static final int HALT_MODE_REBOOT_SAFE_MODE = 2;
+
private final Context mContext;
private final ServiceThread mHandlerThread;
private final PowerManagerHandler mHandler;
@@ -2392,7 +2403,7 @@
updatePowerStateLocked();
}
- private void shutdownOrRebootInternal(final boolean shutdown, final boolean confirm,
+ private void shutdownOrRebootInternal(final @HaltMode int haltMode, final boolean confirm,
final String reason, boolean wait) {
if (mHandler == null || !mSystemReady) {
throw new IllegalStateException("Too early to call shutdown() or reboot()");
@@ -2402,10 +2413,12 @@
@Override
public void run() {
synchronized (this) {
- if (shutdown) {
- ShutdownThread.shutdown(mContext, reason, confirm);
- } else {
+ if (haltMode == HALT_MODE_REBOOT_SAFE_MODE) {
+ ShutdownThread.rebootSafeMode(mContext, confirm);
+ } else if (haltMode == HALT_MODE_REBOOT) {
ShutdownThread.reboot(mContext, reason, confirm);
+ } else {
+ ShutdownThread.shutdown(mContext, reason, confirm);
}
}
}
@@ -3465,7 +3478,26 @@
final long ident = Binder.clearCallingIdentity();
try {
- shutdownOrRebootInternal(false, confirm, reason, wait);
+ shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ /**
+ * Reboots the device into safe mode
+ *
+ * @param confirm If true, shows a reboot confirmation dialog.
+ * @param wait If true, this call waits for the reboot to complete and does not return.
+ */
+ @Override // Binder call
+ public void rebootSafeMode(boolean confirm, boolean wait) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ shutdownOrRebootInternal(HALT_MODE_REBOOT_SAFE_MODE, confirm,
+ PowerManager.REBOOT_SAFE_MODE, wait);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -3483,7 +3515,7 @@
final long ident = Binder.clearCallingIdentity();
try {
- shutdownOrRebootInternal(true, confirm, reason, wait);
+ shutdownOrRebootInternal(HALT_MODE_SHUTDOWN, confirm, reason, wait);
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index a4bbb51..50699f8 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -35,14 +35,14 @@
import android.os.ResultReceiver;
import android.os.UserHandle;
import android.os.UserManager;
-import android.provider.Settings;
import android.provider.Settings.Global;
+import android.provider.Settings;
import android.util.AndroidRuntimeException;
import android.util.Slog;
import android.webkit.IWebViewUpdateService;
+import android.webkit.WebViewFactory;
import android.webkit.WebViewProviderInfo;
import android.webkit.WebViewProviderResponse;
-import android.webkit.WebViewFactory;
import com.android.server.SystemService;
@@ -76,9 +76,11 @@
private WebViewProviderInfo[] mCurrentValidWebViewPackages = null;
private BroadcastReceiver mWebViewUpdatedReceiver;
+ private WebViewUtilityInterface mWebViewUtility;
public WebViewUpdateService(Context context) {
super(context);
+ mWebViewUtility = new WebViewUtilityImpl();
}
@Override
@@ -114,7 +116,7 @@
updateFallbackState(context, intent);
- for (WebViewProviderInfo provider : WebViewFactory.getWebViewPackages()) {
+ for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) {
String webviewPackage = "package:" + provider.packageName;
if (webviewPackage.equals(intent.getDataString())) {
@@ -153,11 +155,7 @@
// package that was not the previous provider then we must kill
// packages dependent on the old package ourselves. The framework
// only kills dependents of packages that are being removed.
- try {
- ActivityManagerNative.getDefault().killPackageDependents(
- oldProviderName, UserHandle.USER_ALL);
- } catch (RemoteException e) {
- }
+ mWebViewUtility.killPackageDependents(oldProviderName);
}
return;
}
@@ -170,7 +168,7 @@
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
// Make sure we only receive intents for WebView packages from our config file.
- for (WebViewProviderInfo provider : WebViewFactory.getWebViewPackages()) {
+ for (WebViewProviderInfo provider : mWebViewUtility.getWebViewPackages()) {
filter.addDataSchemeSpecificPart(provider.packageName, PatternMatcher.PATTERN_LITERAL);
}
getContext().registerReceiver(mWebViewUpdatedReceiver, filter);
@@ -210,7 +208,7 @@
void handleNewUser(int userId) {
if (!isFallbackLogicEnabled()) return;
- WebViewProviderInfo[] webviewProviders = WebViewFactory.getWebViewPackages();
+ WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();
WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewProviders);
if (fallbackProvider == null) return;
boolean existsValidNonFallbackProvider =
@@ -228,7 +226,7 @@
void updateFallbackState(final Context context, final Intent intent) {
if (!isFallbackLogicEnabled()) return;
- WebViewProviderInfo[] webviewProviders = WebViewFactory.getWebViewPackages();
+ WebViewProviderInfo[] webviewProviders = mWebViewUtility.getWebViewPackages();
if (intent != null && (intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)
|| intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED))) {
@@ -319,10 +317,10 @@
return false;
}
- private static boolean isFallbackPackage(String packageName) {
+ private boolean isFallbackPackage(String packageName) {
if (packageName == null || !isFallbackLogicEnabled()) return false;
- WebViewProviderInfo[] webviewPackages = WebViewFactory.getWebViewPackages();
+ WebViewProviderInfo[] webviewPackages = mWebViewUtility.getWebViewPackages();
WebViewProviderInfo fallbackProvider = getFallbackProvider(webviewPackages);
return (fallbackProvider != null
&& packageName.equals(fallbackProvider.packageName));
@@ -359,13 +357,13 @@
PackageInfo newPackage = null;
synchronized(this) {
oldPackage = mCurrentWebViewPackage;
- updateUserSetting(newProviderName);
+ mWebViewUtility.updateUserSetting(getContext(), newProviderName);
try {
newPackage = findPreferredWebViewPackage();
if (oldPackage != null && newPackage.packageName.equals(oldPackage.packageName)) {
// If we don't perform the user change, revert the settings change.
- updateUserSetting(newPackage.packageName);
+ mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName);
return newPackage.packageName;
}
} catch (WebViewFactory.MissingWebViewPackageException e) {
@@ -378,12 +376,8 @@
onWebViewProviderChanged(newPackage);
}
// Kill apps using the old provider
- try {
- if (oldPackage != null) {
- ActivityManagerNative.getDefault().killPackageDependents(
- oldPackage.packageName, UserHandle.USER_ALL);
- }
- } catch (RemoteException e) {
+ if (oldPackage != null) {
+ mWebViewUtility.killPackageDependents(oldPackage.packageName);
}
return newPackage.packageName;
}
@@ -397,14 +391,14 @@
mAnyWebViewInstalled = true;
if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
mCurrentWebViewPackage = newPackage;
- updateUserSetting(newPackage.packageName);
+ mWebViewUtility.updateUserSetting(getContext(), newPackage.packageName);
// The relro creations might 'finish' (not start at all) before
// WebViewFactory.onWebViewProviderChanged which means we might not know the number
// of started creations before they finish.
mNumRelroCreationsStarted = NUMBER_OF_RELROS_UNKNOWN;
mNumRelroCreationsFinished = 0;
- mNumRelroCreationsStarted = WebViewFactory.onWebViewProviderChanged(newPackage);
+ mNumRelroCreationsStarted = mWebViewUtility.onWebViewProviderChanged(newPackage);
// If the relro creations finish before we know the number of started creations we
// will have to do any cleanup/notifying here.
checkIfRelrosDoneLocked();
@@ -421,7 +415,7 @@
* */
private void updateValidWebViewPackages() {
List<WebViewProviderInfo> webViewProviders =
- new ArrayList<WebViewProviderInfo>(Arrays.asList(WebViewFactory.getWebViewPackages()));
+ new ArrayList<WebViewProviderInfo>(Arrays.asList(mWebViewUtility.getWebViewPackages()));
Iterator<WebViewProviderInfo> it = webViewProviders.iterator();
// remove non-valid packages
while(it.hasNext()) {
@@ -435,17 +429,6 @@
}
}
- private static String getUserChosenWebViewProvider() {
- return Settings.Global.getString(AppGlobals.getInitialApplication().getContentResolver(),
- Settings.Global.WEBVIEW_PROVIDER);
- }
-
- private void updateUserSetting(String newProviderName) {
- Settings.Global.putString(getContext().getContentResolver(),
- Settings.Global.WEBVIEW_PROVIDER,
- newProviderName == null ? "" : newProviderName);
- }
-
/**
* Returns either the package info of the WebView provider determined in the following way:
* If the user has chosen a provider then use that if it is valid,
@@ -456,7 +439,7 @@
private PackageInfo findPreferredWebViewPackage() {
WebViewProviderInfo[] providers = mCurrentValidWebViewPackages;
- String userChosenProvider = getUserChosenWebViewProvider();
+ String userChosenProvider = mWebViewUtility.getUserChosenWebViewProvider(getContext());
// If the user has chosen provider, use that
for (WebViewProviderInfo provider : providers) {
@@ -616,6 +599,11 @@
}
@Override // Binder call
+ public WebViewProviderInfo[] getAllWebViewPackages() {
+ return WebViewUpdateService.this.mWebViewUtility.getWebViewPackages();
+ }
+
+ @Override // Binder call
public String getCurrentWebViewPackageName() {
synchronized(WebViewUpdateService.this) {
if (WebViewUpdateService.this.mCurrentWebViewPackage == null)
@@ -626,7 +614,7 @@
@Override // Binder call
public boolean isFallbackPackage(String packageName) {
- return WebViewUpdateService.isFallbackPackage(packageName);
+ return WebViewUpdateService.this.isFallbackPackage(packageName);
}
@Override // Binder call
diff --git a/services/core/java/com/android/server/webkit/WebViewUtilityImpl.java b/services/core/java/com/android/server/webkit/WebViewUtilityImpl.java
new file mode 100644
index 0000000..4dbd02d
--- /dev/null
+++ b/services/core/java/com/android/server/webkit/WebViewUtilityImpl.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.webkit;
+
+import android.app.ActivityManagerNative;
+import android.app.AppGlobals;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.res.XmlResourceParser;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.AndroidRuntimeException;
+import android.util.Log;
+import android.webkit.WebViewFactory;
+import android.webkit.WebViewFactory.MissingWebViewPackageException;
+import android.webkit.WebViewProviderInfo;
+
+import com.android.internal.util.XmlUtils;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+/**
+ * Default implementation for the WebView preparation Utility interface.
+ * @hide
+ */
+public class WebViewUtilityImpl implements WebViewUtilityInterface {
+ private static final String TAG = WebViewUtilityImpl.class.getSimpleName();
+ private static final String TAG_START = "webviewproviders";
+ private static final String TAG_WEBVIEW_PROVIDER = "webviewprovider";
+ private static final String TAG_PACKAGE_NAME = "packageName";
+ private static final String TAG_DESCRIPTION = "description";
+ // Whether or not the provider must be explicitly chosen by the user to be used.
+ private static final String TAG_AVAILABILITY = "availableByDefault";
+ private static final String TAG_SIGNATURE = "signature";
+ private static final String TAG_FALLBACK = "isFallback";
+
+ /**
+ * Returns all packages declared in the framework resources as potential WebView providers.
+ * @hide
+ * */
+ @Override
+ public WebViewProviderInfo[] getWebViewPackages() {
+ int numFallbackPackages = 0;
+ XmlResourceParser parser = null;
+ List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>();
+ try {
+ parser = AppGlobals.getInitialApplication().getResources().getXml(
+ com.android.internal.R.xml.config_webview_packages);
+ XmlUtils.beginDocument(parser, TAG_START);
+ while(true) {
+ XmlUtils.nextElement(parser);
+ String element = parser.getName();
+ if (element == null) {
+ break;
+ }
+ if (element.equals(TAG_WEBVIEW_PROVIDER)) {
+ String packageName = parser.getAttributeValue(null, TAG_PACKAGE_NAME);
+ if (packageName == null) {
+ throw new MissingWebViewPackageException(
+ "WebView provider in framework resources missing package name");
+ }
+ String description = parser.getAttributeValue(null, TAG_DESCRIPTION);
+ if (description == null) {
+ throw new MissingWebViewPackageException(
+ "WebView provider in framework resources missing description");
+ }
+ boolean availableByDefault = "true".equals(
+ parser.getAttributeValue(null, TAG_AVAILABILITY));
+ boolean isFallback = "true".equals(
+ parser.getAttributeValue(null, TAG_FALLBACK));
+ WebViewProviderInfo currentProvider =
+ new WebViewProviderInfo(packageName, description, availableByDefault,
+ isFallback, readSignatures(parser));
+ if (currentProvider.isFallbackPackage()) {
+ numFallbackPackages++;
+ if (numFallbackPackages > 1) {
+ throw new AndroidRuntimeException(
+ "There can be at most one webview fallback package.");
+ }
+ }
+ webViewProviders.add(currentProvider);
+ }
+ else {
+ Log.e(TAG, "Found an element that is not a webview provider");
+ }
+ }
+ } catch(XmlPullParserException e) {
+ throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
+ } catch(IOException e) {
+ throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e);
+ } finally {
+ if (parser != null) parser.close();
+ }
+ return webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
+ }
+
+ /**
+ * Reads all signatures at the current depth (within the current provider) from the XML parser.
+ */
+ private static String[] readSignatures(XmlResourceParser parser) throws IOException,
+ XmlPullParserException {
+ List<String> signatures = new ArrayList<String>();
+ int outerDepth = parser.getDepth();
+ while(XmlUtils.nextElementWithin(parser, outerDepth)) {
+ if (parser.getName().equals(TAG_SIGNATURE)) {
+ // Parse the value within the signature tag
+ String signature = parser.nextText();
+ signatures.add(signature);
+ } else {
+ Log.e(TAG, "Found an element in a webview provider that is not a signature");
+ }
+ }
+ return signatures.toArray(new String[signatures.size()]);
+ }
+
+ @Override
+ public int onWebViewProviderChanged(PackageInfo packageInfo) {
+ return WebViewFactory.onWebViewProviderChanged(packageInfo);
+ }
+
+ @Override
+ public String getUserChosenWebViewProvider(Context context) {
+ return Settings.Global.getString(context.getContentResolver(),
+ Settings.Global.WEBVIEW_PROVIDER);
+ }
+
+ @Override
+ public void updateUserSetting(Context context, String newProviderName) {
+ Settings.Global.putString(context.getContentResolver(),
+ Settings.Global.WEBVIEW_PROVIDER,
+ newProviderName == null ? "" : newProviderName);
+ }
+
+ @Override
+ public void killPackageDependents(String packageName) {
+ try {
+ ActivityManagerNative.getDefault().killPackageDependents(packageName,
+ UserHandle.USER_ALL);
+ } catch (RemoteException e) {
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/webkit/WebViewUtilityInterface.java b/services/core/java/com/android/server/webkit/WebViewUtilityInterface.java
new file mode 100644
index 0000000..1919f40
--- /dev/null
+++ b/services/core/java/com/android/server/webkit/WebViewUtilityInterface.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.webkit;
+
+import android.webkit.WebViewProviderInfo;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+
+/**
+ * Utility interface for the WebViewUpdateService.
+ * This interface provides a way to test the WebView preparation mechanism - during normal use this
+ * interface is implemented using calls to the Android framework, but by providing an alternative
+ * implementation we can test the WebView preparation logic without reaching other framework code.
+ * @hide
+ */
+public interface WebViewUtilityInterface {
+ public WebViewProviderInfo[] getWebViewPackages();
+ public int onWebViewProviderChanged(PackageInfo packageInfo);
+
+ public String getUserChosenWebViewProvider(Context context);
+ public void updateUserSetting(Context context, String newProviderName);
+ public void killPackageDependents(String packageName);
+}
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index f2f555b..8ab1878 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -443,10 +443,7 @@
@Nullable List<PrinterId> printerIds) {
synchronized (mLock) {
throwIfDestroyedLocked();
- // No services - nothing to do.
- if (mActiveServices.isEmpty()) {
- return;
- }
+
// No session - nothing to do.
if (mPrinterDiscoverySession == null) {
return;
@@ -460,10 +457,7 @@
public void stopPrinterDiscovery(@NonNull IPrinterDiscoveryObserver observer) {
synchronized (mLock) {
throwIfDestroyedLocked();
- // No services - nothing to do.
- if (mActiveServices.isEmpty()) {
- return;
- }
+
// No session - nothing to do.
if (mPrinterDiscoverySession == null) {
return;