Merge "Revise createIntent and parseResult API." into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index 5c18ade..129e2de 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5499,7 +5499,7 @@
method public void uninstallCaCert(android.content.ComponentName, byte[]);
method public void wipeData(int);
field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
- field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.ACTION_PROVISION_MANAGED_PROFILE";
+ field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
field public static final int ENCRYPTION_STATUS_ACTIVATING = 2; // 0x2
@@ -5509,11 +5509,10 @@
field public static final java.lang.String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION";
field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
field public static final java.lang.String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
- field public static final java.lang.String EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME = "android.app.extra.PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
- field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.deviceAdminPackageName";
+ field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
@@ -8908,6 +8907,7 @@
field public static final java.lang.String FEATURE_PRINTING = "android.software.print";
field public static final java.lang.String FEATURE_SCREEN_LANDSCAPE = "android.hardware.screen.landscape";
field public static final java.lang.String FEATURE_SCREEN_PORTRAIT = "android.hardware.screen.portrait";
+ field public static final java.lang.String FEATURE_SECURELY_REMOVES_USERS = "android.software.securely_removes_users";
field public static final java.lang.String FEATURE_SENSOR_ACCELEROMETER = "android.hardware.sensor.accelerometer";
field public static final java.lang.String FEATURE_SENSOR_AMBIENT_TEMPERATURE = "android.hardware.sensor.ambient_temperature";
field public static final java.lang.String FEATURE_SENSOR_BAROMETER = "android.hardware.sensor.barometer";
@@ -8932,6 +8932,7 @@
field public static final java.lang.String FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND = "android.hardware.touchscreen.multitouch.jazzhand";
field public static final java.lang.String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
field public static final java.lang.String FEATURE_USB_HOST = "android.hardware.usb.host";
+ field public static final java.lang.String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
field public static final java.lang.String FEATURE_WATCH = "android.hardware.type.watch";
field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview";
field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
@@ -12682,7 +12683,7 @@
method public void onCaptureProgressed(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, android.hardware.camera2.CaptureResult);
method public void onCaptureSequenceAborted(android.hardware.camera2.CameraCaptureSession, int);
method public void onCaptureSequenceCompleted(android.hardware.camera2.CameraCaptureSession, int, long);
- method public void onCaptureStarted(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, long);
+ method public void onCaptureStarted(android.hardware.camera2.CameraCaptureSession, android.hardware.camera2.CaptureRequest, long, long);
}
public static abstract class CameraCaptureSession.StateCallback {
@@ -14074,29 +14075,6 @@
method public android.media.AudioAttributes.Builder setUsage(int);
}
- public class AudioDevice {
- field public static final int DEVICE_TYPE_AUX_LINE = 19; // 0x13
- field public static final int DEVICE_TYPE_BLUETOOTH_A2DP = 8; // 0x8
- field public static final int DEVICE_TYPE_BLUETOOTH_SCO = 7; // 0x7
- field public static final int DEVICE_TYPE_BUILTIN_EARPIECE = 1; // 0x1
- field public static final int DEVICE_TYPE_BUILTIN_MIC = 15; // 0xf
- field public static final int DEVICE_TYPE_BUILTIN_SPEAKER = 2; // 0x2
- field public static final int DEVICE_TYPE_DOCK = 13; // 0xd
- field public static final int DEVICE_TYPE_FM = 14; // 0xe
- field public static final int DEVICE_TYPE_FM_TUNER = 16; // 0x10
- field public static final int DEVICE_TYPE_HDMI = 9; // 0x9
- field public static final int DEVICE_TYPE_HDMI_ARC = 10; // 0xa
- field public static final int DEVICE_TYPE_LINE_ANALOG = 5; // 0x5
- field public static final int DEVICE_TYPE_LINE_DIGITAL = 6; // 0x6
- field public static final int DEVICE_TYPE_TELEPHONY = 18; // 0x12
- field public static final int DEVICE_TYPE_TV_TUNER = 17; // 0x11
- field public static final int DEVICE_TYPE_UNKNOWN = 0; // 0x0
- field public static final int DEVICE_TYPE_USB_ACCESSORY = 12; // 0xc
- field public static final int DEVICE_TYPE_USB_DEVICE = 11; // 0xb
- field public static final int DEVICE_TYPE_WIRED_HEADPHONES = 4; // 0x4
- field public static final int DEVICE_TYPE_WIRED_HEADSET = 3; // 0x3
- }
-
public class AudioFormat {
method public int getChannelMask();
method public int getEncoding();
@@ -14420,6 +14398,7 @@
field public static final int QUALITY_CIF = 3; // 0x3
field public static final int QUALITY_HIGH = 1; // 0x1
field public static final int QUALITY_HIGH_SPEED_1080P = 2004; // 0x7d4
+ field public static final int QUALITY_HIGH_SPEED_2160P = 2005; // 0x7d5
field public static final int QUALITY_HIGH_SPEED_480P = 2002; // 0x7d2
field public static final int QUALITY_HIGH_SPEED_720P = 2003; // 0x7d3
field public static final int QUALITY_HIGH_SPEED_HIGH = 2001; // 0x7d1
@@ -14664,7 +14643,7 @@
}
public static final class MediaCodec.CodecException extends java.lang.IllegalStateException {
- method public int getErrorCode();
+ method public java.lang.String getDiagnosticInfo();
method public boolean isRecoverable();
method public boolean isTransient();
}
@@ -14672,6 +14651,7 @@
public static final class MediaCodec.CryptoException extends java.lang.RuntimeException {
ctor public MediaCodec.CryptoException(int, java.lang.String);
method public int getErrorCode();
+ field public static final int ERROR_INSUFFICIENT_OUTPUT_PROTECTION = 4; // 0x4
field public static final int ERROR_KEY_EXPIRED = 2; // 0x2
field public static final int ERROR_NO_KEY = 1; // 0x1
field public static final int ERROR_RESOURCE_BUSY = 3; // 0x3
@@ -15001,7 +14981,7 @@
public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException {
ctor public MediaDrm.MediaDrmStateException(int, java.lang.String);
- method public int getErrorCode();
+ method public java.lang.String getDiagnosticInfo();
}
public static abstract interface MediaDrm.OnEventListener {
@@ -16187,12 +16167,16 @@
method public short getRoundedStrength() throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
method public boolean getSpeakerAngles(int, int, int[]) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
method public boolean getStrengthSupported();
- method public int getVirtualizationMode() throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
+ method public int getVirtualizationMode() throws java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
method public void setParameterListener(android.media.audiofx.Virtualizer.OnParameterChangeListener);
method public void setProperties(android.media.audiofx.Virtualizer.Settings) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
method public void setStrength(short) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;
field public static final int PARAM_STRENGTH = 1; // 0x1
field public static final int PARAM_STRENGTH_SUPPORTED = 0; // 0x0
+ field public static final int VIRTUALIZATION_MODE_AUTO = 1; // 0x1
+ field public static final int VIRTUALIZATION_MODE_BINAURAL = 2; // 0x2
+ field public static final int VIRTUALIZATION_MODE_OFF = 0; // 0x0
+ field public static final int VIRTUALIZATION_MODE_TRANSAURAL = 3; // 0x3
}
public static abstract interface Virtualizer.OnParameterChangeListener {
@@ -22500,6 +22484,7 @@
field public static final java.lang.String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
field public static final java.lang.String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
field public static final java.lang.String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media";
+ field public static final java.lang.String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam";
field public static final java.lang.String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls";
field public static final java.lang.String DISALLOW_REMOVE_USER = "no_remove_user";
field public static final java.lang.String DISALLOW_SHARE_LOCATION = "no_share_location";
@@ -29033,7 +29018,6 @@
method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
method public boolean setGlobalPreferredNetworkType();
method public void setLine1NumberForDisplay(java.lang.String, java.lang.String);
- method public void setLine1NumberForDisplay(long, java.lang.String, java.lang.String);
method public boolean setOperatorBrandOverride(java.lang.String);
field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
diff --git a/api/removed.txt b/api/removed.txt
index 3c16276..c8a3b4b 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -22,14 +22,6 @@
}
-package android.service.notification {
-
- public static class NotificationListenerService.Ranking {
- method public boolean meetsInterruptionFilter();
- }
-
-}
-
package android.view {
public static class WindowManager.LayoutParams extends android.view.ViewGroup.LayoutParams implements android.os.Parcelable {
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index f4e4671..25417ed 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -92,21 +92,27 @@
*/
public static Animator loadAnimator(Resources resources, Theme theme, int id)
throws NotFoundException {
+ return loadAnimator(resources, theme, id, 1);
+ }
+
+ /** @hide */
+ public static Animator loadAnimator(Resources resources, Theme theme, int id,
+ float pathErrorScale) throws NotFoundException {
XmlResourceParser parser = null;
try {
parser = resources.getAnimation(id);
- return createAnimatorFromXml(resources, theme, parser);
+ return createAnimatorFromXml(resources, theme, parser, pathErrorScale);
} catch (XmlPullParserException ex) {
Resources.NotFoundException rnf =
new Resources.NotFoundException("Can't load animation resource ID #0x" +
- Integer.toHexString(id));
+ Integer.toHexString(id));
rnf.initCause(ex);
throw rnf;
} catch (IOException ex) {
Resources.NotFoundException rnf =
new Resources.NotFoundException("Can't load animation resource ID #0x" +
- Integer.toHexString(id));
+ Integer.toHexString(id));
rnf.initCause(ex);
throw rnf;
} finally {
@@ -177,7 +183,7 @@
}
if (animator == null) {
animator = createAnimatorFromXml(context.getResources(),
- context.getTheme(), parser);
+ context.getTheme(), parser, 1f);
}
if (animator == null) {
@@ -248,9 +254,11 @@
* @param arrayAnimator Incoming typed array for Animator's attributes.
* @param arrayObjectAnimator Incoming typed array for Object Animator's
* attributes.
+ * @param pixelSize The relative pixel size, used to calculate the
+ * maximum error for path animations.
*/
private static void parseAnimatorFromTypeArray(ValueAnimator anim,
- TypedArray arrayAnimator, TypedArray arrayObjectAnimator) {
+ TypedArray arrayAnimator, TypedArray arrayObjectAnimator, float pixelSize) {
long duration = arrayAnimator.getInt(R.styleable.Animator_duration, 300);
long startDelay = arrayAnimator.getInt(R.styleable.Animator_startOffset, 0);
@@ -303,7 +311,7 @@
}
if (arrayObjectAnimator != null) {
- setupObjectAnimator(anim, arrayObjectAnimator, getFloats);
+ setupObjectAnimator(anim, arrayObjectAnimator, getFloats, pixelSize);
}
}
@@ -351,9 +359,11 @@
* @param anim The target Animator which will be updated.
* @param arrayObjectAnimator TypedArray for the ObjectAnimator.
* @param getFloats True if the value type is float.
+ * @param pixelSize The relative pixel size, used to calculate the
+ * maximum error for path animations.
*/
private static void setupObjectAnimator(ValueAnimator anim, TypedArray arrayObjectAnimator,
- boolean getFloats) {
+ boolean getFloats, float pixelSize) {
ObjectAnimator oa = (ObjectAnimator) anim;
String pathData = arrayObjectAnimator.getString(R.styleable.PropertyAnimator_pathData);
@@ -370,7 +380,8 @@
+ " propertyXName or propertyYName is needed for PathData");
} else {
Path path = PathParser.createPathFromPathData(pathData);
- PathKeyframes keyframeSet = KeyframeSet.ofPath(path);
+ float error = 0.5f * pixelSize; // max half a pixel error
+ PathKeyframes keyframeSet = KeyframeSet.ofPath(path, error);
Keyframes xKeyframes;
Keyframes yKeyframes;
if (getFloats) {
@@ -487,13 +498,15 @@
}
}
- private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser)
+ private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser,
+ float pixelSize)
throws XmlPullParserException, IOException {
- return createAnimatorFromXml(res, theme, parser, Xml.asAttributeSet(parser), null, 0);
+ return createAnimatorFromXml(res, theme, parser, Xml.asAttributeSet(parser), null, 0,
+ pixelSize);
}
private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser,
- AttributeSet attrs, AnimatorSet parent, int sequenceOrdering)
+ AttributeSet attrs, AnimatorSet parent, int sequenceOrdering, float pixelSize)
throws XmlPullParserException, IOException {
Animator anim = null;
@@ -513,9 +526,9 @@
String name = parser.getName();
if (name.equals("objectAnimator")) {
- anim = loadObjectAnimator(res, theme, attrs);
+ anim = loadObjectAnimator(res, theme, attrs, pixelSize);
} else if (name.equals("animator")) {
- anim = loadAnimator(res, theme, attrs, null);
+ anim = loadAnimator(res, theme, attrs, null, pixelSize);
} else if (name.equals("set")) {
anim = new AnimatorSet();
TypedArray a;
@@ -526,7 +539,8 @@
}
int ordering = a.getInt(R.styleable.AnimatorSet_ordering,
TOGETHER);
- createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering);
+ createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering,
+ pixelSize);
a.recycle();
} else {
throw new RuntimeException("Unknown animator name: " + parser.getName());
@@ -556,11 +570,11 @@
}
- private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs)
- throws NotFoundException {
+ private static ObjectAnimator loadObjectAnimator(Resources res, Theme theme, AttributeSet attrs,
+ float pathErrorScale) throws NotFoundException {
ObjectAnimator anim = new ObjectAnimator();
- loadAnimator(res, theme, attrs, anim);
+ loadAnimator(res, theme, attrs, anim, pathErrorScale);
return anim;
}
@@ -575,7 +589,7 @@
* ObjectAnimator
*/
private static ValueAnimator loadAnimator(Resources res, Theme theme,
- AttributeSet attrs, ValueAnimator anim)
+ AttributeSet attrs, ValueAnimator anim, float pathErrorScale)
throws NotFoundException {
TypedArray arrayAnimator = null;
@@ -601,7 +615,7 @@
anim = new ValueAnimator();
}
- parseAnimatorFromTypeArray(anim, arrayAnimator, arrayObjectAnimator);
+ parseAnimatorFromTypeArray(anim, arrayAnimator, arrayObjectAnimator, pathErrorScale);
final int resID =
arrayAnimator.getResourceId(R.styleable.Animator_interpolator, 0);
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 7c13dbe..0aa8fdd 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -636,6 +636,7 @@
anim.mNodes = new ArrayList<Node>();
anim.mSortedNodes = new ArrayList<Node>();
anim.mReversible = mReversible;
+ anim.mSetListener = null;
// Walk through the old nodes list, cloning each node and adding it to the new nodemap.
// One problem is that the old node dependencies point to nodes in the old AnimatorSet.
diff --git a/core/java/android/animation/KeyframeSet.java b/core/java/android/animation/KeyframeSet.java
index fc9bbb1..8d15db2 100644
--- a/core/java/android/animation/KeyframeSet.java
+++ b/core/java/android/animation/KeyframeSet.java
@@ -154,6 +154,10 @@
return new PathKeyframes(path);
}
+ public static PathKeyframes ofPath(Path path, float error) {
+ return new PathKeyframes(path, error);
+ }
+
/**
* Sets the TypeEvaluator to be used when calculating animated values. This object
* is required only for KeyframeSets that are not either IntKeyframeSet or FloatKeyframeSet,
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 394b183..677fcef 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2295,6 +2295,13 @@
reply.writeNoException();
return true;
}
+
+ case BOOT_ANIMATION_COMPLETE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ bootAnimationComplete();
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -5301,5 +5308,16 @@
reply.recycle();
}
+ @Override
+ public void bootAnimationComplete() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(BOOT_ANIMATION_COMPLETE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java
index 9f49194..43fa3f0 100644
--- a/core/java/android/app/ActivityTransitionCoordinator.java
+++ b/core/java/android/app/ActivityTransitionCoordinator.java
@@ -599,17 +599,18 @@
mOriginalAlphas.put(view, view.getAlpha());
}
view.setAlpha(0f);
- view.setTransitionAlpha(0f);
}
}
- protected void showViews(ArrayList<View> views) {
+ protected void showViews(ArrayList<View> views, boolean setTransitionAlpha) {
int count = views.size();
for (int i = 0; i < count; i++) {
View view = views.get(i);
Float alpha = mOriginalAlphas.remove(view);
if (alpha != null) {
view.setAlpha(alpha);
+ }
+ if (setTransitionAlpha) {
view.setTransitionAlpha(1f);
}
}
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 8227915..b09f169 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -38,7 +38,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Collection;
final class BackStackState implements Parcelable {
final int[] mOps;
@@ -745,13 +744,8 @@
SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
-
calculateFragments(firstOutFragments, lastInFragments);
-
- TransitionState state = null;
- if (firstOutFragments.size() != 0 || lastInFragments.size() != 0) {
- state = beginTransition(firstOutFragments, lastInFragments, false);
- }
+ beginTransition(firstOutFragments, lastInFragments, false);
Op op = mHead;
while (op != null) {
@@ -842,10 +836,6 @@
if (mAddToBackStack) {
mManager.addBackStackState(this);
}
-
- if (state != null) {
- updateTransitionEndState(state, firstOutFragments, lastInFragments, false);
- }
}
private static void setFirstOut(SparseArray<Fragment> fragments, Fragment fragment) {
@@ -920,43 +910,6 @@
op = op.next;
}
-
- if (!haveTransitions(firstOutFragments, lastInFragments, false)) {
- firstOutFragments.clear();
- lastInFragments.clear();
- }
- }
-
- /**
- * @return true if custom transitions exist on any fragment in firstOutFragments or
- * lastInFragments or false otherwise.
- */
- private static boolean haveTransitions(SparseArray<Fragment> firstOutFragments,
- SparseArray<Fragment> lastInFragments, boolean isBack) {
- for (int i = firstOutFragments.size() - 1; i >= 0; i--) {
- Fragment f = firstOutFragments.valueAt(i);
- if (isBack) {
- if (f.getReturnTransition() != null ||
- f.getSharedElementReturnTransition() != null) {
- return true;
- }
- } else if (f.getExitTransition() != null) {
- return true;
- }
- }
-
- for (int i = lastInFragments.size() - 1; i >= 0; i--) {
- Fragment f = lastInFragments.valueAt(i);
- if (isBack) {
- if (f.getReenterTransition() != null) {
- return true;
- }
- } else if (f.getEnterTransition() != null ||
- f.getSharedElementEnterTransition() != null) {
- return true;
- }
- }
- return false;
}
/**
@@ -1003,11 +956,6 @@
op = op.next;
}
-
- if (!haveTransitions(firstOutFragments, lastInFragments, true)) {
- firstOutFragments.clear();
- lastInFragments.clear();
- }
}
/**
@@ -1038,8 +986,8 @@
* @param isBack true if this is popping the back stack or false if this is a
* forward operation.
* @return The TransitionState used to complete the operation of the transition
- * in {@link #updateTransitionEndState(android.app.BackStackRecord.TransitionState,
- * android.util.SparseArray, android.util.SparseArray, boolean)}.
+ * in {@link #setNameOverrides(android.app.BackStackRecord.TransitionState, java.util.ArrayList,
+ * java.util.ArrayList)}.
*/
private TransitionState beginTransition(SparseArray<Fragment> firstOutFragments,
SparseArray<Fragment> lastInFragments, boolean isBack) {
@@ -1050,16 +998,11 @@
// add any, then no views will be targeted.
state.nonExistentView = new View(mManager.mActivity);
- ArrayMap<String, View> tempViews1 = new ArrayMap<String, View>();
- ArrayMap<String, View> tempViews2 = new ArrayMap<String, View>();
- ArrayList<String> tempNames = new ArrayList<String>();
- ArrayList<View> tempViewList = new ArrayList<View>();
-
// Go over all leaving fragments.
for (int i = 0; i < firstOutFragments.size(); i++) {
int containerId = firstOutFragments.keyAt(i);
configureTransitions(containerId, state, isBack, firstOutFragments,
- lastInFragments, tempViews1, tempViews2, tempNames, tempViewList);
+ lastInFragments);
}
// Now go over all entering fragments that didn't have a leaving fragment.
@@ -1067,28 +1010,33 @@
int containerId = lastInFragments.keyAt(i);
if (firstOutFragments.get(containerId) == null) {
configureTransitions(containerId, state, isBack, firstOutFragments,
- lastInFragments, tempViews1, tempViews2, tempNames, tempViewList);
+ lastInFragments);
}
}
-
- if (state.overallTransitions.size() == 0) {
- state = null;
- }
return state;
}
+ private static Transition cloneTransition(Transition transition) {
+ if (transition != null) {
+ transition = transition.clone();
+ }
+ return transition;
+ }
+
private static Transition getEnterTransition(Fragment inFragment, boolean isBack) {
if (inFragment == null) {
return null;
}
- return isBack ? inFragment.getReenterTransition() : inFragment.getEnterTransition();
+ return cloneTransition(isBack ? inFragment.getReenterTransition() :
+ inFragment.getEnterTransition());
}
private static Transition getExitTransition(Fragment outFragment, boolean isBack) {
if (outFragment == null) {
return null;
}
- return isBack ? outFragment.getReturnTransition() : outFragment.getExitTransition();
+ return cloneTransition(isBack ? outFragment.getReturnTransition() :
+ outFragment.getExitTransition());
}
private static Transition getSharedElementTransition(Fragment inFragment, Fragment outFragment,
@@ -1096,34 +1044,32 @@
if (inFragment == null || outFragment == null) {
return null;
}
- return isBack ? outFragment.getSharedElementReturnTransition() :
- inFragment.getSharedElementEnterTransition();
+ return cloneTransition(isBack ? outFragment.getSharedElementReturnTransition() :
+ inFragment.getSharedElementEnterTransition());
}
- private static Transition captureExitingViews(Transition exitTransition, Fragment outFragment,
- ArrayList<View> viewList) {
+ private static ArrayList<View> captureExitingViews(Transition exitTransition,
+ Fragment outFragment) {
+ ArrayList<View> viewList = null;
if (exitTransition != null) {
+ viewList = new ArrayList<View>();
View root = outFragment.getView();
- viewList.clear();
root.captureTransitioningViews(viewList);
- if (viewList.isEmpty()) {
- exitTransition = null;
- } else {
- addTransitioningViews(exitTransition, viewList);
- }
+ addTargets(exitTransition, viewList);
}
- return exitTransition;
+ return viewList;
}
private ArrayMap<String, View> remapSharedElements(TransitionState state, Fragment outFragment,
- ArrayMap<String, View> namedViews, ArrayMap<String, View> tempViews2, boolean isBack) {
+ boolean isBack) {
+ ArrayMap<String, View> namedViews = new ArrayMap<String, View>();
if (mSharedElementSourceNames != null) {
outFragment.getView().findNamedViews(namedViews);
if (isBack) {
namedViews.retainAll(mSharedElementTargetNames);
} else {
namedViews = remapNames(mSharedElementSourceNames, mSharedElementTargetNames,
- namedViews, tempViews2);
+ namedViews);
}
}
@@ -1147,41 +1093,94 @@
* We will add to the views before the end state of the transition is captured so that the
* views will appear. At the start of the transition, we clear the list of targets so that
* we can restore the state of the transition and use it again.
+ *
+ * <p>The shared element transition maps its shared elements immediately prior to
+ * capturing the final state of the Transition.</p>
*/
- private void prepareEnterTransition(TransitionState state, final Transition enterTransition,
- final View container, final Fragment inFragment) {
- if (enterTransition != null) {
- final ArrayList<View> enteringViews = new ArrayList<View>();
- final View nonExistentView = state.nonExistentView;
- enterTransition.addTarget(state.nonExistentView);
- enterTransition.addListener(new Transition.TransitionListenerAdapter() {
- @Override
- public void onTransitionStart(Transition transition) {
- transition.removeListener(this);
- transition.removeTarget(nonExistentView);
- int numViews = enteringViews.size();
- for (int i = 0; i < numViews; i++) {
- transition.removeTarget(enteringViews.get(i));
- }
- }
- });
- container.getViewTreeObserver().addOnPreDrawListener(
- new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- container.getViewTreeObserver().removeOnPreDrawListener(this);
+ private ArrayList<View> addTransitionTargets(final TransitionState state,
+ final Transition enterTransition, final Transition sharedElementTransition,
+ final Transition overallTransition, final View container,
+ final Fragment inFragment, final Fragment outFragment,
+ final ArrayList<View> hiddenFragmentViews, final boolean isBack) {
+ if (enterTransition == null && sharedElementTransition == null &&
+ overallTransition == null) {
+ return null;
+ }
+ final ArrayList<View> enteringViews = new ArrayList<View>();
+ container.getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ container.getViewTreeObserver().removeOnPreDrawListener(this);
+
+ // Don't include any newly-hidden fragments in the transition.
+ excludeHiddenFragments(hiddenFragmentViews, inFragment.mContainerId,
+ overallTransition);
+
+ if (sharedElementTransition != null) {
+ ArrayMap<String, View> namedViews = mapSharedElementsIn(
+ state, isBack, inFragment);
+
+ setEpicenterIn(namedViews, state);
+
+ callSharedElementEnd(state, inFragment, outFragment, isBack,
+ namedViews);
+ }
+
+ if (enterTransition != null) {
View view = inFragment.getView();
if (view != null) {
view.captureTransitioningViews(enteringViews);
- addTransitioningViews(enterTransition, enteringViews);
+ addTargets(enterTransition, enteringViews);
}
- return true;
+ setSharedElementEpicenter(enterTransition, state);
}
- });
- setSharedElementEpicenter(enterTransition, state);
+ return true;
+ }
+ });
+ return enteringViews;
+ }
+
+ private void callSharedElementEnd(TransitionState state, Fragment inFragment,
+ Fragment outFragment, boolean isBack, ArrayMap<String, View> namedViews) {
+ SharedElementCallback sharedElementCallback = isBack ?
+ outFragment.mEnterTransitionCallback :
+ inFragment.mEnterTransitionCallback;
+ ArrayList<String> names = new ArrayList<String>(namedViews.keySet());
+ ArrayList<View> views = new ArrayList<View>(namedViews.values());
+ sharedElementCallback.onSharedElementEnd(names, views, null);
+ }
+
+ private void setEpicenterIn(ArrayMap<String, View> namedViews, TransitionState state) {
+ if (mSharedElementTargetNames != null && !namedViews.isEmpty()) {
+ // now we know the epicenter of the entering transition.
+ View epicenter = namedViews
+ .get(mSharedElementTargetNames.get(0));
+ if (epicenter != null) {
+ state.enteringEpicenterView = epicenter;
+ }
}
}
+ private ArrayMap<String, View> mapSharedElementsIn(TransitionState state,
+ boolean isBack, Fragment inFragment) {
+ // Now map the shared elements in the incoming fragment
+ ArrayMap<String, View> namedViews = mapEnteringSharedElements(state, inFragment, isBack);
+
+ // remap shared elements and set the name mapping used
+ // in the shared element transition.
+ if (isBack) {
+ inFragment.mExitTransitionCallback.onMapSharedElements(
+ mSharedElementTargetNames, namedViews);
+ setBackNameOverrides(state, namedViews, true);
+ } else {
+ inFragment.mEnterTransitionCallback.onMapSharedElements(
+ mSharedElementTargetNames, namedViews);
+ setNameOverrides(state, namedViews, true);
+ }
+ return namedViews;
+ }
+
private static Transition mergeTransitions(Transition enterTransition,
Transition exitTransition, Transition sharedElementTransition, Fragment inFragment,
boolean isBack) {
@@ -1209,26 +1208,16 @@
* Configures custom transitions for a specific fragment container.
*
* @param containerId The container ID of the fragments to configure the transition for.
- * @param state The Transition State to be shared with {@link #updateTransitionEndState(
- * android.app.BackStackRecord.TransitionState, android.util.SparseArray,
- * android.util.SparseArray, boolean)} later.
+ * @param state The Transition State keeping track of the executing transitions.
* @param firstOutFragments The list of first fragments to be removed, keyed on the
* container ID.
* @param lastInFragments The list of last fragments to be added, keyed on the
* container ID.
* @param isBack true if this is popping the back stack or false if this is a
* forward operation.
- * @param tempViews1 A temporary mapping of names to Views, used to avoid allocation
- * inside a loop.
- * @param tempViews2 A temporary mapping of names to Views, used to avoid allocation
- * inside a loop.
- * @param tempNames A temporary list of Strings, used to avoid allocation inside a loop.
- * @param tempViewList A temporary list of Views, used to avoid allocation inside a loop.
*/
private void configureTransitions(int containerId, TransitionState state, boolean isBack,
- SparseArray<Fragment> firstOutFragments, SparseArray<Fragment> lastInFragments,
- ArrayMap<String, View> tempViews1, ArrayMap<String, View> tempViews2,
- ArrayList<String> tempNames, ArrayList<View> tempViewList) {
+ SparseArray<Fragment> firstOutFragments, SparseArray<Fragment> lastInFragments) {
ViewGroup sceneRoot = (ViewGroup) mManager.mContainer.findViewById(containerId);
if (sceneRoot != null) {
Fragment inFragment = lastInFragments.get(containerId);
@@ -1238,146 +1227,150 @@
Transition sharedElementTransition = getSharedElementTransition(inFragment, outFragment,
isBack);
Transition exitTransition = getExitTransition(outFragment, isBack);
- exitTransition = captureExitingViews(exitTransition, outFragment, tempViewList);
- ArrayMap<String, View> namedViews = tempViews1;
- namedViews.clear();
- if (sharedElementTransition != null) {
- namedViews = remapSharedElements(state,
- outFragment, namedViews, tempViews2, isBack);
+ if (enterTransition == null && sharedElementTransition == null &&
+ exitTransition == null) {
+ return; // no transitions!
+ }
+ ArrayList<View> exitingViews = captureExitingViews(exitTransition, outFragment);
+ if (exitingViews == null || exitingViews.isEmpty()) {
+ exitTransition = null;
}
- // Notify the start of the transition.
- SharedElementCallback callback = isBack ?
- outFragment.mEnterTransitionCallback :
- inFragment.mEnterTransitionCallback;
- tempNames.clear();
- tempNames.addAll(namedViews.keySet());
- tempViewList.clear();
- tempViewList.addAll(namedViews.values());
- callback.onSharedElementStart(tempNames, tempViewList, null);
+ ArrayMap<String, View> namedViews = null;
+ if (sharedElementTransition != null) {
+ namedViews = remapSharedElements(state, outFragment, isBack);
+
+ // Notify the start of the transition.
+ SharedElementCallback callback = isBack ?
+ outFragment.mEnterTransitionCallback :
+ inFragment.mEnterTransitionCallback;
+ ArrayList<String> names = new ArrayList<String>(namedViews.keySet());
+ ArrayList<View> views = new ArrayList<View>(namedViews.values());
+ callback.onSharedElementStart(names, views, null);
+ }
// Set the epicenter of the exit transition
- if (mSharedElementTargetNames != null && exitTransition != null) {
+ if (mSharedElementTargetNames != null && exitTransition != null && namedViews != null) {
View epicenterView = namedViews.get(mSharedElementTargetNames.get(0));
if (epicenterView != null) {
setEpicenter(exitTransition, epicenterView);
}
}
- prepareEnterTransition(state, enterTransition, sceneRoot, inFragment);
-
Transition transition = mergeTransitions(enterTransition, exitTransition,
sharedElementTransition, inFragment, isBack);
if (transition != null) {
- state.overallTransitions.put(containerId, transition);
+ ArrayList<View> hiddenFragments = new ArrayList<View>();
+ ArrayList<View> enteringViews = addTransitionTargets(state, enterTransition,
+ sharedElementTransition, transition, sceneRoot, inFragment, outFragment,
+ hiddenFragments, isBack);
+
transition.setNameOverrides(state.nameOverrides);
// We want to exclude hidden views later, so we need a non-null list in the
// transition now.
transition.excludeTarget(state.nonExistentView, true);
// Now exclude all currently hidden fragments.
- excludeHiddenFragments(state, containerId, transition);
- cleanupHiddenFragments(transition, state);
+ excludeHiddenFragments(hiddenFragments, containerId, transition);
TransitionManager.beginDelayedTransition(sceneRoot, transition);
+ // Remove the view targeting after the transition starts
+ removeTargetedViewsFromTransitions(sceneRoot, state.nonExistentView,
+ enterTransition, enteringViews, exitTransition, exitingViews,
+ transition, hiddenFragments);
}
}
}
/**
+ * After the transition has started, remove all targets that we added to the transitions
+ * so that the transitions are left in a clean state.
+ */
+ private void removeTargetedViewsFromTransitions(
+ final ViewGroup sceneRoot, final View nonExistingView,
+ final Transition enterTransition, final ArrayList<View> enteringViews,
+ final Transition exitTransition, final ArrayList<View> exitingViews,
+ final Transition overallTransition, final ArrayList<View> hiddenViews) {
+ if (enterTransition != null || exitTransition != null) {
+ sceneRoot.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ sceneRoot.getViewTreeObserver().removeOnPreDrawListener(this);
+ if (enterTransition != null) {
+ enterTransition.removeTarget(nonExistingView);
+ removeTargets(enterTransition, enteringViews);
+ }
+ if (exitTransition != null) {
+ removeTargets(exitTransition, exitingViews);
+ }
+ int numViews = hiddenViews.size();
+ for (int i = 0; i < numViews; i++) {
+ overallTransition.excludeTarget(hiddenViews.get(i), false);
+ }
+ overallTransition.excludeTarget(nonExistingView, false);
+ return true;
+ }
+ });
+ }
+ }
+
+ private static void removeTargets(Transition transition, ArrayList<View> views) {
+ int numViews = views.size();
+ for (int i = 0; i < numViews; i++) {
+ transition.removeTarget(views.get(i));
+ }
+ }
+
+ private static void addTargets(Transition transition, ArrayList<View> views) {
+ int numViews = views.size();
+ for (int i = 0; i < numViews; i++) {
+ transition.addTarget(views.get(i));
+ }
+ }
+
+ /**
* Remaps a name-to-View map, substituting different names for keys.
*
* @param inMap A list of keys found in the map, in the order in toGoInMap
* @param toGoInMap A list of keys to use for the new map, in the order of inMap
* @param namedViews The current mapping
- * @param tempMap A temporary mapping that will be filled with the new values.
- * @return tempMap after it has been mapped with the new names as keys.
+ * @return a new Map after it has been mapped with the new names as keys.
*/
private static ArrayMap<String, View> remapNames(ArrayList<String> inMap,
- ArrayList<String> toGoInMap, ArrayMap<String, View> namedViews,
- ArrayMap<String, View> tempMap) {
- tempMap.clear();
+ ArrayList<String> toGoInMap, ArrayMap<String, View> namedViews) {
+ ArrayMap<String, View> remappedViews = new ArrayMap<String, View>();
if (!namedViews.isEmpty()) {
int numKeys = inMap.size();
for (int i = 0; i < numKeys; i++) {
View view = namedViews.get(inMap.get(i));
+
if (view != null) {
- tempMap.put(toGoInMap.get(i), view);
+ remappedViews.put(toGoInMap.get(i), view);
}
}
}
- return tempMap;
+ return remappedViews;
}
/**
- * After making all fragment changes, this updates the custom transitions to take into
- * account the entering views and any remapping.
+ * Maps shared elements to views in the entering fragment.
*
* @param state The transition State as returned from {@link #beginTransition(
* android.util.SparseArray, android.util.SparseArray, boolean)}.
- * @param outFragments The list of first fragments to be removed, keyed on the
- * container ID.
- * @param inFragments The list of last fragments to be added, keyed on the
- * container ID.
+ * @param inFragment The last fragment to be added.
* @param isBack true if this is popping the back stack or false if this is a
* forward operation.
*/
- private void updateTransitionEndState(TransitionState state, SparseArray<Fragment> outFragments,
- SparseArray<Fragment> inFragments, boolean isBack) {
- ArrayMap<String, View> tempViews1 = new ArrayMap<String, View>();
- ArrayMap<String, View> tempViews2 = new ArrayMap<String, View>();
- ArrayList<String> tempNames = new ArrayList<String>();
- ArrayList<View> tempViews = new ArrayList<View>();
-
- int numInFragments = inFragments.size();
- for (int i = 0; i < numInFragments; i++) {
- Fragment inFragment = inFragments.valueAt(i);
- tempViews1.clear();
- ArrayMap<String, View> namedViews = mapEnteringSharedElements(inFragment, tempViews1,
- tempViews2, isBack);
- // remap shared elements and set the name mapping used in the shared element transition.
- if (isBack) {
- inFragment.mExitTransitionCallback.onMapSharedElements(
- mSharedElementTargetNames, namedViews);
- setBackNameOverrides(state, namedViews, true);
- } else {
- inFragment.mEnterTransitionCallback.onMapSharedElements(
- mSharedElementTargetNames, namedViews);
- setNameOverrides(state, namedViews, true);
- }
-
- if (mSharedElementTargetNames != null && !namedViews.isEmpty()) {
- // now we know the epicenter of the entering transition.
- View epicenter = namedViews.get(mSharedElementTargetNames.get(0));
- if (epicenter != null) {
- state.enteringEpicenterView = epicenter;
- }
- }
-
- int containerId = inFragments.keyAt(i);
- SharedElementCallback sharedElementCallback = isBack ?
- outFragments.get(containerId).mEnterTransitionCallback :
- inFragment.mEnterTransitionCallback;
- tempNames.clear();
- tempNames.addAll(namedViews.keySet());
- tempViews.clear();
- tempViews.addAll(namedViews.values());
- sharedElementCallback.onSharedElementEnd(tempNames, tempViews, null);
- }
-
- // Don't include any newly-hidden fragments in the transition.
- excludeHiddenFragments(state);
- }
-
- private ArrayMap<String, View> mapEnteringSharedElements(Fragment inFragment,
- ArrayMap<String, View> namedViews, ArrayMap<String, View> tempViews2, boolean isBack) {
+ private ArrayMap<String, View> mapEnteringSharedElements(TransitionState state,
+ Fragment inFragment, boolean isBack) {
+ ArrayMap<String, View> namedViews = new ArrayMap<String, View>();
View root = inFragment.getView();
if (root != null) {
if (mSharedElementSourceNames != null) {
root.findNamedViews(namedViews);
if (isBack) {
namedViews = remapNames(mSharedElementSourceNames,
- mSharedElementTargetNames, namedViews, tempViews2);
+ mSharedElementTargetNames, namedViews);
} else {
namedViews.retainAll(mSharedElementTargetNames);
}
@@ -1386,21 +1379,7 @@
return namedViews;
}
- private static void cleanupHiddenFragments(Transition transition, TransitionState state) {
- final ArrayList<View> hiddenViews = state.hiddenFragmentViews;
- transition.addListener(new Transition.TransitionListenerAdapter() {
- @Override
- public void onTransitionStart(Transition transition) {
- transition.removeListener(this);
- int numViews = hiddenViews.size();
- for (int i = 0; i < numViews; i++) {
- transition.excludeTarget(hiddenViews.get(i), false);
- }
- }
- });
- }
-
- private void excludeHiddenFragments(TransitionState state, int containerId,
+ private void excludeHiddenFragments(final ArrayList<View> hiddenFragmentViews, int containerId,
Transition transition) {
if (mManager.mAdded != null) {
for (int i = 0; i < mManager.mAdded.size(); i++) {
@@ -1408,44 +1387,19 @@
if (fragment.mView != null && fragment.mContainer != null &&
fragment.mContainerId == containerId) {
if (fragment.mHidden) {
- if (!state.hiddenFragmentViews.contains(fragment.mView)) {
+ if (!hiddenFragmentViews.contains(fragment.mView)) {
transition.excludeTarget(fragment.mView, true);
- state.hiddenFragmentViews.add(fragment.mView);
+ hiddenFragmentViews.add(fragment.mView);
}
} else {
transition.excludeTarget(fragment.mView, false);
- state.hiddenFragmentViews.remove(fragment.mView);
+ hiddenFragmentViews.remove(fragment.mView);
}
}
}
}
}
- private void excludeHiddenFragments(TransitionState state) {
- int numTransitions = state.overallTransitions.size();
- for (int i = 0; i < numTransitions; i++) {
- Transition transition = state.overallTransitions.valueAt(i);
- int containerId = state.overallTransitions.keyAt(i);
- excludeHiddenFragments(state, containerId, transition);
- }
- }
-
- private static void addTransitioningViews(Transition transition, final Collection<View> views) {
- for (View view : views) {
- transition.addTarget(view);
- }
-
- transition.addListener(new Transition.TransitionListenerAdapter() {
- @Override
- public void onTransitionStart(Transition transition) {
- transition.removeListener(this);
- for (View view : views) {
- transition.removeTarget(view);
- }
- }
- });
- }
-
private static void setEpicenter(Transition transition, View view) {
final Rect epicenter = new Rect();
view.getBoundsOnScreen(epicenter);
@@ -1566,10 +1520,7 @@
if (doStateMove) {
mManager.moveToState(mManager.mCurState,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle, true);
- if (state != null) {
- updateTransitionEndState(state, firstOutFragments, lastInFragments, true);
- state = null;
- }
+ state = null;
}
if (mIndex >= 0) {
@@ -1609,11 +1560,14 @@
for (int i = 0; i < count; i++) {
String source = mSharedElementSourceNames.get(i);
String originalTarget = mSharedElementTargetNames.get(i);
- String target = namedViews.get(originalTarget).getTransitionName();
- if (isEnd) {
- setNameOverride(state.nameOverrides, source, target);
- } else {
- setNameOverride(state.nameOverrides, target, source);
+ View view = namedViews.get(originalTarget);
+ if (view != null) {
+ String target = view.getTransitionName();
+ if (isEnd) {
+ setNameOverride(state.nameOverrides, source, target);
+ } else {
+ setNameOverride(state.nameOverrides, target, source);
+ }
}
}
}
@@ -1649,10 +1603,7 @@
}
public class TransitionState {
- public SparseArray<Transition> overallTransitions = new SparseArray<Transition>();
public ArrayMap<String, String> nameOverrides = new ArrayMap<String, String>();
- public ArrayList<View> hiddenFragmentViews = new ArrayList<View>();
-
public View enteringEpicenterView;
public View nonExistentView;
}
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index f38c108..9c7728e 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -240,7 +240,7 @@
if (!mIsCanceled) {
mIsCanceled = true;
if (getViewsTransition() == null || mIsViewsTransitionStarted) {
- showViews(mSharedElements);
+ showViews(mSharedElements, true);
} else {
mTransitioningViews.addAll(mSharedElements);
}
@@ -300,7 +300,7 @@
// Now start shared element transition
ArrayList<View> sharedElementSnapshots = createSnapshots(sharedElementState,
mSharedElementNames);
- showViews(mSharedElements);
+ showViews(mSharedElements, true);
scheduleSetSharedElementEnd(sharedElementSnapshots);
ArrayList<SharedElementOriginalState> originalImageViewState =
setSharedElementState(sharedElementState, sharedElementSnapshots);
@@ -411,7 +411,7 @@
@Override
public void onTransitionStart(Transition transition) {
mEnterViewsTransition = transition;
- showViews(mTransitioningViews);
+ showViews(mTransitioningViews, false);
super.onTransitionStart(transition);
}
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index 982bbc4..e85ec63 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -126,8 +126,8 @@
}
public void resetViews() {
- showViews(mTransitioningViews);
- showViews(mSharedElements);
+ showViews(mTransitioningViews, true);
+ showViews(mSharedElements, true);
mIsHidden = true;
if (!mIsReturning && getDecor() != null) {
getDecor().suppressLayout(false);
@@ -296,7 +296,7 @@
transition.removeListener(this);
exitTransitionComplete();
if (mIsHidden) {
- showViews(mTransitioningViews);
+ showViews(mTransitioningViews, true);
}
if (mSharedElementBundle != null) {
delayCancel();
@@ -323,7 +323,7 @@
transition.removeListener(this);
sharedElementTransitionComplete();
if (mIsHidden) {
- showViews(mSharedElements);
+ showViews(mSharedElements, true);
}
}
});
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 672ef7b..4374622 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -166,11 +166,12 @@
* activity: if the activity is stopped, no fragments inside of it can be
* started; when the activity is destroyed, all fragments will be destroyed.
*
- * <p>All subclasses of Fragment must include a public empty constructor.
+ * <p>All subclasses of Fragment must include a public no-argument constructor.
* The framework will often re-instantiate a fragment class when needed,
* in particular during state restore, and needs to be able to find this
- * constructor to instantiate it. If the empty constructor is not available,
- * a runtime exception will occur in some cases during state restore.
+ * constructor to instantiate it. If the no-argument constructor is not
+ * available, a runtime exception will occur in some cases during state
+ * restore.
*
* <p>Topics covered here:
* <ol>
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 9483680..8fa1fd53 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -327,6 +327,8 @@
public void notifyActivityDrawn(IBinder token) throws RemoteException;
public ActivityOptions getActivityOptions(IBinder token) throws RemoteException;
+ public void bootAnimationComplete() throws RemoteException;
+
public void setImmersive(IBinder token, boolean immersive) throws RemoteException;
public boolean isImmersive(IBinder token) throws RemoteException;
public boolean isTopActivityImmersive() throws RemoteException;
@@ -772,4 +774,5 @@
int GET_APP_TASK_THUMBNAIL_SIZE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+234;
int RELEASE_ACTIVITY_INSTANCE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+235;
int RELEASE_SOME_ACTIVITIES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+236;
+ int BOOT_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+237;
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index c831c25..f9e4895 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -545,8 +545,26 @@
*/
public int visibility;
+ /**
+ * Notification visibility: Show this notification in its entirety on all lockscreens.
+ *
+ * {@see #visibility}
+ */
public static final int VISIBILITY_PUBLIC = 1;
+
+ /**
+ * Notification visibility: Show this notification on all lockscreens, but conceal sensitive or
+ * private information on secure lockscreens.
+ *
+ * {@see #visibility}
+ */
public static final int VISIBILITY_PRIVATE = 0;
+
+ /**
+ * Notification visibility: Do not reveal any part of this notification on a secure lockscreen.
+ *
+ * {@see #visibility}
+ */
public static final int VISIBILITY_SECRET = -1;
/**
@@ -824,6 +842,13 @@
public static final String EXTRA_COMPACT_ACTIONS = "android.compactActions";
/**
+ * {@link #extras} key: the user that built the notification.
+ *
+ * @hide
+ */
+ public static final String EXTRA_ORIGINATING_USERID = "android.originatingUserId";
+
+ /**
* Value for {@link #EXTRA_AS_HEADS_UP} that indicates this notification should not be
* displayed in the heads up space.
*
@@ -1862,6 +1887,11 @@
private int mColor = COLOR_DEFAULT;
/**
+ * The user that built the notification originally.
+ */
+ private int mOriginatingUserId;
+
+ /**
* Contains extras related to rebuilding during the build phase.
*/
private Bundle mRebuildBundle = new Bundle();
@@ -2581,7 +2611,7 @@
// Note: This assumes that the current user can read the profile badge of the
// originating user.
return mContext.getPackageManager().getUserBadgeForDensity(
- new UserHandle(mContext.getUserId()), 0);
+ new UserHandle(mOriginatingUserId), 0);
}
private Bitmap getProfileBadge() {
@@ -2721,9 +2751,9 @@
} else {
contentView.setViewVisibility(R.id.text2, View.GONE);
if (hasProgress && (mProgressMax != 0 || mProgressIndeterminate)) {
+ contentView.setViewVisibility(R.id.progress, View.VISIBLE);
contentView.setProgressBar(
R.id.progress, mProgressMax, mProgress, mProgressIndeterminate);
- contentView.setViewVisibility(R.id.progress, View.VISIBLE);
showLine2 = true;
} else {
contentView.setViewVisibility(R.id.progress, View.GONE);
@@ -3052,6 +3082,7 @@
*/
public void populateExtras(Bundle extras) {
// Store original information used in the construction of this object
+ extras.putInt(EXTRA_ORIGINATING_USERID, mOriginatingUserId);
extras.putParcelable(EXTRA_REBUILD_CONTEXT_APPLICATION_INFO,
mContext.getApplicationInfo());
extras.putCharSequence(EXTRA_TITLE, mContentTitle);
@@ -3283,6 +3314,7 @@
// Extras.
Bundle extras = n.extras;
+ mOriginatingUserId = extras.getInt(EXTRA_ORIGINATING_USERID);
mContentTitle = extras.getCharSequence(EXTRA_TITLE);
mContentText = extras.getCharSequence(EXTRA_TEXT);
mSubText = extras.getCharSequence(EXTRA_SUB_TEXT);
@@ -3315,6 +3347,7 @@
* object.
*/
public Notification build() {
+ mOriginatingUserId = mContext.getUserId();
mHasThreeLines = hasThreeLines();
Notification n = buildUnstyled();
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 926a348..ea041e8 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -97,8 +97,7 @@
* Provisioning adds a managed profile and sets the mdm as the profile owner who has full
* control over the profile
*
- * <p>This intent must contain the extras {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}
- * {@link #EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME} and {@link #EXTRA_DEVICE_ADMIN}.
+ * <p>This intent must contain the extra {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}.
*
* <p> When managed provisioning has completed, an intent of the type
* {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcasted to the
@@ -112,7 +111,7 @@
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_PROVISION_MANAGED_PROFILE
- = "android.app.action.ACTION_PROVISION_MANAGED_PROFILE";
+ = "android.app.action.PROVISION_MANAGED_PROFILE";
/**
* A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that allows
@@ -139,21 +138,18 @@
* message containing an Nfc record with MIME type {@link #MIME_TYPE_PROVISIONING_NFC}.
*/
public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME
- = "android.app.extra.deviceAdminPackageName";
+ = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
/**
- * A String extra holding the default name of the profile that is created during managed profile
- * provisioning.
+ * A String extra that, holds the email address of the account which a managed profile is
+ * created for. Used with {@link #ACTION_PROVISION_MANAGED_PROFILE} and
+ * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE}.
*
- * <p>Use with {@link #ACTION_PROVISION_MANAGED_PROFILE}
- */
- public static final String EXTRA_PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME
- = "android.app.extra.PROVISIONING_DEFAULT_MANAGED_PROFILE_NAME";
-
- /**
- * A bundle key, used in the bundle extra {@link #EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE}. The
- * corresponding value holds the email address of the account which the managed profile is
- * created for.
+ * <p> If the {@link #ACTION_PROVISION_MANAGED_PROFILE} intent that starts managed provisioning
+ * contains this extra, it is forwarded in the
+ * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} intent to the mobile
+ * device management application that was set as the profile owner during provisioning.
+ * It is usually used to avoid that the user has to enter their email address twice.
*/
public static final String KEY_PROVISIONING_EMAIL_ADDRESS
= "android.app.key.PROVISIONING_EMAIL_ADDRESS";
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 1bb4eba..9151a16 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -218,6 +218,7 @@
*/
@SystemApi
public boolean isBackupEnabled() {
+ checkServiceBinder();
if (sService != null) {
try {
return sService.isBackupEnabled();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 36d15a0..5ce968b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1525,6 +1525,22 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+ * The device supports verified boot.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_VERIFIED_BOOT = "android.software.verified_boot";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+ * The device supports secure removal of users. When a user is deleted the data associated
+ * with that user is securely deleted and no longer available.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_SECURELY_REMOVES_USERS
+ = "android.software.securely_removes_users";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
* The device has a full implementation of the android.webkit.* APIs. Devices
* lacking this feature will not have a functioning WebView implementation.
*/
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e0fd532..ddb0a6d 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1099,9 +1099,12 @@
}
}
}
- } catch (GeneralSecurityException | IOException | RuntimeException e) {
+ } catch (GeneralSecurityException e) {
throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
"Failed to collect certificates from " + apkPath, e);
+ } catch (IOException | RuntimeException e) {
+ throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
+ "Failed to collect certificates from " + apkPath, e);
} finally {
closeQuietly(jarFile);
}
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index c0383a3..c03be32 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -89,6 +89,7 @@
/** User is only partially created. */
public boolean partial;
+ public boolean guestToRemove;
public UserInfo(int id, String name, int flags) {
this(id, name, null, flags);
@@ -147,6 +148,7 @@
lastLoggedInTime = orig.lastLoggedInTime;
partial = orig.partial;
profileGroupId = orig.profileGroupId;
+ guestToRemove = orig.guestToRemove;
}
public UserHandle getUserHandle() {
@@ -172,6 +174,7 @@
dest.writeLong(lastLoggedInTime);
dest.writeInt(partial ? 1 : 0);
dest.writeInt(profileGroupId);
+ dest.writeInt(guestToRemove ? 1 : 0);
}
public static final Parcelable.Creator<UserInfo> CREATOR
@@ -194,5 +197,6 @@
lastLoggedInTime = source.readLong();
partial = source.readInt() != 0;
profileGroupId = source.readInt();
+ guestToRemove = source.readInt() != 0;
}
}
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 29e42ea..ce83028 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -483,7 +483,9 @@
* and in the buffers sent to each output Surface. These buffer
* timestamps are accessible through, for example,
* {@link android.media.Image#getTimestamp() Image.getTimestamp()} or
- * {@link android.graphics.SurfaceTexture#getTimestamp()}.</p>
+ * {@link android.graphics.SurfaceTexture#getTimestamp()}.
+ * The frame number included is equal to the frame number that will be included in
+ * {@link CaptureResult#getFrameNumber}.</p>
*
* <p>For the simplest way to play a shutter sound camera shutter or a
* video recording start/stop sound, see the
@@ -494,10 +496,21 @@
* @param session the session returned by {@link CameraDevice#createCaptureSession}
* @param request the request for the capture that just begun
* @param timestamp the timestamp at start of capture, in nanoseconds.
+ * @param frameNumber the frame number for this capture
*
* @see android.media.MediaActionSound
*/
public void onCaptureStarted(CameraCaptureSession session,
+ CaptureRequest request, long timestamp, long frameNumber) {
+ // Temporary trampoline for API change transition
+ onCaptureStarted(session, request, timestamp);
+ }
+
+ /**
+ * Temporary for API change transition
+ * @hide
+ */
+ public void onCaptureStarted(CameraCaptureSession session,
CaptureRequest request, long timestamp) {
// default empty implementation
}
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 6d0d505..93eb3de 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -731,6 +731,8 @@
/**
* <p>List of areas to use for
* metering.</p>
+ * <p>Optional. Not available if {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AE android.control.maxRegionsAe} is 0.
+ * Otherwise will always be present.</p>
* <p>The coordinate system is based on the active pixel array,
* with (0,0) being the top-left pixel in the active pixel array, and
* ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
@@ -746,7 +748,9 @@
* outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
* the camera device will ignore the sections outside the region and output the
* used sections in the result metadata.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
+ * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AE
* @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
*/
@@ -820,6 +824,8 @@
/**
* <p>List of areas to use for focus
* estimation.</p>
+ * <p>Optional. Not available if {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AF android.control.maxRegionsAf} is 0.
+ * Otherwise will always be present.</p>
* <p>The coordinate system is based on the active pixel array,
* with (0,0) being the top-left pixel in the active pixel array, and
* ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
@@ -835,7 +841,9 @@
* outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
* the camera device will ignore the sections outside the region and output the
* used sections in the result metadata.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
+ * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AF
* @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
*/
@@ -921,6 +929,8 @@
/**
* <p>List of areas to use for illuminant
* estimation.</p>
+ * <p>Optional. Not available if {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AWB android.control.maxRegionsAwb} is 0.
+ * Otherwise will always be present.</p>
* <p>The coordinate system is based on the active pixel array,
* with (0,0) being the top-left pixel in the active pixel array, and
* ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
@@ -936,7 +946,9 @@
* outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
* the camera device will ignore the sections outside the region and output the
* used sections in the result metadata.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
+ * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AWB
* @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
*/
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 754d83e..01276a2 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -582,6 +582,8 @@
/**
* <p>List of areas to use for
* metering.</p>
+ * <p>Optional. Not available if {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AE android.control.maxRegionsAe} is 0.
+ * Otherwise will always be present.</p>
* <p>The coordinate system is based on the active pixel array,
* with (0,0) being the top-left pixel in the active pixel array, and
* ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
@@ -597,7 +599,9 @@
* outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
* the camera device will ignore the sections outside the region and output the
* used sections in the result metadata.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
+ * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AE
* @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
*/
@@ -870,6 +874,8 @@
/**
* <p>List of areas to use for focus
* estimation.</p>
+ * <p>Optional. Not available if {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AF android.control.maxRegionsAf} is 0.
+ * Otherwise will always be present.</p>
* <p>The coordinate system is based on the active pixel array,
* with (0,0) being the top-left pixel in the active pixel array, and
* ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
@@ -885,7 +891,9 @@
* outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
* the camera device will ignore the sections outside the region and output the
* used sections in the result metadata.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
+ * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AF
* @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
*/
@@ -1369,6 +1377,8 @@
/**
* <p>List of areas to use for illuminant
* estimation.</p>
+ * <p>Optional. Not available if {@link CameraCharacteristics#CONTROL_MAX_REGIONS_AWB android.control.maxRegionsAwb} is 0.
+ * Otherwise will always be present.</p>
* <p>The coordinate system is based on the active pixel array,
* with (0,0) being the top-left pixel in the active pixel array, and
* ({@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.width - 1,
@@ -1384,7 +1394,9 @@
* outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in capture result metadata,
* the camera device will ignore the sections outside the region and output the
* used sections in the result metadata.</p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
+ * @see CameraCharacteristics#CONTROL_MAX_REGIONS_AWB
* @see CaptureRequest#SCALER_CROP_REGION
* @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
*/
diff --git a/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java b/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
index 02c3d87..c66a3a4 100644
--- a/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
+++ b/core/java/android/hardware/camera2/dispatch/MethodNameInvoker.java
@@ -48,7 +48,8 @@
/**
* Invoke a method by its name.
*
- * <p>If more than one method exists in {@code targetClass}, the first method will be used.</p>
+ * <p>If more than one method exists in {@code targetClass}, the first method with the right
+ * number of arguments will be used, and later calls will all use that method.</p>
*
* @param methodName
* The name of the method, which will be matched 1:1 to the destination method
@@ -68,8 +69,9 @@
Method targetMethod = mMethods.get(methodName);
if (targetMethod == null) {
for (Method method : mTargetClass.getMethods()) {
- // TODO future: match by # of params and types of params if possible
- if (method.getName().equals(methodName)) {
+ // TODO future: match types of params if possible
+ if (method.getName().equals(methodName) &&
+ (params.length == method.getParameterTypes().length) ) {
targetMethod = method;
mMethods.put(methodName, targetMethod);
break;
diff --git a/core/java/android/hardware/camera2/impl/CallbackProxies.java b/core/java/android/hardware/camera2/impl/CallbackProxies.java
index e5ddb7a..f0217ac 100644
--- a/core/java/android/hardware/camera2/impl/CallbackProxies.java
+++ b/core/java/android/hardware/camera2/impl/CallbackProxies.java
@@ -98,8 +98,8 @@
@Override
public void onCaptureStarted(CameraDevice camera,
- CaptureRequest request, long timestamp) {
- mProxy.invoke("onCaptureStarted", camera, request, timestamp);
+ CaptureRequest request, long timestamp, long frameNumber) {
+ mProxy.invoke("onCaptureStarted", camera, request, timestamp, frameNumber);
}
@Override
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 843f117..0057f61 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -143,7 +143,6 @@
}
checkNotClosed();
- checkLegalToCapture();
handler = checkHandler(handler, callback);
@@ -166,7 +165,6 @@
}
checkNotClosed();
- checkLegalToCapture();
handler = checkHandler(handler, callback);
@@ -188,7 +186,6 @@
}
checkNotClosed();
- checkLegalToCapture();
handler = checkHandler(handler, callback);
@@ -211,7 +208,6 @@
}
checkNotClosed();
- checkLegalToCapture();
handler = checkHandler(handler, callback);
@@ -542,13 +538,6 @@
}
}
- private void checkLegalToCapture() {
- if (mAborting) {
- throw new IllegalStateException(
- "Session is aborting captures; new captures are not permitted");
- }
- }
-
private void checkNotClosed() {
if (mClosed) {
throw new IllegalStateException(
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index d454092..f011d60 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -803,7 +803,7 @@
* @see android.media.MediaActionSound
*/
public void onCaptureStarted(CameraDevice camera,
- CaptureRequest request, long timestamp) {
+ CaptureRequest request, long timestamp, long frameNumber) {
// default empty implementation
}
@@ -1237,8 +1237,10 @@
@Override
public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {
int requestId = resultExtras.getRequestId();
+ final long frameNumber = resultExtras.getFrameNumber();
+
if (DEBUG) {
- Log.d(TAG, "Capture started for id " + requestId);
+ Log.d(TAG, "Capture started for id " + requestId + " frame number " + frameNumber);
}
final CaptureCallbackHolder holder;
@@ -1263,7 +1265,7 @@
holder.getCallback().onCaptureStarted(
CameraDeviceImpl.this,
holder.getRequest(resultExtras.getSubsequenceId()),
- timestamp);
+ timestamp, frameNumber);
}
}
});
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index a8d1018..3c0e0e4 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -675,15 +675,13 @@
* request.availableRequestKeys
*/
{
- CaptureRequest.Key<?> availableKeys[] = new CaptureRequest.Key<?>[] {
+ CaptureRequest.Key<?> defaultAvailableKeys[] = new CaptureRequest.Key<?>[] {
CaptureRequest.CONTROL_AE_ANTIBANDING_MODE,
CaptureRequest.CONTROL_AE_EXPOSURE_COMPENSATION,
CaptureRequest.CONTROL_AE_LOCK,
CaptureRequest.CONTROL_AE_MODE,
- CaptureRequest.CONTROL_AE_REGIONS,
CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
CaptureRequest.CONTROL_AF_MODE,
- CaptureRequest.CONTROL_AF_REGIONS,
CaptureRequest.CONTROL_AF_TRIGGER,
CaptureRequest.CONTROL_AWB_LOCK,
CaptureRequest.CONTROL_AWB_MODE,
@@ -704,21 +702,32 @@
CaptureRequest.SCALER_CROP_REGION,
CaptureRequest.STATISTICS_FACE_DETECT_MODE,
};
- m.set(REQUEST_AVAILABLE_REQUEST_KEYS, getTagsForKeys(availableKeys));
+ ArrayList<CaptureRequest.Key<?>> availableKeys =
+ new ArrayList<CaptureRequest.Key<?>>(Arrays.asList(defaultAvailableKeys));
+
+ if (p.getMaxNumMeteringAreas() > 0) {
+ availableKeys.add(CaptureRequest.CONTROL_AE_REGIONS);
+ }
+ if (p.getMaxNumFocusAreas() > 0) {
+ availableKeys.add(CaptureRequest.CONTROL_AF_REGIONS);
+ }
+
+ CaptureRequest.Key<?> availableRequestKeys[] =
+ new CaptureRequest.Key<?>[availableKeys.size()];
+ availableKeys.toArray(availableRequestKeys);
+ m.set(REQUEST_AVAILABLE_REQUEST_KEYS, getTagsForKeys(availableRequestKeys));
}
/*
* request.availableResultKeys
*/
{
- CaptureResult.Key<?> availableKeys[] = new CaptureResult.Key<?>[] {
+ CaptureResult.Key<?> defaultAvailableKeys[] = new CaptureResult.Key<?>[] {
CaptureResult.CONTROL_AE_ANTIBANDING_MODE ,
CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION ,
CaptureResult.CONTROL_AE_LOCK ,
CaptureResult.CONTROL_AE_MODE ,
- CaptureResult.CONTROL_AE_REGIONS ,
CaptureResult.CONTROL_AF_MODE ,
- CaptureResult.CONTROL_AF_REGIONS ,
CaptureResult.CONTROL_AF_STATE ,
CaptureResult.CONTROL_AWB_MODE ,
CaptureResult.CONTROL_AWB_LOCK ,
@@ -737,7 +746,20 @@
CaptureResult.STATISTICS_FACE_DETECT_MODE ,
// CaptureResult.STATISTICS_FACES ,
};
- m.set(REQUEST_AVAILABLE_RESULT_KEYS, getTagsForKeys(availableKeys));
+ List<CaptureResult.Key<?>> availableKeys =
+ new ArrayList<CaptureResult.Key<?>>(Arrays.asList(defaultAvailableKeys));
+
+ if (p.getMaxNumMeteringAreas() > 0) {
+ availableKeys.add(CaptureResult.CONTROL_AE_REGIONS);
+ }
+ if (p.getMaxNumFocusAreas() > 0) {
+ availableKeys.add(CaptureResult.CONTROL_AF_REGIONS);
+ }
+
+ CaptureResult.Key<?> availableResultKeys[] =
+ new CaptureResult.Key<?>[availableKeys.size()];
+ availableKeys.toArray(availableResultKeys);
+ m.set(REQUEST_AVAILABLE_RESULT_KEYS, getTagsForKeys(availableResultKeys));
}
/*
diff --git a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
index 090a822..ddaa6ee 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyResultMapper.java
@@ -322,7 +322,7 @@
}
// control.aeRegions
- {
+ if (p.getMaxNumMeteringAreas() > 0) {
if (VERBOSE) {
String meteringAreas = p.get("metering-areas");
Log.v(TAG, "mapAe - parameter dump; metering-areas: " + meteringAreas);
@@ -342,7 +342,7 @@
m.set(CaptureResult.CONTROL_AF_MODE, convertLegacyAfMode(p.getFocusMode()));
// control.afRegions
- {
+ if (p.getMaxNumFocusAreas() > 0) {
if (VERBOSE) {
String focusAreas = p.get("focus-areas");
Log.v(TAG, "mapAe - parameter dump; focus-areas: " + focusAreas);
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index e6ff17b..e6da670 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -374,6 +374,9 @@
}
mIntermediateBufferSize = bestPreviewDimen;
+ mParams.setPreviewSize(mIntermediateBufferSize.getWidth(),
+ mIntermediateBufferSize.getHeight());
+
if (DEBUG) {
Log.d(TAG, "Intermediate buffer selected with dimens: " +
bestPreviewDimen.toString());
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 8df9916..80e5b91 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -223,6 +223,9 @@
* Called by the bearer code when it has a new score for this network.
*/
public void sendNetworkScore(int score) {
+ if (score < 0) {
+ throw new IllegalArgumentException("Score must be >= 0");
+ }
queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new Integer(score));
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index ec77a5e..33fda4a 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -43,190 +43,208 @@
private final Context mContext;
/**
- * Key for user restrictions. Specifies if a user is disallowed from adding and removing
- * accounts.
+ * Specifies if a user is disallowed from adding and removing accounts.
* The default value is <code>false</code>.
- * <p/>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
/**
- * Key for user restrictions. Specifies if a user is disallowed from changing Wi-Fi
+ * Specifies if a user is disallowed from changing Wi-Fi
* access points. The default value is <code>false</code>.
- * <p/>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_CONFIG_WIFI = "no_config_wifi";
/**
- * Key for user restrictions. Specifies if a user is disallowed from installing applications.
+ * Specifies if a user is disallowed from installing applications.
* The default value is <code>false</code>.
- * <p/>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_INSTALL_APPS = "no_install_apps";
/**
- * Key for user restrictions. Specifies if a user is disallowed from uninstalling applications.
+ * Specifies if a user is disallowed from uninstalling applications.
* The default value is <code>false</code>.
- * <p/>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
/**
- * Key for user restrictions. Specifies if a user is disallowed from toggling location sharing.
+ * Specifies if a user is disallowed from toggling location sharing.
* The default value is <code>false</code>.
- * <p/>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_SHARE_LOCATION = "no_share_location";
/**
- * Key for user restrictions. Specifies if a user is disallowed from enabling the
+ * Specifies if a user is disallowed from enabling the
* "Unknown Sources" setting, that allows installation of apps from unknown sources.
* The default value is <code>false</code>.
- * <p/>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
/**
- * Key for user restrictions. Specifies if a user is disallowed from configuring bluetooth.
+ * Specifies if a user is disallowed from configuring bluetooth.
* The default value is <code>false</code>.
- * <p/>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
/**
- * Key for user restrictions. Specifies if a user is disallowed from transferring files over
+ * Specifies if a user is disallowed from transferring files over
* USB. This can only be set by device owners. The default value is <code>false</code>.
- * <p/>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
/**
- * Key for user restrictions. Specifies if a user is disallowed from configuring user
+ * Specifies if a user is disallowed from configuring user
* credentials. The default value is <code>false</code>.
- * <p/>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
/**
- * Key for user restrictions. Specifies if a user is disallowed from removing itself and other
+ * Specifies if a user is disallowed from removing itself and other
* users. The default value is <code>false</code>.
- * <p/>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_REMOVE_USER = "no_remove_user";
/**
- * Key for user restrictions. Specifies if a user is disallowed from enabling or
+ * Specifies if a user is disallowed from enabling or
* accessing debugging features. The default value is <code>false</code>.
- * <p/>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features";
/**
- * Key for user restrictions. Specifies if a user is disallowed from configuring VPN.
+ * Specifies if a user is disallowed from configuring VPN.
* The default value is <code>false</code>.
- * <p/>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_CONFIG_VPN = "no_config_vpn";
/**
- * Key for user restrictions. Specifies if a user is disallowed from configuring Tethering
+ * Specifies if a user is disallowed from configuring Tethering
* & portable hotspots. This can only be set by device owners. The default value is
* <code>false</code>.
- * <p/>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_CONFIG_TETHERING = "no_config_tethering";
/**
- * Key for user restrictions. Specifies if a user is disallowed from factory resetting
+ * Specifies if a user is disallowed from factory resetting
* from Settings. This can only be set by device owners. The default value is
* <code>false</code>.
- * <p>
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_FACTORY_RESET = "no_factory_reset";
/**
- * Key for user restrictions. Specifies if a user is disallowed from adding new users and
+ * Specifies if a user is disallowed from adding new users and
* profiles. This can only be set by device owners. The default value is <code>false</code>.
- * <p>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_ADD_USER = "no_add_user";
/**
- * Key for user restrictions. Specifies if a user is disallowed from disabling application
+ * Specifies if a user is disallowed from disabling application
* verification. The default value is <code>false</code>.
- * <p>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String ENSURE_VERIFY_APPS = "ensure_verify_apps";
/**
- * Key for user restrictions. Specifies if a user is disallowed from configuring cell
+ * Specifies if a user is disallowed from configuring cell
* broadcasts. This can only be set by device owners. The default value is <code>false</code>.
- * <p>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
/**
- * Key for user restrictions. Specifies if a user is disallowed from configuring mobile
+ * Specifies if a user is disallowed from configuring mobile
* networks. This can only be set by device owners. The default value is <code>false</code>.
- * <p>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
/**
- * Key for user restrictions. Specifies if a user is disallowed from modifying
+ * Specifies if a user is disallowed from modifying
* applications in Settings or launchers. The following actions will not be allowed when this
* restriction is enabled:
* <li>uninstalling apps</li>
@@ -237,69 +255,75 @@
* <li>clearing app defaults</li>
* <p>
* The default value is <code>false</code>.
- * <p>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_APPS_CONTROL = "no_control_apps";
/**
- * Key for user restrictions. Specifies if a user is disallowed from mounting
+ * Specifies if a user is disallowed from mounting
* physical external media. This can only be set by device owners. The default value is
* <code>false</code>.
- * <p/>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media";
/**
- * Key for user restrictions. Specifies if a user is disallowed from adjusting microphone
+ * Specifies if a user is disallowed from adjusting microphone
* volume. If set, the microphone will be muted. This can only be set by device owners.
* The default value is <code>false</code>.
- * <p/>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone";
/**
- * Key for user restrictions. Specifies if a user is disallowed from adjusting the master
+ * Specifies if a user is disallowed from adjusting the master
* volume. If set, the master volume will be muted. This can only be set by device owners.
* The default value is <code>false</code>.
- * <p/>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
/**
- * Key for user restrictions. Specifies that the user is not allowed to make outgoing
+ * Specifies that the user is not allowed to make outgoing
* phone calls. Emergency calls are still permitted.
* The default value is <code>false</code>.
- * <p/>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls";
/**
- * Key for user restrictions. Specifies that the user is not allowed to send or receive
+ * Specifies that the user is not allowed to send or receive
* SMS messages. This can only be set by device owners. The default value is <code>false</code>.
- * <p/>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_SMS = "no_sms";
/**
- * Key for user restrictions. Specifies that windows besides app windows should not be
+ * Specifies that windows besides app windows should not be
* created. This will block the creation of the following types of windows.
* <li>{@link LayoutParams#TYPE_TOAST}</li>
* <li>{@link LayoutParams#TYPE_PHONE}</li>
@@ -309,25 +333,38 @@
* <li>{@link LayoutParams#TYPE_SYSTEM_OVERLAY}</li>
*
* <p>This can only be set by device owners. The default value is <code>false</code>.
- * <p/>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_CREATE_WINDOWS = "no_create_windows";
/**
- * Key for user restrictions. Specifies if what is copied in the clipboard of this profile can
+ * Specifies if what is copied in the clipboard of this profile can
* be pasted in related profiles. Does not restrict if the clipboard of related profiles can be
* pasted in this profile.
* The default value is <code>false</code>.
- * <p/>
- * Type: Boolean
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
* @see #setUserRestrictions(Bundle)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste";
+ /**
+ * Specifies if the user is not allowed to use NFC to beam out data from apps.
+ * The default value is <code>false</code>.
+ *
+ * <p/>Key for user restrictions.
+ * <p/>Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam";
+
/** @hide */
public static final int PIN_VERIFICATION_FAILED_INCORRECT = -3;
/** @hide */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f4c2dc8..01fda47 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3739,6 +3739,13 @@
"show_note_about_notification_hiding";
/**
+ * Set to 1 by the system after trust agents have been initialized.
+ * @hide
+ */
+ public static final String TRUST_AGENTS_INITIALIZED =
+ "trust_agents_initialized";
+
+ /**
* The Logging ID (a unique 64-bit value) as a hex string.
* Used as a pseudonymous identifier for logging.
* @deprecated This identifier is poorly initialized and has
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index aa724f0..3a91d1a 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -16,6 +16,7 @@
package android.service.notification;
+import android.annotation.SystemApi;
import android.content.Context;
import android.net.Uri;
import android.os.Parcel;
@@ -28,6 +29,7 @@
*
* @hide
*/
+@SystemApi
public class Condition implements Parcelable {
public static final String SCHEME = "condition";
diff --git a/core/java/android/service/notification/ConditionProviderService.java b/core/java/android/service/notification/ConditionProviderService.java
index 326412f..03ee726 100644
--- a/core/java/android/service/notification/ConditionProviderService.java
+++ b/core/java/android/service/notification/ConditionProviderService.java
@@ -17,6 +17,7 @@
package android.service.notification;
import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
import android.app.INotificationManager;
import android.app.Service;
import android.content.Context;
@@ -44,6 +45,7 @@
*
* @hide
*/
+@SystemApi
public abstract class ConditionProviderService extends Service {
private final String TAG = ConditionProviderService.class.getSimpleName()
+ "[" + getClass().getSimpleName() + "]";
diff --git a/core/java/android/service/notification/IStatusBarNotificationHolder.aidl b/core/java/android/service/notification/IStatusBarNotificationHolder.aidl
index fd6b59e..c25cdb2 100644
--- a/core/java/android/service/notification/IStatusBarNotificationHolder.aidl
+++ b/core/java/android/service/notification/IStatusBarNotificationHolder.aidl
@@ -20,5 +20,6 @@
/** @hide */
interface IStatusBarNotificationHolder {
+ /** Fetch the held StatusBarNotification. This method should only be called once per Holder */
StatusBarNotification get();
}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index d744070..b22fd9c 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -756,15 +756,6 @@
return mVisibilityOverride;
}
- /**
- * Returns whether the notification meets the user's interruption
- * filter.
- *
- * @removed
- */
- public boolean meetsInterruptionFilter() {
- return mMatchesInterruptionFilter;
- }
/**
* Returns whether the notification matches the user's interruption
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 872f911..9cbedab 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -17,6 +17,7 @@
package android.service.notification;
import android.content.ComponentName;
+import android.content.res.Resources;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@@ -55,6 +56,11 @@
public static final int[] WEEKNIGHT_DAYS = { Calendar.SUNDAY, Calendar.MONDAY, Calendar.TUESDAY,
Calendar.WEDNESDAY, Calendar.THURSDAY };
+ public static final int[] MINUTE_BUCKETS = new int[] { 15, 30, 45, 60, 120, 180, 240, 480 };
+ private static final int SECONDS_MS = 1000;
+ private static final int MINUTES_MS = 60 * SECONDS_MS;
+ private static final int ZERO_VALUE_MS = 20 * SECONDS_MS;
+
private static final int XML_VERSION = 1;
private static final String ZEN_TAG = "zen";
private static final String ZEN_ATT_VERSION = "version";
@@ -445,6 +451,23 @@
return downtime;
}
+ public static Condition toTimeCondition(int minutesFromNow) {
+ final long now = System.currentTimeMillis();
+ final long millis = minutesFromNow == 0 ? ZERO_VALUE_MS : minutesFromNow * MINUTES_MS;
+ return toTimeCondition(now + millis, minutesFromNow);
+ }
+
+ public static Condition toTimeCondition(long time, int minutes) {
+ final int num = minutes < 60 ? minutes : Math.round(minutes / 60f);
+ final int resId = minutes < 60
+ ? com.android.internal.R.plurals.zen_mode_duration_minutes
+ : com.android.internal.R.plurals.zen_mode_duration_hours;
+ final String caption = Resources.getSystem().getQuantityString(resId, num, num);
+ final Uri id = toCountdownConditionId(time);
+ return new Condition(id, caption, "", "", 0, Condition.STATE_TRUE,
+ Condition.FLAG_RELEVANT_NOW);
+ }
+
// For built-in conditions
private static final String SYSTEM_AUTHORITY = "android";
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 1e28e33..4074529 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -39,7 +39,7 @@
private static native Bitmap nativeScreenshot(IBinder displayToken,
Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
- boolean allLayers, boolean useIdentityTransform);
+ boolean allLayers, boolean useIdentityTransform, int rotation);
private static native void nativeScreenshot(IBinder displayToken, Surface consumer,
Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
boolean allLayers, boolean useIdentityTransform);
@@ -688,17 +688,23 @@
* @param useIdentityTransform Replace whatever transformation (rotation,
* scaling, translation) the surface layers are currently using with the
* identity transformation while taking the screenshot.
+ * @param rotation Apply a custom clockwise rotation to the screenshot, i.e.
+ * Surface.ROTATION_0,90,180,270. Surfaceflinger will always take
+ * screenshots in its native portrait orientation by default, so this is
+ * useful for returning screenshots that are independent of device
+ * orientation.
* @return Returns a Bitmap containing the screen contents, or null
* if an error occurs. Make sure to call Bitmap.recycle() as soon as
* possible, once its content is not needed anymore.
*/
public static Bitmap screenshot(Rect sourceCrop, int width, int height,
- int minLayer, int maxLayer, boolean useIdentityTransform) {
+ int minLayer, int maxLayer, boolean useIdentityTransform,
+ int rotation) {
// TODO: should take the display as a parameter
IBinder displayToken = SurfaceControl.getBuiltInDisplay(
SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
return nativeScreenshot(displayToken, sourceCrop, width, height,
- minLayer, maxLayer, false, useIdentityTransform);
+ minLayer, maxLayer, false, useIdentityTransform, rotation);
}
/**
@@ -717,7 +723,8 @@
// TODO: should take the display as a parameter
IBinder displayToken = SurfaceControl.getBuiltInDisplay(
SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
- return nativeScreenshot(displayToken, new Rect(), width, height, 0, 0, true, false);
+ return nativeScreenshot(displayToken, new Rect(), width, height, 0, 0, true,
+ false, Surface.ROTATION_0);
}
private static void screenshot(IBinder display, Surface consumer, Rect sourceCrop,
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index a94f973..12a49d5 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -875,6 +875,11 @@
data[i + 1] = theme.resolveAttribute(attributeId, outValue, true) ?
outValue.coerceToString().toString() : nullString;
i += 2;
+
+ // attempt to replace reference data with its name
+ if (outValue.type == TypedValue.TYPE_REFERENCE) {
+ data[i - 1] = resources.getResourceName(outValue.resourceId);
+ }
} catch (Resources.NotFoundException e) {
// ignore resources we can't resolve
}
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index e7ada27..1671faa 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -211,18 +211,6 @@
}
/**
- * Constructor with no subtype ID specified, overridesImplicitlyEnabledSubtype not specified.
- * Arguments for this constructor have the same meanings as
- * {@link InputMethodSubtype#InputMethodSubtype(int, int, String, String, String, boolean,
- * boolean, int)} except "id" and "overridesImplicitlyEnabledSubtype".
- * @hide
- */
- public InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue,
- boolean isAuxiliary) {
- this(nameId, iconId, locale, mode, extraValue, isAuxiliary, false);
- }
-
- /**
* Constructor with no subtype ID specified.
* @deprecated use {@link InputMethodSubtypeBuilder} instead.
* Arguments for this constructor have the same meanings as
diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java
index 6ca4a9e..7198e52 100644
--- a/core/java/android/widget/ActionMenuView.java
+++ b/core/java/android/widget/ActionMenuView.java
@@ -611,6 +611,7 @@
mMenu = new MenuBuilder(context);
mMenu.setCallback(new MenuBuilderCallback());
mPresenter = new ActionMenuPresenter(context);
+ mPresenter.setReserveOverflow(true);
mPresenter.setCallback(mActionMenuPresenterCallback != null
? mActionMenuPresenterCallback : new ActionMenuPresenterCallback());
mMenu.addMenuPresenter(mPresenter, mPopupContext);
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 3f168e8..128a06c 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1860,9 +1860,8 @@
}
final int originalLength = mTextView.getText().length();
- long minMax = mTextView.prepareSpacesAroundPaste(offset, offset, content);
- int min = TextUtils.unpackRangeStartFromLong(minMax);
- int max = TextUtils.unpackRangeEndFromLong(minMax);
+ int min = offset;
+ int max = offset;
Selection.setSelection((Spannable) mTextView.getText(), max);
mTextView.replaceText_internal(min, max, content);
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index d263625..efd6fc0 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -2356,7 +2356,7 @@
final int rowsCount = getCount() / columnsCount;
final int selectionMode = getSelectionModeForAccessibility();
final CollectionInfo collectionInfo = CollectionInfo.obtain(
- columnsCount, rowsCount, false, selectionMode);
+ rowsCount, columnsCount, false, selectionMode);
info.setCollectionInfo(collectionInfo);
}
@@ -2385,7 +2385,7 @@
final boolean isHeading = lp != null && lp.viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
final boolean isSelected = isItemChecked(position);
final CollectionItemInfo itemInfo = CollectionItemInfo.obtain(
- column, 1, row, 1, isHeading, isSelected);
+ row, 1, column, 1, isHeading, isSelected);
info.setCollectionItemInfo(itemInfo);
}
}
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 1368cd3..2e9858c 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -3882,9 +3882,10 @@
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(ListView.class.getName());
- final int count = getCount();
+ final int rowsCount = getCount();
final int selectionMode = getSelectionModeForAccessibility();
- final CollectionInfo collectionInfo = CollectionInfo.obtain(1, count, false, selectionMode);
+ final CollectionInfo collectionInfo = CollectionInfo.obtain(
+ rowsCount, 1, false, selectionMode);
info.setCollectionInfo(collectionInfo);
}
@@ -3897,7 +3898,7 @@
final boolean isHeading = lp != null && lp.viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER;
final boolean isSelected = isItemChecked(position);
final CollectionItemInfo itemInfo = CollectionItemInfo.obtain(
- 0, 1, position, 1, isHeading, isSelected);
+ position, 1, 0, 1, isHeading, isSelected);
info.setCollectionItemInfo(itemInfo);
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 3e1b674..76e8ab5 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8423,6 +8423,33 @@
@Override
public boolean performAccessibilityAction(int action, Bundle arguments) {
switch (action) {
+ case AccessibilityNodeInfo.ACTION_CLICK: {
+ boolean handled = false;
+
+ // Simulate View.onTouchEvent for an ACTION_UP event.
+ if (isClickable() || isLongClickable()) {
+ if (isFocusable() && !isFocused()) {
+ requestFocus();
+ }
+
+ performClick();
+ handled = true;
+ }
+
+ // Simulate TextView.onTouchEvent for an ACTION_UP event.
+ if ((mMovement != null || onCheckIsTextEditor()) && isEnabled()
+ && mText instanceof Spannable && mLayout != null
+ && (isTextEditable() || isTextSelectable()) && isFocused()) {
+ // Show the IME, except when selecting in read-only text.
+ final InputMethodManager imm = InputMethodManager.peekInstance();
+ viewClicked(imm);
+ if (!isTextSelectable() && mEditor.mShowSoftInputOnFocus && imm != null) {
+ handled |= imm.showSoftInput(this, 0);
+ }
+ }
+
+ return handled;
+ }
case AccessibilityNodeInfo.ACTION_COPY: {
if (isFocused() && canCopy()) {
if (onTextContextMenuItem(ID_COPY)) {
@@ -8727,57 +8754,6 @@
}
/**
- * Prepare text so that there are not zero or two spaces at beginning and end of region defined
- * by [min, max] when replacing this region by paste.
- * Note that if there were two spaces (or more) at that position before, they are kept. We just
- * make sure we do not add an extra one from the paste content.
- */
- long prepareSpacesAroundPaste(int min, int max, CharSequence paste) {
- if (paste.length() > 0) {
- if (min > 0) {
- final char charBefore = mTransformed.charAt(min - 1);
- final char charAfter = paste.charAt(0);
-
- if (Character.isSpaceChar(charBefore) && Character.isSpaceChar(charAfter)) {
- // Two spaces at beginning of paste: remove one
- final int originalLength = mText.length();
- deleteText_internal(min - 1, min);
- // Due to filters, there is no guarantee that exactly one character was
- // removed: count instead.
- final int delta = mText.length() - originalLength;
- min += delta;
- max += delta;
- } else if (!Character.isSpaceChar(charBefore) && charBefore != '\n' &&
- !Character.isSpaceChar(charAfter) && charAfter != '\n') {
- // No space at beginning of paste: add one
- final int originalLength = mText.length();
- replaceText_internal(min, min, " ");
- // Taking possible filters into account as above.
- final int delta = mText.length() - originalLength;
- min += delta;
- max += delta;
- }
- }
-
- if (max < mText.length()) {
- final char charBefore = paste.charAt(paste.length() - 1);
- final char charAfter = mTransformed.charAt(max);
-
- if (Character.isSpaceChar(charBefore) && Character.isSpaceChar(charAfter)) {
- // Two spaces at end of paste: remove one
- deleteText_internal(max, max + 1);
- } else if (!Character.isSpaceChar(charBefore) && charBefore != '\n' &&
- !Character.isSpaceChar(charAfter) && charAfter != '\n') {
- // No space at end of paste: add one
- replaceText_internal(max, max, " ");
- }
- }
- }
-
- return TextUtils.packRangeInLong(min, max);
- }
-
- /**
* Paste clipboard content between min and max positions.
*/
private void paste(int min, int max) {
@@ -8790,9 +8766,6 @@
CharSequence paste = clip.getItemAt(i).coerceToStyledText(getContext());
if (paste != null) {
if (!didFirst) {
- long minMax = prepareSpacesAroundPaste(min, max, paste);
- min = TextUtils.unpackRangeStartFromLong(minMax);
- max = TextUtils.unpackRangeEndFromLong(minMax);
Selection.setSelection((Spannable) mText, max);
((Editable) mText).replace(min, max, paste);
didFirst = true;
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 3ed4d51..8e786da 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -107,7 +107,7 @@
return (T[]) EmptyArray.OBJECT;
}
- int bucket = ((System.identityHashCode(kind) / 8) & 0x7FFFFFFF) % CACHE_SIZE;
+ int bucket = (kind.hashCode() & 0x7FFFFFFF) % CACHE_SIZE;
Object cache = sCache[bucket];
if (cache == null || cache.getClass().getComponentType() != kind) {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 2106d38..dbaa4b8 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -129,6 +129,7 @@
android/graphics/Xfermode.cpp \
android/graphics/YuvToJpegEncoder.cpp \
android/graphics/pdf/PdfDocument.cpp \
+ android/graphics/pdf/PdfEditor.cpp \
android/graphics/pdf/PdfRenderer.cpp \
android_media_AudioRecord.cpp \
android_media_AudioSystem.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 62d8036..a63258c 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -126,6 +126,7 @@
extern int register_android_graphics_SurfaceTexture(JNIEnv* env);
extern int register_android_graphics_Xfermode(JNIEnv* env);
extern int register_android_graphics_pdf_PdfDocument(JNIEnv* env);
+extern int register_android_graphics_pdf_PdfEditor(JNIEnv* env);
extern int register_android_graphics_pdf_PdfRenderer(JNIEnv* env);
extern int register_android_view_DisplayEventReceiver(JNIEnv* env);
extern int register_android_view_RenderNode(JNIEnv* env);
@@ -1305,6 +1306,7 @@
REG_JNI(register_android_graphics_Xfermode),
REG_JNI(register_android_graphics_YuvImage),
REG_JNI(register_android_graphics_pdf_PdfDocument),
+ REG_JNI(register_android_graphics_pdf_PdfEditor),
REG_JNI(register_android_graphics_pdf_PdfRenderer),
REG_JNI(register_android_database_CursorWindow),
diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp
new file mode 100644
index 0000000..5f60c9e
--- /dev/null
+++ b/core/jni/android/graphics/pdf/PdfEditor.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "fpdfview.h"
+#include "fpdfedit.h"
+#include "fpdfsave.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <vector>
+#include <utils/Log.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace android {
+
+static Mutex sLock;
+
+static int sUnmatchedInitRequestCount = 0;
+
+static void initializeLibraryIfNeeded() {
+ Mutex::Autolock _l(sLock);
+ if (sUnmatchedInitRequestCount == 0) {
+ FPDF_InitLibrary(NULL);
+ }
+ sUnmatchedInitRequestCount++;
+}
+
+static void destroyLibraryIfNeeded() {
+ Mutex::Autolock _l(sLock);
+ sUnmatchedInitRequestCount--;
+ if (sUnmatchedInitRequestCount == 0) {
+ FPDF_DestroyLibrary();
+ }
+}
+
+static int getBlock(void* param, unsigned long position, unsigned char* outBuffer,
+ unsigned long size) {
+ const int fd = reinterpret_cast<intptr_t>(param);
+ const int readCount = pread(fd, outBuffer, size, position);
+ if (readCount < 0) {
+ ALOGE("Cannot read from file descriptor. Error:%d", errno);
+ return 0;
+ }
+ return 1;
+}
+
+static jlong nativeOpen(JNIEnv* env, jclass thiz, jint fd, jlong size) {
+ initializeLibraryIfNeeded();
+
+ FPDF_FILEACCESS loader;
+ loader.m_FileLen = size;
+ loader.m_Param = reinterpret_cast<void*>(intptr_t(fd));
+ loader.m_GetBlock = &getBlock;
+
+ FPDF_DOCUMENT document = FPDF_LoadCustomDocument(&loader, NULL);
+
+ if (!document) {
+ const long error = FPDF_GetLastError();
+ jniThrowException(env, "java/io/IOException",
+ "cannot create document. Error:" + error);
+ destroyLibraryIfNeeded();
+ return -1;
+ }
+
+ return reinterpret_cast<jlong>(document);
+}
+
+static void nativeClose(JNIEnv* env, jclass thiz, jlong documentPtr) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+ FPDF_CloseDocument(document);
+ destroyLibraryIfNeeded();
+}
+
+static jint nativeGetPageCount(JNIEnv* env, jclass thiz, jlong documentPtr) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+ return FPDF_GetPageCount(document);
+}
+
+static jint nativeRemovePage(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+ FPDFPage_Delete(document, pageIndex);
+ return FPDF_GetPageCount(document);
+}
+
+struct PdfToFdWriter : FPDF_FILEWRITE {
+ int dstFd;
+};
+
+static bool writeAllBytes(const int fd, const void* buffer, const size_t byteCount) {
+ char* writeBuffer = static_cast<char*>(const_cast<void*>(buffer));
+ size_t remainingBytes = byteCount;
+ while (remainingBytes > 0) {
+ ssize_t writtenByteCount = write(fd, writeBuffer, remainingBytes);
+ if (writtenByteCount == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ __android_log_print(ANDROID_LOG_ERROR, LOG_TAG,
+ "Error writing to buffer: %d", errno);
+ return false;
+ }
+ remainingBytes -= writtenByteCount;
+ writeBuffer += writtenByteCount;
+ }
+ return true;
+}
+
+static int writeBlock(FPDF_FILEWRITE* owner, const void* buffer, unsigned long size) {
+ const PdfToFdWriter* writer = reinterpret_cast<PdfToFdWriter*>(owner);
+ const bool success = writeAllBytes(writer->dstFd, buffer, size);
+ if (success < 0) {
+ ALOGE("Cannot write to file descriptor. Error:%d", errno);
+ return 0;
+ }
+ return 1;
+}
+
+static void nativeWrite(JNIEnv* env, jclass thiz, jlong documentPtr, jint fd) {
+ FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
+ PdfToFdWriter writer;
+ writer.dstFd = fd;
+ writer.WriteBlock = &writeBlock;
+ const bool success = FPDF_SaveAsCopy(document, &writer, FPDF_NO_INCREMENTAL);
+ if (!success) {
+ jniThrowException(env, "java/io/IOException",
+ "cannot write to fd. Error:" + errno);
+ destroyLibraryIfNeeded();
+ }
+}
+
+static JNINativeMethod gPdfEditor_Methods[] = {
+ {"nativeOpen", "(IJ)J", (void*) nativeOpen},
+ {"nativeClose", "(J)V", (void*) nativeClose},
+ {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
+ {"nativeRemovePage", "(JI)I", (void*) nativeRemovePage},
+ {"nativeWrite", "(JI)V", (void*) nativeWrite}
+};
+
+int register_android_graphics_pdf_PdfEditor(JNIEnv* env) {
+ return android::AndroidRuntime::registerNativeMethods(
+ env, "android/graphics/pdf/PdfEditor", gPdfEditor_Methods,
+ NELEM(gPdfEditor_Methods));
+};
+
+};
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 8f30f5d..06c22ae 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -117,7 +117,8 @@
static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz,
jobject displayTokenObj, jobject sourceCropObj, jint width, jint height,
- jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform) {
+ jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform,
+ int rotation) {
sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
if (displayToken == NULL) {
return NULL;
@@ -131,17 +132,13 @@
SkAutoTDelete<ScreenshotClient> screenshot(new ScreenshotClient());
status_t res;
- if (width > 0 && height > 0) {
- if (allLayers) {
- res = screenshot->update(displayToken, sourceCrop, width, height,
- useIdentityTransform);
- } else {
- res = screenshot->update(displayToken, sourceCrop, width, height,
- minLayer, maxLayer, useIdentityTransform);
- }
- } else {
- res = screenshot->update(displayToken, sourceCrop, useIdentityTransform);
+ if (allLayers) {
+ minLayer = 0;
+ maxLayer = -1UL;
}
+
+ res = screenshot->update(displayToken, sourceCrop, width, height,
+ minLayer, maxLayer, useIdentityTransform, static_cast<uint32_t>(rotation));
if (res != NO_ERROR) {
return NULL;
}
@@ -588,7 +585,7 @@
(void*)nativeRelease },
{"nativeDestroy", "(J)V",
(void*)nativeDestroy },
- {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZ)Landroid/graphics/Bitmap;",
+ {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZI)Landroid/graphics/Bitmap;",
(void*)nativeScreenshotBitmap },
{"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;Landroid/graphics/Rect;IIIIZZ)V",
(void*)nativeScreenshot },
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index c84a466..2e2d0c7 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -175,17 +175,23 @@
continue;
}
}
- // Skip whitespace.
- while (*pos == ' ') {
- pos++;
- }
- // Next field is tag.
- rawTag = strtoll(pos, &endPos, 16);
- //ALOGI("Index #%d: %s", idx, buffer);
- if (pos == endPos) {
- ALOGE("bad tag: %s", pos);
- fclose(fp);
- return -1;
+
+ // Ignore whitespace
+ while (*pos == ' ') pos++;
+
+ // Find end of tag field
+ endPos = pos;
+ while (*endPos != ' ') endPos++;
+
+ // Three digit field is always 0x0, otherwise parse
+ if (endPos - pos == 3) {
+ rawTag = 0;
+ } else {
+ if (sscanf(pos, "%llx", &rawTag) != 1) {
+ ALOGE("bad tag: %s", pos);
+ fclose(fp);
+ return -1;
+ }
}
s.tag = rawTag >> 32;
if (limitTag != -1 && s.tag != limitTag) {
@@ -193,10 +199,10 @@
continue;
}
pos = endPos;
- // Skip whitespace.
- while (*pos == ' ') {
- pos++;
- }
+
+ // Ignore whitespace
+ while (*pos == ' ') pos++;
+
// Parse remaining fields.
if (sscanf(pos, "%u %u %llu %llu %llu %llu",
&s.uid, &s.set, &s.rxBytes, &s.rxPackets,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 72dd930..bf2d09b 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2502,7 +2502,7 @@
<permission android:name="android.permission.PACKAGE_USAGE_STATS"
android:label="@string/permlab_pkgUsageStats"
android:description="@string/permdesc_pkgUsageStats"
- android:protectionLevel="signature|system|development|appop" />
+ android:protectionLevel="signature|development|appop" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
<!-- @SystemApi Allows an application to collect battery statistics -->
@@ -2773,7 +2773,7 @@
android:description="@string/permdesc_bindNotificationListenerService"
android:protectionLevel="signature" />
- <!-- Must be required by an {@link
+ <!-- @SystemApi Must be required by a {@link
android.service.notification.ConditionProviderService},
to ensure that only the system can bind to it.
@hide -->
diff --git a/core/res/res/layout/alert_dialog_material.xml b/core/res/res/layout/alert_dialog_material.xml
index 5f9066a..be89e41 100644
--- a/core/res/res/layout/alert_dialog_material.xml
+++ b/core/res/res/layout/alert_dialog_material.xml
@@ -33,8 +33,7 @@
android:gravity="center_vertical|start"
android:paddingStart="@dimen/alert_dialog_padding_material"
android:paddingEnd="@dimen/alert_dialog_padding_material"
- android:paddingTop="@dimen/alert_dialog_padding_material"
- android:paddingBottom="8dip">
+ android:paddingTop="@dimen/alert_dialog_padding_top_material">
<ImageView android:id="@+id/icon"
android:layout_width="32dip"
android:layout_height="32dip"
@@ -57,7 +56,8 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
- android:minHeight="64dp">
+ android:minHeight="64dp"
+ android:paddingTop="@dimen/alert_dialog_padding_top_material">
<ScrollView android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -67,9 +67,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/alert_dialog_padding_material"
- android:paddingEnd="@dimen/alert_dialog_padding_material"
- android:paddingTop="@dimen/alert_dialog_padding_material"
- android:paddingBottom="@dimen/alert_dialog_padding_material" />
+ android:paddingEnd="@dimen/alert_dialog_padding_material" />
</ScrollView>
</LinearLayout>
@@ -89,15 +87,14 @@
android:layout_height="wrap_content"
android:layoutDirection="locale"
android:orientation="horizontal"
- android:paddingStart="6dp"
- android:paddingEnd="6dp"
- android:paddingBottom="6dp">
+ android:paddingStart="12dp"
+ android:paddingEnd="12dp"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp">
<Button android:id="@+id/button3"
style="?attr/buttonBarNeutralButtonStyle"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:maxLines="2"
- android:minHeight="@dimen/alert_dialog_button_bar_height" />
+ android:layout_height="wrap_content" />
<Space
android:layout_width="0dp"
android:layout_height="0dp"
@@ -106,14 +103,10 @@
<Button android:id="@+id/button2"
style="?attr/buttonBarNegativeButtonStyle"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:maxLines="2"
- android:minHeight="@dimen/alert_dialog_button_bar_height" />
+ android:layout_height="wrap_content" />
<Button android:id="@+id/button1"
style="?attr/buttonBarPositiveButtonStyle"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:maxLines="2"
- android:minHeight="@dimen/alert_dialog_button_bar_height" />
+ android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
diff --git a/core/res/res/layout/alert_dialog_progress_material.xml b/core/res/res/layout/alert_dialog_progress_material.xml
index b9d0814..d005a44 100644
--- a/core/res/res/layout/alert_dialog_progress_material.xml
+++ b/core/res/res/layout/alert_dialog_progress_material.xml
@@ -17,32 +17,27 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
- android:layout_height="match_parent">
- <ProgressBar android:id="@+id/progress"
- style="?android:attr/progressBarStyleHorizontal"
+ android:layout_height="match_parent"
+ android:paddingStart="@dimen/alert_dialog_padding_material"
+ android:paddingTop="@dimen/alert_dialog_padding_top_material"
+ android:paddingEnd="@dimen/alert_dialog_padding_material"
+ android:paddingBottom="@dimen/alert_dialog_padding_top_material">
+ <ProgressBar
+ android:id="@+id/progress"
+ style="?attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="16dip"
- android:layout_marginBottom="1dip"
- android:layout_marginStart="16dip"
- android:layout_marginEnd="16dip"
android:layout_centerHorizontal="true" />
<TextView
android:id="@+id/progress_percent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingBottom="16dip"
- android:layout_marginStart="16dip"
- android:layout_marginEnd="16dip"
android:layout_alignParentStart="true"
android:layout_below="@id/progress" />
<TextView
android:id="@+id/progress_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingBottom="16dip"
- android:layout_marginStart="16dip"
- android:layout_marginEnd="16dip"
android:layout_alignParentEnd="true"
android:layout_below="@id/progress" />
</RelativeLayout>
diff --git a/core/res/res/layout/dialog_custom_title_material.xml b/core/res/res/layout/dialog_custom_title_material.xml
index 550b72e..248a05e 100644
--- a/core/res/res/layout/dialog_custom_title_material.xml
+++ b/core/res/res/layout/dialog_custom_title_material.xml
@@ -23,17 +23,17 @@
android:fitsSystemWindows="true">
<FrameLayout android:id="@android:id/title_container"
android:layout_width="match_parent"
- android:layout_height="?android:attr/windowTitleSize"
+ android:layout_height="?attr/windowTitleSize"
android:layout_weight="0"
android:gravity="center_vertical|start"
- style="?android:attr/windowTitleBackgroundStyle" />
+ style="?attr/windowTitleBackgroundStyle" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
- android:foreground="?android:attr/windowContentOverlay">
- <FrameLayout android:id="@android:id/content"
+ android:foreground="?attr/windowContentOverlay">
+ <FrameLayout android:id="@id/content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
diff --git a/core/res/res/layout/dialog_title_icons_material.xml b/core/res/res/layout/dialog_title_icons_material.xml
index 28e20d9..21396da 100644
--- a/core/res/res/layout/dialog_title_icons_material.xml
+++ b/core/res/res/layout/dialog_title_icons_material.xml
@@ -28,16 +28,16 @@
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
- android:paddingStart="16dip"
- android:paddingEnd="16dip"
- android:paddingTop="16dip">
+ android:paddingStart="@dimen/alert_dialog_padding_material"
+ android:paddingEnd="@dimen/alert_dialog_padding_material"
+ android:paddingTop="@dimen/alert_dialog_padding_material">
<ImageView android:id="@+id/left_icon"
android:layout_width="32dip"
android:layout_height="32dip"
android:scaleType="fitCenter"
android:layout_marginEnd="8dip" />
- <TextView android:id="@android:id/title"
- style="?android:attr/windowTitleStyle"
+ <TextView android:id="@id/title"
+ style="?attr/windowTitleStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0" />
@@ -52,8 +52,8 @@
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
- android:foreground="?android:attr/windowContentOverlay">
- <FrameLayout android:id="@android:id/content"
+ android:foreground="?attr/windowContentOverlay">
+ <FrameLayout android:id="@id/content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
diff --git a/core/res/res/layout/dialog_title_material.xml b/core/res/res/layout/dialog_title_material.xml
index 918c8f1..fcf6164 100644
--- a/core/res/res/layout/dialog_title_material.xml
+++ b/core/res/res/layout/dialog_title_material.xml
@@ -29,15 +29,15 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="viewStart"
- android:paddingStart="16dip"
- android:paddingEnd="16dip"
- android:paddingTop="16dip" />
+ android:paddingStart="@dimen/alert_dialog_padding_material"
+ android:paddingEnd="@dimen/alert_dialog_padding_material"
+ android:paddingTop="@dimen/alert_dialog_padding_top_material" />
<FrameLayout
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
- android:foreground="?android:attr/windowContentOverlay">
- <FrameLayout android:id="@android:id/content"
+ android:foreground="?attr/windowContentOverlay">
+ <FrameLayout android:id="@id/content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
diff --git a/core/res/res/layout/notification_template_part_line2.xml b/core/res/res/layout/notification_template_part_line2.xml
index 7e99c5e..aeef3ab 100644
--- a/core/res/res/layout/notification_template_part_line2.xml
+++ b/core/res/res/layout/notification_template_part_line2.xml
@@ -45,13 +45,13 @@
android:visibility="gone"
/>
</LinearLayout>
- <ProgressBar
+ <ViewStub
android:id="@android:id/progress"
+ android:layout="@layout/notification_template_progressbar"
android:layout_width="match_parent"
android:layout_height="15dp"
android:layout_marginEnd="8dp"
android:visibility="gone"
android:layout_weight="0"
- style="@style/Widget.Material.Light.ProgressBar.Horizontal"
/>
</merge>
diff --git a/core/res/res/layout/notification_template_progressbar.xml b/core/res/res/layout/notification_template_progressbar.xml
new file mode 100644
index 0000000..61480b8
--- /dev/null
+++ b/core/res/res/layout/notification_template_progressbar.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2014 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
+ -->
+
+<ProgressBar xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/progress"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ style="@style/Widget.Material.Light.ProgressBar.Horizontal"
+ />
diff --git a/core/res/res/layout/progress_dialog_material.xml b/core/res/res/layout/progress_dialog_material.xml
index 84d06b5..54af106 100644
--- a/core/res/res/layout/progress_dialog_material.xml
+++ b/core/res/res/layout/progress_dialog_material.xml
@@ -19,21 +19,27 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
- <LinearLayout android:id="@+id/body"
+ <LinearLayout
+ android:id="@+id/body"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="false"
- android:padding="16dip">
+ android:paddingStart="@dimen/alert_dialog_padding_material"
+ android:paddingTop="@dimen/alert_dialog_padding_top_material"
+ android:paddingEnd="@dimen/alert_dialog_padding_material"
+ android:paddingBottom="@dimen/alert_dialog_padding_top_material">
- <ProgressBar android:id="@android:id/progress"
+ <ProgressBar
+ android:id="@id/progress"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:max="10000"
- android:layout_marginEnd="16dip" />
+ android:layout_marginEnd="@dimen/alert_dialog_padding_material" />
- <TextView android:id="@+id/message"
+ <TextView
+ android:id="@+id/message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" />
diff --git a/core/res/res/layout/simple_spinner_dropdown_item.xml b/core/res/res/layout/simple_spinner_dropdown_item.xml
index e2bd474..f276cfa 100644
--- a/core/res/res/layout/simple_spinner_dropdown_item.xml
+++ b/core/res/res/layout/simple_spinner_dropdown_item.xml
@@ -4,24 +4,23 @@
**
** Copyright 2008, 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
+** 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
+** 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
+** 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.
*/
-->
-<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
+<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
style="?android:attr/spinnerDropDownItemStyle"
android:singleLine="true"
android:layout_width="match_parent"
android:layout_height="?android:attr/dropdownListPreferredItemHeight"
- android:ellipsize="marquee"
- android:textAlignment="inherit"/>
+ android:ellipsize="marquee"/>
diff --git a/core/res/res/values-mcc310-mnc004/config.xml b/core/res/res/values-mcc310-mnc004/config.xml
index 2778b6e..423e250 100644
--- a/core/res/res/values-mcc310-mnc004/config.xml
+++ b/core/res/res/values-mcc310-mnc004/config.xml
@@ -34,11 +34,4 @@
</string-array>
<bool name="config_auto_attach_data_on_creation">false</bool>
-
- <!-- Values for GPS configuration (Verizon) -->
- <string-array translatable="false" name="config_gpsParameters">
- <item>CAPABILITIES=0x31</item>
- <item>LPP_PROFILE=3</item>
- <item>GPS_LOCK=3</item>
- </string-array>
</resources>
diff --git a/core/res/res/values-mcc310-mnc120/config.xml b/core/res/res/values-mcc310-mnc120/config.xml
index 3b95db5..62001d9 100644
--- a/core/res/res/values-mcc310-mnc120/config.xml
+++ b/core/res/res/values-mcc310-mnc120/config.xml
@@ -25,10 +25,4 @@
-->
<integer name="config_mobile_mtu">1422</integer>
- <!-- Values for GPS configuration (Sprint) -->
- <string-array translatable="false" name="config_gpsParameters">
- <item>CAPABILITIES=0x31</item>
- <item>GPS_LOCK=3</item>
- <item>LPP_PROFILE=2</item>
- </string-array>
</resources>
diff --git a/core/res/res/values-mcc310-mnc150/config.xml b/core/res/res/values-mcc310-mnc150/config.xml
index 00d2db8..f1936f4 100644
--- a/core/res/res/values-mcc310-mnc150/config.xml
+++ b/core/res/res/values-mcc310-mnc150/config.xml
@@ -33,10 +33,4 @@
<item>315</item>
<item>316</item>
</string-array>
- <!-- Values for GPS configuration (AT&T) -->
- <string-array translatable="false" name="config_gpsParameters">
- <item>CAPABILITIES=0x33</item>
- <item>LPP_PROFILE=3</item>
- <item>GPS_LOCK=1</item>
- </string-array>
</resources>
diff --git a/core/res/res/values-mcc310-mnc260/config.xml b/core/res/res/values-mcc310-mnc260/config.xml
index f8fff3b..28cd695 100644
--- a/core/res/res/values-mcc310-mnc260/config.xml
+++ b/core/res/res/values-mcc310-mnc260/config.xml
@@ -29,11 +29,4 @@
carrier provisioning. If false: hard disabled. If true: then depends on carrier
provisioning, availability etc -->
<bool name="config_carrier_volte_vt_available">true</bool>
-
- <!-- Values for GPS configuration (T-Mobile) -->
- <string-array translatable="false" name="config_gpsParameters">
- <item>CAPABILITEIS=0x33</item>
- <item>GPS_LOCK=1</item>
- <item>LPP_PROFILE=2</item>
- </string-array>
</resources>
diff --git a/core/res/res/values-mcc310-mnc410/config.xml b/core/res/res/values-mcc310-mnc410/config.xml
index edf6d9f..b863aae 100644
--- a/core/res/res/values-mcc310-mnc410/config.xml
+++ b/core/res/res/values-mcc310-mnc410/config.xml
@@ -40,12 +40,6 @@
<item>315</item>
<item>316</item>
</string-array>
- <!-- Values for GPS configuration (AT&T) -->
- <string-array translatable="false" name="config_gpsParameters">
- <item>CAPABILITIES=0x33</item>
- <item>GPS_LOCK=1</item>
- <item>LPP_PROFILE=3</item>
- </string-array>
<!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
<string-array name="config_twoDigitNumberPattern">
<item>"0"</item>
diff --git a/core/res/res/values-mcc311-mnc190/config.xml b/core/res/res/values-mcc311-mnc190/config.xml
index b4e436d..a6c4d1b 100644
--- a/core/res/res/values-mcc311-mnc190/config.xml
+++ b/core/res/res/values-mcc311-mnc190/config.xml
@@ -37,11 +37,4 @@
note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
<string translatable="false" name="config_tether_apndata">Tether,broadband.cellular1.net,,,,,,,,,311,190,,DUN</string>
- <!-- Values for GPS configuration (Sprint) -->
- <string-array translatable="false" name="config_gpsParameters">
- <item>CAPABILITIES=0x31</item>
- <item>GPS_LOCK=3</item>
- <item>LPP_PROFILE=2</item>
- </string-array>
-
</resources>
diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml
index 57ecd31..cf19235 100644
--- a/core/res/res/values-mcc311-mnc480/config.xml
+++ b/core/res/res/values-mcc311-mnc480/config.xml
@@ -44,11 +44,4 @@
<bool name="config_carrier_volte_vt_available">false</bool>
<bool name="config_auto_attach_data_on_creation">false</bool>
-
- <!-- Values for GPS configuration (Verizon) -->
- <string-array translatable="false" name="config_gpsParameters">
- <item>CAPABILITIES=0x31</item>
- <item>GPS_LOCK=3</item>
- <item>LPP_PROFILE=3</item>
- </string-array>
</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index cf4064f..a00ed5d 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4483,12 +4483,12 @@
<!-- The row boundary delimiting the top of the group of cells
occupied by this view. -->
<attr name="layout_row" format="integer" />
- <!-- The row span: the difference between the bottom and top
+ <!-- The row span: the difference between the top and bottom
boundaries delimiting the group of cells occupied by this view.
The default is one.
See {@link android.widget.GridLayout.Spec}. -->
<attr name="layout_rowSpan" format="integer" min="1" />
- <!-- The relative proportion of horizontal space that should be allocated to this view
+ <!-- The relative proportion of vertical space that should be allocated to this view
during excess space distribution. -->
<attr name="layout_rowWeight" format="float" />
<!-- The column boundary delimiting the left of the group of cells
@@ -4499,7 +4499,7 @@
The default is one.
See {@link android.widget.GridLayout.Spec}. -->
<attr name="layout_columnSpan" format="integer" min="1" />
- <!-- The relative proportion of vertical space that should be allocated to this view
+ <!-- The relative proportion of horizontal space that should be allocated to this view
during excess space distribution. -->
<attr name="layout_columnWeight" format="float" />
<!-- Gravity specifies how a component should be placed in its group of cells.
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1b12ff2..d67690a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -351,6 +351,15 @@
point on the move. A value of 0 means no periodic scans will be used in the framework. -->
<integer translatable="false" name="config_wifi_framework_scan_interval">300000</integer>
+ <!-- Integer indicating associated scan interval in milliseconds -->
+ <integer translatable="false" name="config_wifi_framework_associated_scan_interval">10000</integer>
+
+ <!-- Boolean indicating associated scan are allowed -->
+ <bool translatable="false" name="config_wifi_framework_enable_associated_autojoin_scan">true</bool>
+
+ <!-- Boolean indicating associated network selection is allowed -->
+ <bool translatable="false" name="config_wifi_framework_enable_associated_network_selection">true</bool>
+
<!-- Wifi driver stop delay, in milliseconds.
Default value is 2 minutes. -->
<integer translatable="false" name="config_wifi_driver_stop_delay">120000</integer>
@@ -1719,16 +1728,22 @@
<string-array translatable="false" name="config_gpsParameters">
<item>SUPL_HOST=supl.google.com</item>
<item>SUPL_PORT=7275</item>
- <item>XTRA_SERVER_1=http://xtrapath1.izatcloud.net/xtra2.bin</item>
- <item>XTRA_SERVER_2=http://xtrapath2.izatcloud.net/xtra2.bin</item>
- <item>XTRA_SERVER_3=http://xtrapath3.izatcloud.net/xtra2.bin</item>
<item>NTP_SERVER=north-america.pool.ntp.org</item>
<item>SUPL_VER=0x20000</item>
- <item>CAPABILITIES=0x33</item>
- <item>LPP_PROFILE=0</item>
- <item>NMEA_PROVIDER=0</item>
- <item>A_GLONASS_POS_PROTOCOL_SELECT=0</item>
- <item>ERR_ESTIMATE=0</item>
- <item>INTERMEDIATE_POS=0</item>
</string-array>
+
+ <!-- If there is no preload VM number in the sim card, carriers such as
+ Verizon require to load a default vm number from the configurantion.
+ Define config_default_vm_number for this purpose. And there are two
+ optional formats for this configuration as below:
+ (1)<item>voicemail number</item>
+ (2)<item>voicemail number;gid</item>
+ The logic to pick up the correct voicemail number:
+ (1) If the config_default_vm_number array has no gid special item, the last one will be
+ picked
+ (2) If the config_default_vm_number array has gid special item and it matches the current
+ sim's gid, it will be picked.
+ (3) If the config_default_vm_number array has gid special item but it doesn't match the
+ current sim's gid, the last one without gid will be picked -->
+ <string-array translatable="false" name="config_default_vm_number" />
</resources>
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index 5f7f0ed..275a5ec 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -77,5 +77,6 @@
<!-- Default rounded corner for controls -->
<dimen name="control_corner_material">2dp</dimen>
- <dimen name="alert_dialog_padding_material">18dp</dimen>
+ <dimen name="alert_dialog_padding_material">24dp</dimen>
+ <dimen name="alert_dialog_padding_top_material">18dp</dimen>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 5c932fd..50da1fa 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4877,4 +4877,19 @@
<!-- [CHAR_LIMIT=NONE] Zen mode: Condition summary for built-in downtime condition, if active -->
<string name="downtime_condition_summary">Until your downtime ends at <xliff:g id="formattedTime" example="10.00 PM">%1$s</xliff:g></string>
+
+ <!-- Zen mode condition: time duration in minutes. [CHAR LIMIT=NONE] -->
+ <plurals name="zen_mode_duration_minutes">
+ <item quantity="one">For one minute</item>
+ <item quantity="other">For %d minutes</item>
+ </plurals>
+
+ <!-- Zen mode condition: time duration in hours. [CHAR LIMIT=NONE] -->
+ <plurals name="zen_mode_duration_hours">
+ <item quantity="one">For one hour</item>
+ <item quantity="other">For %d hours</item>
+ </plurals>
+
+ <!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] -->
+ <string name="zen_mode_forever">Indefinitely</string>
</resources>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index a7335af..26c7d10 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -474,6 +474,13 @@
<item name="stateListAnimator">@anim/disabled_anim_material</item>
</style>
+ <!-- Alert dialog button bar button -->
+ <style name="Widget.Material.Button.ButtonBar.AlertDialog" parent="Widget.Material.Button.Borderless.Colored">
+ <item name="minWidth">64dp</item>
+ <item name="maxLines">2</item>
+ <item name="minHeight">@dimen/alert_dialog_button_bar_height</item>
+ </style>
+
<!-- Small borderless ink button -->
<style name="Widget.Material.Button.Borderless.Small">
<item name="minHeight">48dip</item>
@@ -496,7 +503,6 @@
<style name="Widget.Material.ButtonBar.AlertDialog">
<item name="background">@null</item>
- <item name="minHeight">@dimen/alert_dialog_button_bar_height</item>
</style>
<style name="Widget.Material.SearchView">
@@ -936,6 +942,7 @@
<style name="Widget.Material.Light.Button.Small" parent="Widget.Material.Button.Small"/>
<style name="Widget.Material.Light.Button.Borderless" parent="Widget.Material.Button.Borderless"/>
<style name="Widget.Material.Light.Button.Borderless.Colored" parent="Widget.Material.Button.Borderless.Colored"/>
+ <style name="Widget.Material.Light.Button.ButtonBar.AlertDialog" parent="Widget.Material.Button.ButtonBar.AlertDialog" />
<style name="Widget.Material.Light.Button.Borderless.Small" parent="Widget.Material.Button.Borderless.Small"/>
<style name="Widget.Material.Light.Button.Inset" parent="Widget.Material.Button.Inset"/>
<style name="Widget.Material.Light.Button.Toggle" parent="Widget.Material.Button.Toggle" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f5197ec..221269d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -294,6 +294,8 @@
<java-symbol type="bool" name="config_hasRecents" />
<java-symbol type="bool" name="config_windowShowCircularMask" />
<java-symbol type="bool" name="config_windowEnableCircularEmulatorDisplayOverlay" />
+ <java-symbol type="bool" name="config_wifi_framework_enable_associated_autojoin_scan" />
+ <java-symbol type="bool" name="config_wifi_framework_enable_associated_network_selection" />
<java-symbol type="integer" name="config_bluetooth_max_advertisers" />
<java-symbol type="integer" name="config_bluetooth_max_scan_filters" />
@@ -313,6 +315,7 @@
<java-symbol type="integer" name="config_shortPressOnPowerBehavior" />
<java-symbol type="integer" name="config_toastDefaultGravity" />
<java-symbol type="integer" name="config_wifi_framework_scan_interval" />
+ <java-symbol type="integer" name="config_wifi_framework_associated_scan_interval" />
<java-symbol type="integer" name="config_wifi_supplicant_scan_interval" />
<java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" />
<java-symbol type="integer" name="db_connection_pool_size" />
@@ -1917,6 +1920,9 @@
<java-symbol type="string" name="timepicker_transition_end_radius_multiplier" />
<java-symbol type="string" name="battery_saver_description" />
<java-symbol type="string" name="downtime_condition_summary" />
+ <java-symbol type="string" name="zen_mode_forever" />
+ <java-symbol type="plurals" name="zen_mode_duration_minutes" />
+ <java-symbol type="plurals" name="zen_mode_duration_hours" />
<java-symbol type="string" name="item_is_selected" />
<java-symbol type="string" name="day_of_week_label_typeface" />
@@ -2007,4 +2013,5 @@
<java-symbol type="id" name="date_picker_month_day_year_layout" />
<java-symbol type="attr" name="closeItemLayout" />
<java-symbol type="layout" name="resolver_different_item_header" />
+ <java-symbol type="array" name="config_default_vm_number" />
</resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index ab5cd5a..4aca02e 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -333,7 +333,7 @@
<item name="dividerVertical">?attr/listDivider</item>
<item name="dividerHorizontal">?attr/listDivider</item>
<item name="buttonBarStyle">@style/Widget.Material.ButtonBar</item>
- <item name="buttonBarButtonStyle">@style/Widget.Material.Button.Borderless.Colored</item>
+ <item name="buttonBarButtonStyle">@style/Widget.Material.Button.ButtonBar.AlertDialog</item>
<item name="segmentedButtonStyle">@style/Widget.Material.SegmentedButton</item>
<!-- SearchView attributes -->
@@ -679,7 +679,7 @@
<item name="dividerVertical">?attr/listDivider</item>
<item name="dividerHorizontal">?attr/listDivider</item>
<item name="buttonBarStyle">@style/Widget.Material.Light.ButtonBar</item>
- <item name="buttonBarButtonStyle">@style/Widget.Material.Light.Button.Borderless.Colored</item>
+ <item name="buttonBarButtonStyle">@style/Widget.Material.Light.Button.ButtonBar.AlertDialog</item>
<item name="segmentedButtonStyle">@style/Widget.Material.Light.SegmentedButton</item>
<!-- SearchView attributes -->
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
index 77e1c530..80d5668 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java
@@ -322,8 +322,13 @@
* If the device is already associated with a WiFi, disconnect and forget it,
* We don't verify whether the connection is successful or not, leave this to the test
*/
- protected boolean connectToWifi(String knownSSID) {
- WifiConfiguration config = WifiConfigurationHelper.createOpenConfig(knownSSID);
+ protected boolean connectToWifi(String ssid, String password) {
+ WifiConfiguration config;
+ if (password == null) {
+ config = WifiConfigurationHelper.createOpenConfig(ssid);
+ } else {
+ config = WifiConfigurationHelper.createPskConfig(ssid, password);
+ }
return connectToWifiWithConfiguration(config);
}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
index b94306a..b6eb674 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
@@ -35,8 +35,9 @@
*/
public class ConnectivityManagerTestRunner extends InstrumentationTestRunner {
- public boolean mWifiOnlyFlag = false;
- public String mTestSsid = null;
+ public boolean mWifiOnly = false;
+ public String mSsid = null;
+ public String mPassword = null;
@Override
public TestSuite getAllTests() {
@@ -54,13 +55,29 @@
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- String testSSID = (String) icicle.get("ssid");
- if (testSSID != null) {
- mTestSsid = testSSID;
+ String ssid = icicle.getString("ssid");
+ if (ssid != null) {
+ mSsid = ssid;
+ }
+ String password = (String) icicle.get("password");
+ if (password != null) {
+ mPassword = password;
}
String wifiOnlyFlag = (String) icicle.get("wifi-only");
if (wifiOnlyFlag != null) {
- mWifiOnlyFlag = true;
+ mWifiOnly = true;
}
}
+
+ public String getWifiSsid() {
+ return mSsid;
+ }
+
+ public String getWifiPassword() {
+ return mPassword;
+ }
+
+ public boolean isWifiOnly() {
+ return mWifiOnly;
+ }
}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index b280106..d5051df 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -33,7 +33,8 @@
super(ConnectivityManagerMobileTest.class.getSimpleName());
}
- private String mTestAccessPoint;
+ private String mSsid;
+ private String mPassword;
private boolean mWifiOnlyFlag;
@Override
@@ -41,8 +42,9 @@
super.setUp();
ConnectivityManagerTestRunner mRunner =
(ConnectivityManagerTestRunner)getInstrumentation();
- mTestAccessPoint = mRunner.mTestSsid;
- mWifiOnlyFlag = mRunner.mWifiOnlyFlag;
+ mSsid = mRunner.getWifiSsid();
+ mPassword = mRunner.getWifiPassword();
+ mWifiOnlyFlag = mRunner.isWifiOnly();
// Each test case will start with cellular connection
if (Settings.Global.getInt(getInstrumentation().getContext().getContentResolver(),
@@ -120,11 +122,10 @@
// Test case 2: test connection to a given AP
@LargeTest
public void testConnectToWifi() {
- assertNotNull("SSID is null", mTestAccessPoint);
+ assertNotNull("SSID is null", mSsid);
// assert that we are able to connect to the ap
- assertTrue("failed to connect to " + mTestAccessPoint,
- connectToWifi(mTestAccessPoint));
+ assertTrue("failed to connect to " + mSsid, connectToWifi(mSsid, mPassword));
// assert that WifiManager reports correct state
assertTrue("wifi not enabled", waitForWifiState(
WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
@@ -144,14 +145,14 @@
// Test case 3: connect & reconnect to Wifi with known AP
@LargeTest
public void testConnectToWifWithKnownAP() {
- assertNotNull("SSID is null", mTestAccessPoint);
+ assertNotNull("SSID is null", mSsid);
// enable WiFi
assertTrue("failed to enable wifi", enableWifi());
// wait for wifi enable
assertTrue("wifi not enabled", waitForWifiState(
WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
// Connect to AP
- assertTrue("failed to connect to " + mTestAccessPoint, connectToWifi(mTestAccessPoint));
+ assertTrue("failed to connect to " + mSsid, connectToWifi(mSsid, mPassword));
// verify wifi connected as reported by ConnectivityManager
assertTrue("wifi not connected", waitForNetworkState(
ConnectivityManager.TYPE_WIFI, State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
@@ -191,7 +192,7 @@
// Test case 4: test disconnect and clear wifi settings
@LargeTest
public void testDisconnectWifi() {
- assertNotNull("SSID is null", mTestAccessPoint);
+ assertNotNull("SSID is null", mSsid);
// enable WiFi
assertTrue("failed to enable wifi", enableWifi());
@@ -199,8 +200,7 @@
assertTrue("wifi not enabled", waitForWifiState(
WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
// connect to Wifi
- assertTrue("failed to connect to " + mTestAccessPoint,
- connectToWifi(mTestAccessPoint));
+ assertTrue("failed to connect to " + mSsid, connectToWifi(mSsid, mPassword));
assertTrue("wifi not connected", waitForNetworkState(
ConnectivityManager.TYPE_WIFI, State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
@@ -257,7 +257,7 @@
// Test case 6: test connectivity with airplane mode on but wifi enabled
@LargeTest
public void testDataConnectionOverAMWithWifi() {
- assertNotNull("SSID is null", mTestAccessPoint);
+ assertNotNull("SSID is null", mSsid);
// enable airplane mode
mCm.setAirplaneMode(true);
// assert there is active network connection after airplane mode disabled
@@ -265,8 +265,7 @@
waitUntilNoActiveNetworkConnection(LONG_TIMEOUT));
// connect to Wifi
- assertTrue("failed to connect to " + mTestAccessPoint,
- connectToWifi(mTestAccessPoint));
+ assertTrue("failed to connect to " + mSsid, connectToWifi(mSsid, mPassword));
assertTrue("wifi not connected", waitForNetworkState(
ConnectivityManager.TYPE_WIFI, State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
// verify that connection actually works
@@ -280,15 +279,14 @@
@LargeTest
public void testDataConnectionWithWifiToAMToWifi () {
// connect to mTestAccessPoint
- assertNotNull("SSID is null", mTestAccessPoint);
+ assertNotNull("SSID is null", mSsid);
// enable WiFi
assertTrue("failed to enable wifi", enableWifi());
// wait for wifi enable
assertTrue("wifi not enabled", waitForWifiState(
WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
// connect to Wifi
- assertTrue("failed to connect to " + mTestAccessPoint,
- connectToWifi(mTestAccessPoint));
+ assertTrue("failed to connect to " + mSsid, connectToWifi(mSsid, mPassword));
assertTrue("wifi not connected", waitForNetworkState(
ConnectivityManager.TYPE_WIFI, State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
@@ -313,15 +311,14 @@
// Test case 8: test wifi state change while connecting/disconnecting to/from an AP
@LargeTest
public void testWifiStateChange () {
- assertNotNull("SSID is null", mTestAccessPoint);
+ assertNotNull("SSID is null", mSsid);
// enable WiFi
assertTrue("failed to enable wifi", enableWifi());
// wait for wifi enable
assertTrue("wifi not enabled", waitForWifiState(
WifiManager.WIFI_STATE_ENABLED, LONG_TIMEOUT));
// connect to Wifi
- assertTrue("failed to connect to " + mTestAccessPoint,
- connectToWifi(mTestAccessPoint));
+ assertTrue("failed to connect to " + mSsid, connectToWifi(mSsid, mPassword));
assertTrue("wifi not connected", waitForNetworkState(
ConnectivityManager.TYPE_WIFI, State.CONNECTED, WIFI_CONNECTION_TIMEOUT));
assertNotNull("not associated with any AP", mWifiManager.getConnectionInfo().getBSSID());
diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java
index bcf2e45..db547e2 100644
--- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java
+++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerTestApp.java
@@ -60,10 +60,10 @@
super.setUp();
DownloadManagerTestRunner mRunner = (DownloadManagerTestRunner)getInstrumentation();
externalDownloadUriValue = normalizeUri(mRunner.externalDownloadUriValue);
- assertNotNull(externalDownloadUriValue);
+ assertNotNull("download url is null", externalDownloadUriValue);
externalLargeDownloadUriValue = normalizeUri(mRunner.externalDownloadUriValue);
- assertNotNull(externalLargeDownloadUriValue);
+ assertNotNull("large download url is null", externalLargeDownloadUriValue);
}
/**
@@ -140,7 +140,7 @@
dlRequest = mDownloadManager.enqueue(request);
waitForDownloadToStart(dlRequest);
- assertTrue(dlRequest != -1);
+ assertTrue("request id is -1 from download manager", dlRequest != -1);
// Store ID of download for later retrieval
outputFile = new DataOutputStream(fileOutput);
@@ -183,7 +183,7 @@
mContext.deleteFile(DOWNLOAD_STARTED_FLAG);
}
- assertTrue(dlRequest != -1);
+ assertTrue("request id is -1 from download manager", dlRequest != -1);
Cursor cursor = getCursor(dlRequest);
ParcelFileDescriptor pfd = null;
try {
@@ -193,7 +193,7 @@
int status = cursor.getInt(columnIndex);
int currentWaitTime = 0;
- assertTrue(waitForDownload(dlRequest, 15 * 60 * 1000));
+ assertTrue("download not finished", waitForDownload(dlRequest, 15 * 60 * 1000));
Log.i(LOG_TAG, "Verifying download information...");
// Verify specific info about the file (size, name, etc)...
@@ -233,7 +233,7 @@
dlRequest = mDownloadManager.enqueue(request);
// Rather large file, so wait up to 15 mins...
- assertTrue(waitForDownload(dlRequest, 15 * 60 * 1000));
+ assertTrue("download not finished", waitForDownload(dlRequest, 15 * 60 * 1000));
Cursor cursor = getCursor(dlRequest);
ParcelFileDescriptor pfd = null;
@@ -317,7 +317,7 @@
Log.i(LOG_TAG, "Turning on WiFi...");
setWiFiStateOn(true);
Log.i(LOG_TAG, "Waiting up to 10 minutes for download to complete...");
- assertTrue(waitForDownload(dlRequest, 10 * 60 * 1000));
+ assertTrue("download not finished", waitForDownload(dlRequest, 10 * 60 * 1000));
ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest);
verifyFileSize(pfd, filesize);
} finally {
@@ -385,7 +385,7 @@
setWiFiStateOn(true);
Log.i(LOG_TAG, "Waiting up to 10 minutes for download to complete...");
- assertTrue(waitForDownload(dlRequest, 10 * 60 * 1000));
+ assertTrue("download not finished", waitForDownload(dlRequest, 10 * 60 * 1000));
ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest);
verifyFileSize(pfd, filesize);
} finally {
@@ -456,7 +456,7 @@
setAirplaneModeOn(false);
Log.i(LOG_TAG, "Waiting up to 10 minutes for donwload to complete...");
- assertTrue(waitForDownload(dlRequest, 10 * 60 * 1000)); // wait up to 10 mins
+ assertTrue("download not finished", waitForDownload(dlRequest, 10 * 60 * 1000)); // wait up to 10 mins
ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest);
verifyFileSize(pfd, filesize);
} finally {
@@ -489,11 +489,11 @@
Request request = new Request(remoteUri);
request.setTitle(filename);
dlRequest = mDownloadManager.enqueue(request);
- assertTrue(dlRequest != -1);
+ assertTrue("request id is -1 from download manager", dlRequest != -1);
downloadIds.add(dlRequest);
}
- assertTrue(waitForMultipleDownloads(downloadIds, 15 * 60 * 2000)); // wait 15 mins max
+ assertTrue("download not finished", waitForMultipleDownloads(downloadIds, 15 * 60 * 2000)); // wait 15 mins max
} finally {
removeAllCurrentDownloads();
}
diff --git a/core/tests/inputmethodtests/src/android/os/InputMethodTest.java b/core/tests/inputmethodtests/src/android/os/InputMethodTest.java
index fa1bd8f..5958c3a 100644
--- a/core/tests/inputmethodtests/src/android/os/InputMethodTest.java
+++ b/core/tests/inputmethodtests/src/android/os/InputMethodTest.java
@@ -26,6 +26,7 @@
import android.test.suitebuilder.annotation.SmallTest;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
+import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
import java.util.ArrayList;
import java.util.List;
@@ -159,8 +160,15 @@
private static InputMethodSubtype createDummyInputMethodSubtype(String locale, String mode,
boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype) {
- return new InputMethodSubtype(0, 0, locale, mode, "", isAuxiliary,
- overridesImplicitlyEnabledSubtype);
+ return new InputMethodSubtypeBuilder()
+ .setSubtypeNameResId(0)
+ .setSubtypeIconResId(0)
+ .setSubtypeLocale(locale)
+ .setSubtypeMode(mode)
+ .setSubtypeExtraValue("")
+ .setIsAuxiliary(isAuxiliary)
+ .setOverridesImplicitlyEnabledSubtype(overridesImplicitlyEnabledSubtype)
+ .build();
}
private static InputMethodInfo createDefaultAutoDummyVoiceIme() {
diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index 1e5fc4d..808f04a 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -64,7 +64,7 @@
</div>
-<p style="clear:both"><em>Data collected during a 7-day period ending on August 12, 2014.
+<p style="clear:both"><em>Data collected during a 7-day period ending on September 9, 2014.
<br/>Any versions with less than 0.1% distribution are not shown.</em>
</p>
@@ -95,7 +95,8 @@
</div>
-<p style="clear:both"><em>Data collected during a 7-day period ending on August 12, 2014.
+<p style="clear:both"><em>Data collected during a 7-day period ending on September 9, 2014.
+
<br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
@@ -114,7 +115,7 @@
<img alt="" style="float:right"
-src="//chart.googleapis.com/chart?chs=400x250&cht=p&chd=t%3A0.1%2C80.2%2C19.7&chf=bg%2Cs%2C00000000&chl=GL%201.1%20only%7CGL%202.0%7CGL%203.0&chco=c4df9b%2C6fad0c" />
+src="//chart.googleapis.com/chart?chs=400x250&cht=p&chd=t%3A77.5%2C22.5&chf=bg%2Cs%2C00000000&chl=GL%202.0%7CGL%203.0&chco=c4df9b%2C6fad0c" />
<p>To declare which version of OpenGL ES your application requires, you should use the {@code
android:glEsVersion} attribute of the <a
@@ -131,22 +132,18 @@
<th scope="col">Distribution</th>
</tr>
<tr>
-<td>1.1 only</th>
-<td>0.1%</td>
+<td>2.0</td>
+<td>77.5%</td>
</tr>
<tr>
-<td>2.0</th>
-<td>80.2%</td>
-</tr>
-<tr>
-<td>3.0</th>
-<td>19.7%</td>
+<td>3.0</td>
+<td>22.5%</td>
</tr>
</table>
-<p style="clear:both"><em>Data collected during a 7-day period ending on August 12, 2014</em></p>
+<p style="clear:both"><em>Data collected during a 7-day period ending on September 9, 2014</em></p>
@@ -164,7 +161,7 @@
var VERSION_DATA =
[
{
- "chart": "//chart.googleapis.com/chart?cht=p&chs=500x250&chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat&chd=t%3A0.7%2C13.6%2C10.6%2C54.2%2C20.9&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c",
+ "chart": "//chart.googleapis.com/chart?chco=c4df9b%2C6fad0c&cht=p&chs=500x250&chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat&chd=t%3A0.7%2C11.4%2C9.6%2C53.8%2C24.5&chf=bg%2Cs%2C00000000",
"data": [
{
"api": 8,
@@ -174,41 +171,38 @@
{
"api": 10,
"name": "Gingerbread",
- "perc": "13.6"
+ "perc": "11.4"
},
{
"api": 15,
"name": "Ice Cream Sandwich",
- "perc": "10.6"
+ "perc": "9.6"
},
{
"api": 16,
"name": "Jelly Bean",
- "perc": "26.5"
+ "perc": "25.1"
},
{
"api": 17,
"name": "Jelly Bean",
- "perc": "19.8"
+ "perc": "20.7"
},
{
"api": 18,
"name": "Jelly Bean",
- "perc": "7.9"
+ "perc": "8.0"
},
{
"api": 19,
"name": "KitKat",
- "perc": "20.9"
+ "perc": "24.5"
}
]
}
];
-
-
-
var SCREEN_DATA =
[
{
@@ -216,27 +210,27 @@
"Large": {
"hdpi": "0.6",
"ldpi": "0.5",
- "mdpi": "4.2",
- "tvdpi": "1.6",
- "xhdpi": "0.5"
+ "mdpi": "4.3",
+ "tvdpi": "1.7",
+ "xhdpi": "0.6"
},
"Normal": {
- "hdpi": "35.5",
- "mdpi": "11.8",
- "xhdpi": "18.4",
- "xxhdpi": "15.2"
+ "hdpi": "35.7",
+ "mdpi": "10.6",
+ "xhdpi": "19.2",
+ "xxhdpi": "16.2"
},
"Small": {
- "ldpi": "7.4"
+ "ldpi": "6.2"
},
"Xlarge": {
"hdpi": "0.3",
- "mdpi": "3.6",
+ "mdpi": "3.7",
"xhdpi": "0.4"
}
},
- "densitychart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chd=t%3A7.9%2C19.6%2C1.6%2C36.4%2C19.3%2C15.2&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c",
- "layoutchart": "//chart.googleapis.com/chart?cht=p&chs=400x250&chl=Xlarge%7CLarge%7CNormal%7CSmall&chd=t%3A4.3%2C7.4%2C80.9%2C7.4&chf=bg%2Cs%2C00000000&chco=c4df9b%2C6fad0c"
+ "densitychart": "//chart.googleapis.com/chart?chco=c4df9b%2C6fad0c&cht=p&chs=400x250&chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chd=t%3A6.7%2C18.6%2C1.7%2C36.6%2C20.2%2C16.2&chf=bg%2Cs%2C00000000",
+ "layoutchart": "//chart.googleapis.com/chart?chco=c4df9b%2C6fad0c&cht=p&chs=400x250&chl=Xlarge%7CLarge%7CNormal%7CSmall&chd=t%3A4.4%2C7.7%2C81.7%2C6.2&chf=bg%2Cs%2C00000000"
}
];
diff --git a/docs/html/tools/building/index.jd b/docs/html/tools/building/index.jd
index c64942f..c1f3019 100644
--- a/docs/html/tools/building/index.jd
+++ b/docs/html/tools/building/index.jd
@@ -79,3 +79,14 @@
running on a device.</li>
</ul>
+<p class="note"><b>Note:</b> Apps are limited to a 64K method reference limit. If your app reaches
+this limit, the build process outputs the following error message:
+
+<pre>Unable to execute dex: method ID not in [0, 0xffff]: 65536.</pre>
+
+To avoid this, you can
+<a href="http://android-developers.blogspot.com.es/2011/07/custom-class-loading-in-dalvik.html">load
+secondary dex files at runtime</a> and use
+<a href="http://developer.android.com/tools/help/proguard.html">ProGuard</a> to strip out unnecessary
+class references (Proguard only works when building in release mode).
+</p>
\ No newline at end of file
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index ba22550..49e8b9d 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -27,6 +27,7 @@
import android.graphics.Outline;
import android.graphics.PorterDuff;
import android.graphics.Rect;
+import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
@@ -131,7 +132,9 @@
private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false;
- private final AnimatedVectorDrawableState mAnimatedVectorState;
+ private AnimatedVectorDrawableState mAnimatedVectorState;
+
+ private boolean mMutated;
public AnimatedVectorDrawable() {
mAnimatedVectorState = new AnimatedVectorDrawableState(
@@ -140,7 +143,6 @@
private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res,
Theme theme) {
- // TODO: Correctly handle the constant state for AVD.
mAnimatedVectorState = new AnimatedVectorDrawableState(state);
if (theme != null && canApplyTheme()) {
applyTheme(theme);
@@ -148,8 +150,17 @@
}
@Override
+ public Drawable mutate() {
+ if (!mMutated && super.mutate() == this) {
+ mAnimatedVectorState = new AnimatedVectorDrawableState(mAnimatedVectorState);
+ mMutated = true;
+ }
+ return this;
+ }
+
+ @Override
public ConstantState getConstantState() {
- return null;
+ return mAnimatedVectorState;
}
@Override
@@ -252,6 +263,7 @@
throws XmlPullParserException, IOException {
int eventType = parser.getEventType();
+ float pathErrorScale = 1;
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
final String tagName = parser.getName();
@@ -261,9 +273,11 @@
int drawableRes = a.getResourceId(
R.styleable.AnimatedVectorDrawable_drawable, 0);
if (drawableRes != 0) {
- mAnimatedVectorState.mVectorDrawable = (VectorDrawable) res.getDrawable(
+ VectorDrawable vectorDrawable = (VectorDrawable) res.getDrawable(
drawableRes, theme).mutate();
- mAnimatedVectorState.mVectorDrawable.setAllowCaching(false);
+ vectorDrawable.setAllowCaching(false);
+ pathErrorScale = vectorDrawable.getPixelSize();
+ mAnimatedVectorState.mVectorDrawable = vectorDrawable;
}
a.recycle();
} else if (TARGET.equals(tagName)) {
@@ -275,7 +289,8 @@
int id = a.getResourceId(
R.styleable.AnimatedVectorDrawableTarget_animation, 0);
if (id != 0) {
- Animator objectAnimator = AnimatorInflater.loadAnimator(res, theme, id);
+ Animator objectAnimator = AnimatorInflater.loadAnimator(res, theme, id,
+ pathErrorScale);
setupAnimatorsForTarget(target, objectAnimator);
}
a.recycle();
@@ -307,14 +322,31 @@
int mChangingConfigurations;
VectorDrawable mVectorDrawable;
ArrayList<Animator> mAnimators;
+ ArrayMap<Animator, String> mTargetNameMap;
public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy) {
if (copy != null) {
mChangingConfigurations = copy.mChangingConfigurations;
- // TODO: Make sure the constant state are handled correctly.
- mVectorDrawable = new VectorDrawable();
- mVectorDrawable.setAllowCaching(false);
- mAnimators = new ArrayList<Animator>();
+ if (copy.mVectorDrawable != null) {
+ mVectorDrawable = (VectorDrawable) copy.mVectorDrawable.getConstantState().newDrawable();
+ mVectorDrawable.mutate();
+ mVectorDrawable.setAllowCaching(false);
+ mVectorDrawable.setBounds(copy.mVectorDrawable.getBounds());
+ }
+ if (copy.mAnimators != null) {
+ final int numAnimators = copy.mAnimators.size();
+ mAnimators = new ArrayList<Animator>(numAnimators);
+ mTargetNameMap = new ArrayMap<Animator, String>(numAnimators);
+ for (int i = 0; i < numAnimators; ++i) {
+ Animator anim = copy.mAnimators.get(i);
+ Animator animClone = anim.clone();
+ String targetName = copy.mTargetNameMap.get(anim);
+ Object targetObject = mVectorDrawable.getTargetByName(targetName);
+ animClone.setTarget(targetObject);
+ mAnimators.add(animClone);
+ mTargetNameMap.put(animClone, targetName);
+ }
+ }
}
}
@@ -342,7 +374,12 @@
private void setupAnimatorsForTarget(String name, Animator animator) {
Object target = mAnimatedVectorState.mVectorDrawable.getTargetByName(name);
animator.setTarget(target);
+ if (mAnimatedVectorState.mAnimators == null) {
+ mAnimatedVectorState.mAnimators = new ArrayList<Animator>();
+ mAnimatedVectorState.mTargetNameMap = new ArrayMap<Animator, String>();
+ }
mAnimatedVectorState.mAnimators.add(animator);
+ mAnimatedVectorState.mTargetNameMap.put(animator, name);
if (DBG_ANIMATION_VECTOR_DRAWABLE) {
Log.v(LOGTAG, "add animator for target " + name + " " + animator);
}
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 042da5b..65ab454 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -368,6 +368,29 @@
}
}
+ /**
+ * The size of a pixel when scaled from the intrinsic dimension to the viewport dimension.
+ * This is used to calculate the path animation accuracy.
+ *
+ * @hide
+ */
+ public float getPixelSize() {
+ if (mVectorState == null && mVectorState.mVPathRenderer == null ||
+ mVectorState.mVPathRenderer.mBaseWidth == 0 ||
+ mVectorState.mVPathRenderer.mBaseHeight == 0 ||
+ mVectorState.mVPathRenderer.mViewportHeight == 0 ||
+ mVectorState.mVPathRenderer.mViewportWidth == 0) {
+ return 1; // fall back to 1:1 pixel mapping.
+ }
+ float intrinsicWidth = mVectorState.mVPathRenderer.mBaseWidth;
+ float intrinsicHeight = mVectorState.mVPathRenderer.mBaseHeight;
+ float viewportWidth = mVectorState.mVPathRenderer.mViewportWidth;
+ float viewportHeight = mVectorState.mVPathRenderer.mViewportHeight;
+ float scaleX = viewportWidth / intrinsicWidth;
+ float scaleY = viewportHeight / intrinsicHeight;
+ return Math.min(scaleX, scaleY);
+ }
+
/** @hide */
public static VectorDrawable create(Resources resources, int rid) {
try {
@@ -606,6 +629,15 @@
mThemeAttrs = copy.mThemeAttrs;
mChangingConfigurations = copy.mChangingConfigurations;
mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
+ if (copy.mVPathRenderer.mFillPaint != null) {
+ mVPathRenderer.mFillPaint = new Paint(copy.mVPathRenderer.mFillPaint);
+ }
+ if (copy.mVPathRenderer.mStrokePaint != null) {
+ mVPathRenderer.mStrokePaint = new Paint(copy.mVPathRenderer.mStrokePaint);
+ }
+ if (copy.mVPathRenderer.mColorFilter != null) {
+ mVPathRenderer.mColorFilter = copy.mVPathRenderer.mColorFilter;
+ }
mTint = copy.mTint;
mTintMode = copy.mTintMode;
mAutoMirrored = copy.mAutoMirrored;
@@ -677,8 +709,8 @@
*/
// Variables that only used temporarily inside the draw() call, so there
// is no need for deep copying.
- private final Path mPath = new Path();
- private final Path mRenderPath = new Path();
+ private final Path mPath;
+ private final Path mRenderPath;
private static final Matrix IDENTITY_MATRIX = new Matrix();
private final Matrix mFinalPathMatrix = new Matrix();
@@ -701,6 +733,8 @@
public VPathRenderer() {
mRootGroup = new VGroup();
+ mPath = new Path();
+ mRenderPath = new Path();
}
public void setRootAlpha(int alpha) {
@@ -713,6 +747,8 @@
public VPathRenderer(VPathRenderer copy) {
mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap);
+ mPath = new Path(copy.mPath);
+ mRenderPath = new Path(copy.mRenderPath);
mBaseWidth = copy.mBaseWidth;
mBaseHeight = copy.mBaseHeight;
mViewportWidth = copy.mViewportWidth;
diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java
new file mode 100644
index 0000000..9837139
--- /dev/null
+++ b/graphics/java/android/graphics/pdf/PdfEditor.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.pdf;
+
+import android.annotation.NonNull;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.OsConstants;
+import dalvik.system.CloseGuard;
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+
+import java.io.IOException;
+
+/**
+ * Class for editing PDF files.
+ *
+ * @hide
+ */
+public final class PdfEditor {
+
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
+ private final long mNativeDocument;
+
+ private int mPageCount;
+
+ private ParcelFileDescriptor mInput;
+
+ /**
+ * Creates a new instance.
+ * <p>
+ * <strong>Note:</strong> The provided file descriptor must be <strong>seekable</strong>,
+ * i.e. its data being randomly accessed, e.g. pointing to a file. After finishing
+ * with this class you must call {@link #close()}.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> This class takes ownership of the passed in file descriptor
+ * and is responsible for closing it when the editor is closed.
+ * </p>
+ *
+ * @param input Seekable file descriptor to read from.
+ *
+ * @see #close()
+ */
+ public PdfEditor(@NonNull ParcelFileDescriptor input) throws IOException {
+ if (input == null) {
+ throw new NullPointerException("input cannot be null");
+ }
+
+ final long size;
+ try {
+ Libcore.os.lseek(input.getFileDescriptor(), 0, OsConstants.SEEK_SET);
+ size = Libcore.os.fstat(input.getFileDescriptor()).st_size;
+ } catch (ErrnoException ee) {
+ throw new IllegalArgumentException("file descriptor not seekable");
+ }
+
+ mInput = input;
+ mNativeDocument = nativeOpen(mInput.getFd(), size);
+ mPageCount = nativeGetPageCount(mNativeDocument);
+ mCloseGuard.open("close");
+ }
+
+ /**
+ * Gets the number of pages in the document.
+ *
+ * @return The page count.
+ */
+ public int getPageCount() {
+ throwIfClosed();
+ return mPageCount;
+ }
+
+ /**
+ * Removes the page with a given index.
+ *
+ * @param pageIndex The page to remove.
+ */
+ public void removePage(int pageIndex) {
+ throwIfClosed();
+ throwIfPageNotInDocument(pageIndex);
+ mPageCount = nativeRemovePage(mNativeDocument, pageIndex);
+ }
+
+ /**
+ * Writes the PDF file to the provided destination.
+ * <p>
+ * <strong>Note:</strong> This method takes ownership of the passed in file
+ * descriptor and is responsible for closing it when writing completes.
+ * </p>
+ * @param output The destination.
+ */
+ public void write(ParcelFileDescriptor output) throws IOException {
+ try {
+ throwIfClosed();
+ nativeWrite(mNativeDocument, output.getFd());
+ } finally {
+ IoUtils.closeQuietly(output);
+ }
+ }
+
+ /**
+ * Closes this editor. You should not use this instance
+ * after this method is called.
+ */
+ public void close() {
+ throwIfClosed();
+ doClose();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ mCloseGuard.warnIfOpen();
+ if (mInput != null) {
+ doClose();
+ }
+ } finally {
+ super.finalize();
+ }
+ }
+
+ private void doClose() {
+ nativeClose(mNativeDocument);
+ IoUtils.closeQuietly(mInput);
+ mInput = null;
+ mCloseGuard.close();
+ }
+
+ private void throwIfClosed() {
+ if (mInput == null) {
+ throw new IllegalStateException("Already closed");
+ }
+ }
+
+ private void throwIfPageNotInDocument(int pageIndex) {
+ if (pageIndex < 0 || pageIndex >= mPageCount) {
+ throw new IllegalArgumentException("Invalid page index");
+ }
+ }
+
+ private static native long nativeOpen(int fd, long size);
+ private static native void nativeClose(long documentPtr);
+ private static native int nativeGetPageCount(long documentPtr);
+ private static native int nativeRemovePage(long documentPtr, int pageIndex);
+ private static native void nativeWrite(long documentPtr, int fd);
+}
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
index 1072b3c..359c294 100644
--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -239,7 +239,7 @@
}
private void throwIfPageNotInDocument(int pageIndex) {
- if (pageIndex >= mPageCount) {
+ if (pageIndex < 0 || pageIndex >= mPageCount) {
throw new IllegalArgumentException("Invalid page index");
}
}
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 9855f71..f853d1f 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -551,9 +551,13 @@
}
void Caches::bindTexture(GLenum target, GLuint texture) {
- if (mBoundTextures[mTextureUnit] != texture) {
+ if (target == GL_TEXTURE_2D) {
+ bindTexture(texture);
+ } else {
+ // GLConsumer directly calls glBindTexture() with
+ // target=GL_TEXTURE_EXTERNAL_OES, don't cache this target
+ // since the cached state could be stale
glBindTexture(target, texture);
- mBoundTextures[mTextureUnit] = texture;
}
}
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 726b74d..7aa628c 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -431,6 +431,7 @@
uint32_t mFunctorsCount;
+ // Caches texture bindings for the GL_TEXTURE_2D target
GLuint mBoundTextures[REQUIRED_TEXTURE_UNITS_COUNT];
OverdrawColorSet mOverdrawDebugColorSet;
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index e30ac19..281ca02 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -162,14 +162,21 @@
}
/**
- * Outset the bounds of point data (for line endpoints or points) to account for AA stroke
+ * Outset the bounds of point data (for line endpoints or points) to account for stroke
* geometry.
+ *
+ * bounds are in pre-scaled space.
*/
void expandBoundsForStroke(Rect* bounds) const {
- float outset = halfStrokeWidth;
- if (outset == 0) outset = 0.5f;
- bounds->outset(outset * inverseScaleX + Vertex::GeometryFudgeFactor(),
- outset * inverseScaleY + Vertex::GeometryFudgeFactor());
+ if (halfStrokeWidth == 0) {
+ // hairline, outset by (0.5f + fudge factor) in post-scaling space
+ bounds->outset(fabs(inverseScaleX) * (0.5f + Vertex::GeometryFudgeFactor()),
+ fabs(inverseScaleY) * (0.5f + Vertex::GeometryFudgeFactor()));
+ } else {
+ // non hairline, outset by half stroke width pre-scaled, and fudge factor post scaled
+ bounds->outset(halfStrokeWidth + fabs(inverseScaleX) * Vertex::GeometryFudgeFactor(),
+ halfStrokeWidth + fabs(inverseScaleY) * Vertex::GeometryFudgeFactor());
+ }
}
};
diff --git a/media/java/android/media/AudioDevice.java b/media/java/android/media/AudioDevice.java
index e078354..df4d60d 100644
--- a/media/java/android/media/AudioDevice.java
+++ b/media/java/android/media/AudioDevice.java
@@ -20,90 +20,91 @@
/**
* Class to provide information about the audio devices.
+ * @hide
*/
public class AudioDevice {
/**
* A device type associated with an unknown or uninitialized device.
*/
- public static final int DEVICE_TYPE_UNKNOWN = 0;
+ public static final int TYPE_UNKNOWN = 0;
/**
* A device type describing the attached earphone speaker.
*/
- public static final int DEVICE_TYPE_BUILTIN_EARPIECE = 1;
+ public static final int TYPE_BUILTIN_EARPIECE = 1;
/**
* A device type describing the speaker system (i.e. a mono speaker or stereo speakers) built
* in a device.
*/
- public static final int DEVICE_TYPE_BUILTIN_SPEAKER = 2;
+ public static final int TYPE_BUILTIN_SPEAKER = 2;
/**
* A device type describing a headset, which is the combination of a headphones and microphone.
*/
- public static final int DEVICE_TYPE_WIRED_HEADSET = 3;
+ public static final int TYPE_WIRED_HEADSET = 3;
/**
* A device type describing a pair of wired headphones .
*/
- public static final int DEVICE_TYPE_WIRED_HEADPHONES = 4;
+ public static final int TYPE_WIRED_HEADPHONES = 4;
/**
* A device type describing an analog line-level connection.
*/
- public static final int DEVICE_TYPE_LINE_ANALOG = 5;
+ public static final int TYPE_LINE_ANALOG = 5;
/**
* A device type describing a digital line connection (e.g. SPDIF).
*/
- public static final int DEVICE_TYPE_LINE_DIGITAL = 6;
+ public static final int TYPE_LINE_DIGITAL = 6;
/**
* A device type describing a Bluetooth device typically used for telephony .
*/
- public static final int DEVICE_TYPE_BLUETOOTH_SCO = 7;
+ public static final int TYPE_BLUETOOTH_SCO = 7;
/**
* A device type describing a Bluetooth device supporting the A2DP profile.
*/
- public static final int DEVICE_TYPE_BLUETOOTH_A2DP = 8;
+ public static final int TYPE_BLUETOOTH_A2DP = 8;
/**
* A device type describing an HDMI connection .
*/
- public static final int DEVICE_TYPE_HDMI = 9;
+ public static final int TYPE_HDMI = 9;
/**
* A device type describing the Audio Return Channel of an HDMI connection.
*/
- public static final int DEVICE_TYPE_HDMI_ARC = 10;
+ public static final int TYPE_HDMI_ARC = 10;
/**
* A device type describing a USB audio device.
*/
- public static final int DEVICE_TYPE_USB_DEVICE = 11;
+ public static final int TYPE_USB_DEVICE = 11;
/**
* A device type describing a USB audio device in accessory mode.
*/
- public static final int DEVICE_TYPE_USB_ACCESSORY = 12;
+ public static final int TYPE_USB_ACCESSORY = 12;
/**
* A device type describing the audio device associated with a dock.
*/
- public static final int DEVICE_TYPE_DOCK = 13;
+ public static final int TYPE_DOCK = 13;
/**
* A device type associated with the transmission of audio signals over FM.
*/
- public static final int DEVICE_TYPE_FM = 14;
+ public static final int TYPE_FM = 14;
/**
* A device type describing the microphone(s) built in a device.
*/
- public static final int DEVICE_TYPE_BUILTIN_MIC = 15;
+ public static final int TYPE_BUILTIN_MIC = 15;
/**
* A device type for accessing the audio content transmitted over FM.
*/
- public static final int DEVICE_TYPE_FM_TUNER = 16;
+ public static final int TYPE_FM_TUNER = 16;
/**
* A device type for accessing the audio content transmitted over the TV tuner system.
*/
- public static final int DEVICE_TYPE_TV_TUNER = 17;
+ public static final int TYPE_TV_TUNER = 17;
/**
* A device type describing the transmission of audio signals over the telephony network.
*/
- public static final int DEVICE_TYPE_TELEPHONY = 18;
+ public static final int TYPE_TELEPHONY = 18;
/**
* A device type describing the auxiliary line-level connectors.
*/
- public static final int DEVICE_TYPE_AUX_LINE = 19;
+ public static final int TYPE_AUX_LINE = 19;
AudioDevicePortConfig mConfig;
@@ -135,7 +136,7 @@
* @return
*/
public int getDeviceType() {
- return INT_TO_EXT_DEVICE_MAPPING.get(mConfig.port().type(), DEVICE_TYPE_UNKNOWN);
+ return INT_TO_EXT_DEVICE_MAPPING.get(mConfig.port().type(), TYPE_UNKNOWN);
}
/**
@@ -154,7 +155,7 @@
/** @hide */
public static int convertInternalDeviceToDeviceType(int intDevice) {
- return INT_TO_EXT_DEVICE_MAPPING.get(intDevice, DEVICE_TYPE_UNKNOWN);
+ return INT_TO_EXT_DEVICE_MAPPING.get(intDevice, TYPE_UNKNOWN);
}
private static final SparseIntArray INT_TO_EXT_DEVICE_MAPPING;
@@ -163,43 +164,43 @@
static {
INT_TO_EXT_DEVICE_MAPPING = new SparseIntArray();
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_EARPIECE, DEVICE_TYPE_BUILTIN_EARPIECE);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_SPEAKER, DEVICE_TYPE_BUILTIN_SPEAKER);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_WIRED_HEADSET, DEVICE_TYPE_WIRED_HEADSET);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, DEVICE_TYPE_WIRED_HEADPHONES);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, DEVICE_TYPE_BLUETOOTH_SCO);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET, DEVICE_TYPE_BLUETOOTH_SCO);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT, DEVICE_TYPE_BLUETOOTH_SCO);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, DEVICE_TYPE_BLUETOOTH_A2DP);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, DEVICE_TYPE_BLUETOOTH_A2DP);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, DEVICE_TYPE_BLUETOOTH_A2DP);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_HDMI, DEVICE_TYPE_HDMI);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET, DEVICE_TYPE_DOCK);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET, DEVICE_TYPE_DOCK);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_USB_ACCESSORY, DEVICE_TYPE_USB_ACCESSORY);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_USB_DEVICE, DEVICE_TYPE_USB_DEVICE);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_TELEPHONY_TX, DEVICE_TYPE_TELEPHONY);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_LINE, DEVICE_TYPE_LINE_ANALOG);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_HDMI_ARC, DEVICE_TYPE_HDMI_ARC);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_SPDIF, DEVICE_TYPE_LINE_DIGITAL);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_FM, DEVICE_TYPE_FM);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_AUX_LINE, DEVICE_TYPE_AUX_LINE);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_EARPIECE, TYPE_BUILTIN_EARPIECE);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_SPEAKER, TYPE_BUILTIN_SPEAKER);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_WIRED_HEADSET, TYPE_WIRED_HEADSET);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, TYPE_WIRED_HEADPHONES);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO, TYPE_BLUETOOTH_SCO);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET, TYPE_BLUETOOTH_SCO);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT, TYPE_BLUETOOTH_SCO);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, TYPE_BLUETOOTH_A2DP);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, TYPE_BLUETOOTH_A2DP);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, TYPE_BLUETOOTH_A2DP);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_HDMI, TYPE_HDMI);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET, TYPE_DOCK);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET, TYPE_DOCK);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_USB_ACCESSORY, TYPE_USB_ACCESSORY);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_USB_DEVICE, TYPE_USB_DEVICE);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_TELEPHONY_TX, TYPE_TELEPHONY);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_LINE, TYPE_LINE_ANALOG);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_HDMI_ARC, TYPE_HDMI_ARC);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_SPDIF, TYPE_LINE_DIGITAL);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_FM, TYPE_FM);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_OUT_AUX_LINE, TYPE_AUX_LINE);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUILTIN_MIC, DEVICE_TYPE_BUILTIN_MIC);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET, DEVICE_TYPE_BLUETOOTH_SCO);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_WIRED_HEADSET, DEVICE_TYPE_WIRED_HEADSET);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_HDMI, DEVICE_TYPE_HDMI);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_TELEPHONY_RX, DEVICE_TYPE_TELEPHONY);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BACK_MIC, DEVICE_TYPE_BUILTIN_MIC);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET, DEVICE_TYPE_DOCK);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET, DEVICE_TYPE_DOCK);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_USB_ACCESSORY, DEVICE_TYPE_USB_ACCESSORY);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_USB_DEVICE, DEVICE_TYPE_USB_DEVICE);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_FM_TUNER, DEVICE_TYPE_FM_TUNER);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_TV_TUNER, DEVICE_TYPE_TV_TUNER);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_LINE, DEVICE_TYPE_LINE_ANALOG);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_SPDIF, DEVICE_TYPE_LINE_DIGITAL);
- INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, DEVICE_TYPE_BLUETOOTH_A2DP);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BUILTIN_MIC, TYPE_BUILTIN_MIC);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET, TYPE_BLUETOOTH_SCO);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_WIRED_HEADSET, TYPE_WIRED_HEADSET);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_HDMI, TYPE_HDMI);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_TELEPHONY_RX, TYPE_TELEPHONY);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BACK_MIC, TYPE_BUILTIN_MIC);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET, TYPE_DOCK);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET, TYPE_DOCK);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_USB_ACCESSORY, TYPE_USB_ACCESSORY);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_USB_DEVICE, TYPE_USB_DEVICE);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_FM_TUNER, TYPE_FM_TUNER);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_TV_TUNER, TYPE_TV_TUNER);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_LINE, TYPE_LINE_ANALOG);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_SPDIF, TYPE_LINE_DIGITAL);
+ INT_TO_EXT_DEVICE_MAPPING.put(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, TYPE_BLUETOOTH_A2DP);
// not covered here, legacy
//AudioSystem.DEVICE_OUT_REMOTE_SUBMIX
@@ -207,25 +208,25 @@
// privileges mapping to output device
EXT_TO_INT_DEVICE_MAPPING = new SparseIntArray();
- EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_BUILTIN_EARPIECE, AudioSystem.DEVICE_OUT_EARPIECE);
- EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_BUILTIN_SPEAKER, AudioSystem.DEVICE_OUT_SPEAKER);
- EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_WIRED_HEADSET, AudioSystem.DEVICE_OUT_WIRED_HEADSET);
- EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_WIRED_HEADPHONES, AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
- EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_LINE_ANALOG, AudioSystem.DEVICE_OUT_LINE);
- EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_LINE_DIGITAL, AudioSystem.DEVICE_OUT_SPDIF);
- EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_BLUETOOTH_SCO, AudioSystem.DEVICE_OUT_BLUETOOTH_SCO);
- EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_BLUETOOTH_A2DP, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
- EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_HDMI, AudioSystem.DEVICE_OUT_HDMI);
- EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_HDMI_ARC, AudioSystem.DEVICE_OUT_HDMI_ARC);
- EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_USB_DEVICE, AudioSystem.DEVICE_OUT_USB_DEVICE);
- EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_USB_ACCESSORY, AudioSystem.DEVICE_OUT_USB_ACCESSORY);
- EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_DOCK, AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
- EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_FM, AudioSystem.DEVICE_OUT_FM);
- EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_BUILTIN_MIC, AudioSystem.DEVICE_IN_BUILTIN_MIC);
- EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_FM_TUNER, AudioSystem.DEVICE_IN_FM_TUNER);
- EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_TV_TUNER, AudioSystem.DEVICE_IN_TV_TUNER);
- EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_TELEPHONY, AudioSystem.DEVICE_OUT_TELEPHONY_TX);
- EXT_TO_INT_DEVICE_MAPPING.put(DEVICE_TYPE_AUX_LINE, AudioSystem.DEVICE_OUT_AUX_LINE);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BUILTIN_EARPIECE, AudioSystem.DEVICE_OUT_EARPIECE);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BUILTIN_SPEAKER, AudioSystem.DEVICE_OUT_SPEAKER);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_WIRED_HEADSET, AudioSystem.DEVICE_OUT_WIRED_HEADSET);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_WIRED_HEADPHONES, AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_LINE_ANALOG, AudioSystem.DEVICE_OUT_LINE);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_LINE_DIGITAL, AudioSystem.DEVICE_OUT_SPDIF);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLUETOOTH_SCO, AudioSystem.DEVICE_OUT_BLUETOOTH_SCO);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BLUETOOTH_A2DP, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_HDMI, AudioSystem.DEVICE_OUT_HDMI);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_HDMI_ARC, AudioSystem.DEVICE_OUT_HDMI_ARC);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_USB_DEVICE, AudioSystem.DEVICE_OUT_USB_DEVICE);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_USB_ACCESSORY, AudioSystem.DEVICE_OUT_USB_ACCESSORY);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_DOCK, AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_FM, AudioSystem.DEVICE_OUT_FM);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_BUILTIN_MIC, AudioSystem.DEVICE_IN_BUILTIN_MIC);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_FM_TUNER, AudioSystem.DEVICE_IN_FM_TUNER);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_TV_TUNER, AudioSystem.DEVICE_IN_TV_TUNER);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_TELEPHONY, AudioSystem.DEVICE_OUT_TELEPHONY_TX);
+ EXT_TO_INT_DEVICE_MAPPING.put(TYPE_AUX_LINE, AudioSystem.DEVICE_OUT_AUX_LINE);
}
}
diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java
index 8883d28..5651fc9 100644
--- a/media/java/android/media/CamcorderProfile.java
+++ b/media/java/android/media/CamcorderProfile.java
@@ -177,9 +177,15 @@
*/
public static final int QUALITY_HIGH_SPEED_1080P = 2004;
+ /**
+ * High speed ( >= 100fps) quality level corresponding to the 2160p (3840 x 2160)
+ * resolution.
+ */
+ public static final int QUALITY_HIGH_SPEED_2160P = 2005;
+
// Start and end of high speed quality list
private static final int QUALITY_HIGH_SPEED_LIST_START = QUALITY_HIGH_SPEED_LOW;
- private static final int QUALITY_HIGH_SPEED_LIST_END = QUALITY_HIGH_SPEED_1080P;
+ private static final int QUALITY_HIGH_SPEED_LIST_END = QUALITY_HIGH_SPEED_2160P;
/**
* Default recording duration in seconds before the session is terminated.
@@ -313,6 +319,7 @@
* @see #QUALITY_HIGH_SPEED_480P
* @see #QUALITY_HIGH_SPEED_720P
* @see #QUALITY_HIGH_SPEED_1080P
+ * @see #QUALITY_HIGH_SPEED_2160P
*/
public static CamcorderProfile get(int cameraId, int quality) {
if (!((quality >= QUALITY_LIST_START &&
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 675916b..1c7c9ea 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -672,6 +672,11 @@
super(detailMessage);
mErrorCode = errorCode;
mActionCode = actionCode;
+
+ // TODO get this from codec
+ final String sign = errorCode < 0 ? "neg_" : "";
+ mDiagnosticInfo =
+ "android.media.MediaCodec.error_" + sign + Math.abs(errorCode);
}
/**
@@ -696,15 +701,28 @@
* Retrieve the error code associated with a CodecException.
* This is opaque diagnostic information and may depend on
* hardware or API level.
+ *
+ * @hide
*/
public int getErrorCode() {
return mErrorCode;
}
+ /**
+ * Retrieve a human readable diagnostic information string
+ * associated with the exception. DO NOT SHOW THIS TO END-USERS!
+ * This string will not be localized or generally comprehensible
+ * to end-users.
+ */
+ public String getDiagnosticInfo() {
+ return mDiagnosticInfo;
+ }
+
/* Must be in sync with android_media_MediaCodec.cpp */
private final static int ACTION_TRANSIENT = 1;
private final static int ACTION_RECOVERABLE = 2;
+ private final String mDiagnosticInfo;
private final int mErrorCode;
private final int mActionCode;
}
@@ -737,6 +755,13 @@
public static final int ERROR_RESOURCE_BUSY = 3;
/**
+ * This indicates that the output protection levels supported by the
+ * device are not sufficient to meet the requirements set by the
+ * content owner in the license policy.
+ */
+ public static final int ERROR_INSUFFICIENT_OUTPUT_PROTECTION = 4;
+
+ /**
* Retrieve the error code associated with a CryptoException
*/
public int getErrorCode() {
diff --git a/media/java/android/media/MediaCodecList.java b/media/java/android/media/MediaCodecList.java
index 85e9b16..0dcbd65 100644
--- a/media/java/android/media/MediaCodecList.java
+++ b/media/java/android/media/MediaCodecList.java
@@ -118,6 +118,7 @@
/** @hide */
public static MediaCodecInfo getInfoFor(String codec) {
+ initCodecList();
return sAllCodecInfos[findCodecByName(codec)];
}
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index ca707d8..1490732 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -188,18 +188,37 @@
*/
public static final class MediaDrmStateException extends java.lang.IllegalStateException {
private final int mErrorCode;
+ private final String mDiagnosticInfo;
public MediaDrmStateException(int errorCode, String detailMessage) {
super(detailMessage);
mErrorCode = errorCode;
+
+ // TODO get this from DRM session
+ final String sign = errorCode < 0 ? "neg_" : "";
+ mDiagnosticInfo =
+ "android.media.MediaDrm.error_" + sign + Math.abs(errorCode);
+
}
/**
* Retrieve the associated error code
+ *
+ * @hide
*/
public int getErrorCode() {
return mErrorCode;
}
+
+ /**
+ * Retrieve a human readable diagnostic information string
+ * associated with the exception. DO NOT SHOW THIS TO END-USERS!
+ * This string will not be localized or generally comprehensible
+ * to end-users.
+ */
+ public String getDiagnosticInfo() {
+ return mDiagnosticInfo;
+ }
}
/**
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 9343aa4..afa0b6e 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1929,6 +1929,7 @@
mSubtitleController.setAnchor(anchor);
}
+ private final Object mInbandSubtitleLock = new Object();
private SubtitleTrack[] mInbandSubtitleTracks;
private int mSelectedSubtitleTrackIndex = -1;
private Vector<SubtitleTrack> mOutOfBandSubtitleTracks;
@@ -2036,19 +2037,21 @@
}
TrackInfo[] tracks = getInbandTrackInfo();
- SubtitleTrack[] inbandTracks = new SubtitleTrack[tracks.length];
- for (int i=0; i < tracks.length; i++) {
- if (tracks[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
- if (i < mInbandSubtitleTracks.length) {
- inbandTracks[i] = mInbandSubtitleTracks[i];
- } else {
- SubtitleTrack track = mSubtitleController.addTrack(
- tracks[i].getFormat());
- inbandTracks[i] = track;
+ synchronized (mInbandSubtitleLock) {
+ SubtitleTrack[] inbandTracks = new SubtitleTrack[tracks.length];
+ for (int i=0; i < tracks.length; i++) {
+ if (tracks[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
+ if (i < mInbandSubtitleTracks.length) {
+ inbandTracks[i] = mInbandSubtitleTracks[i];
+ } else {
+ SubtitleTrack track = mSubtitleController.addTrack(
+ tracks[i].getFormat());
+ inbandTracks[i] = track;
+ }
}
}
+ mInbandSubtitleTracks = inbandTracks;
}
- mInbandSubtitleTracks = inbandTracks;
mSubtitleController.selectDefaultTrack();
}
@@ -2224,9 +2227,9 @@
try {
Libcore.os.lseek(fd3, offset2, OsConstants.SEEK_SET);
byte[] buffer = new byte[4096];
- for (int total = 0; total < length2;) {
- int remain = (int)length2 - total;
- int bytes = IoBridge.read(fd3, buffer, 0, Math.min(buffer.length, remain));
+ for (long total = 0; total < length2;) {
+ int bytesToRead = (int) Math.min(buffer.length, length2 - total);
+ int bytes = IoBridge.read(fd3, buffer, 0, bytesToRead);
if (bytes < 0) {
break;
} else {
@@ -2358,6 +2361,18 @@
throws IllegalStateException {
// handle subtitle track through subtitle controller
SubtitleTrack track = null;
+ synchronized (mInbandSubtitleLock) {
+ if (mInbandSubtitleTracks.length == 0) {
+ TrackInfo[] tracks = getInbandTrackInfo();
+ mInbandSubtitleTracks = new SubtitleTrack[tracks.length];
+ for (int i=0; i < tracks.length; i++) {
+ if (tracks[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
+ mInbandSubtitleTracks[i] = mSubtitleController.addTrack(tracks[i].getFormat());
+ }
+ }
+ }
+ }
+
if (index < mInbandSubtitleTracks.length) {
track = mInbandSubtitleTracks[index];
} else if (index < mInbandSubtitleTracks.length + mOutOfBandSubtitleTracks.size()) {
@@ -3256,9 +3271,7 @@
if (DEBUG) Log.d(TAG, "scheduleUpdate");
int i = registerListener(listener);
- if (mStopped) {
- scheduleNotification(NOTIFY_STOP, 0 /* delay */);
- } else {
+ if (!mStopped) {
mTimes[i] = 0;
scheduleNotification(NOTIFY_TIME, 0 /* delay */);
}
diff --git a/media/java/android/media/SubtitleController.java b/media/java/android/media/SubtitleController.java
index 37adb8c..f82dbe0 100644
--- a/media/java/android/media/SubtitleController.java
+++ b/media/java/android/media/SubtitleController.java
@@ -275,7 +275,7 @@
mSelectedTrack.getFormat().getInteger(
MediaFormat.KEY_IS_FORCED_SUBTITLE, 0) != 0)) {
show();
- } else {
+ } else if (mSelectedTrack != null && !mSelectedTrack.isTimedText()) {
hide();
}
mVisibilityIsExplicit = false;
diff --git a/media/java/android/media/audiofx/Virtualizer.java b/media/java/android/media/audiofx/Virtualizer.java
index b314c02..be5adc8 100644
--- a/media/java/android/media/audiofx/Virtualizer.java
+++ b/media/java/android/media/audiofx/Virtualizer.java
@@ -16,11 +16,14 @@
package android.media.audiofx;
+import android.annotation.IntDef;
import android.media.AudioDevice;
import android.media.AudioFormat;
import android.media.audiofx.AudioEffect;
import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.StringTokenizer;
@@ -248,14 +251,114 @@
}
/**
- * Checks if the combination of a channel mask and device type is supported by this virtualizer.
+ * A virtualization mode indicating virtualization processing is not active.
+ * See {@link #getVirtualizationMode()} as one of the possible return value.
+ */
+ public static final int VIRTUALIZATION_MODE_OFF = 0;
+
+ /**
+ * A virtualization mode used to indicate the virtualizer effect must stop forcing the
+ * processing to a particular mode in {@link #forceVirtualizationMode(int)}.
+ */
+ public static final int VIRTUALIZATION_MODE_AUTO = 1;
+ /**
+ * A virtualization mode typically used over headphones.
+ * Binaural virtualization describes an audio processing configuration for virtualization
+ * where the left and right channels are respectively reaching the left and right ear of the
+ * user, without also feeding the opposite ear (as is the case when listening over speakers).
+ * <p>Such a mode is therefore meant to be used when audio is playing over stereo wired
+ * headphones or headsets, but also stereo headphones through a wireless A2DP Bluetooth link.
+ * <p>See {@link #canVirtualize(int, int)} to verify this mode is supported by this Virtualizer.
+ */
+ public final static int VIRTUALIZATION_MODE_BINAURAL = 2;
+
+ /**
+ * A virtualization mode typically used over speakers.
+ * Transaural virtualization describes an audio processing configuration that differs from
+ * binaural (as described in {@link #VIRTUALIZATION_MODE_BINAURAL} in that cross-talk is
+ * present, i.e. audio played from the left channel also reaches the right ear of the user,
+ * and vice-versa.
+ * <p>When supported, such a mode is therefore meant to be used when audio is playing over the
+ * built-in stereo speakers of a device, if they are featured.
+ * <p>See {@link #canVirtualize(int, int)} to verify this mode is supported by this Virtualizer.
+ */
+ public final static int VIRTUALIZATION_MODE_TRANSAURAL = 3;
+
+ /** @hide */
+ @IntDef( {
+ VIRTUALIZATION_MODE_BINAURAL,
+ VIRTUALIZATION_MODE_TRANSAURAL
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface VirtualizationMode {}
+
+ /** @hide */
+ @IntDef( {
+ VIRTUALIZATION_MODE_AUTO,
+ VIRTUALIZATION_MODE_BINAURAL,
+ VIRTUALIZATION_MODE_TRANSAURAL
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ForceVirtualizationMode {}
+
+ private static int getDeviceForModeQuery(@VirtualizationMode int virtualizationMode)
+ throws IllegalArgumentException {
+ switch (virtualizationMode) {
+ case VIRTUALIZATION_MODE_BINAURAL:
+ return AudioDevice.TYPE_WIRED_HEADPHONES;
+ case VIRTUALIZATION_MODE_TRANSAURAL:
+ return AudioDevice.TYPE_BUILTIN_SPEAKER;
+ default:
+ throw (new IllegalArgumentException(
+ "Virtualizer: illegal virtualization mode " + virtualizationMode));
+ }
+ }
+
+ private static int getDeviceForModeForce(@ForceVirtualizationMode int virtualizationMode)
+ throws IllegalArgumentException {
+ if (virtualizationMode == VIRTUALIZATION_MODE_AUTO) {
+ return AudioDevice.TYPE_UNKNOWN;
+ } else {
+ return getDeviceForModeQuery(virtualizationMode);
+ }
+ }
+
+ private static int deviceToMode(int deviceType) {
+ switch (deviceType) {
+ case AudioDevice.TYPE_WIRED_HEADSET:
+ case AudioDevice.TYPE_WIRED_HEADPHONES:
+ case AudioDevice.TYPE_BLUETOOTH_SCO:
+ case AudioDevice.TYPE_BUILTIN_EARPIECE:
+ return VIRTUALIZATION_MODE_BINAURAL;
+ case AudioDevice.TYPE_BUILTIN_SPEAKER:
+ case AudioDevice.TYPE_LINE_ANALOG:
+ case AudioDevice.TYPE_LINE_DIGITAL:
+ case AudioDevice.TYPE_BLUETOOTH_A2DP:
+ case AudioDevice.TYPE_HDMI:
+ case AudioDevice.TYPE_HDMI_ARC:
+ case AudioDevice.TYPE_USB_DEVICE:
+ case AudioDevice.TYPE_USB_ACCESSORY:
+ case AudioDevice.TYPE_DOCK:
+ case AudioDevice.TYPE_FM:
+ case AudioDevice.TYPE_AUX_LINE:
+ return VIRTUALIZATION_MODE_TRANSAURAL;
+ case AudioDevice.TYPE_UNKNOWN:
+ default:
+ return VIRTUALIZATION_MODE_OFF;
+ }
+ }
+
+ /**
+ * Checks if the combination of a channel mask and virtualization mode is supported by this
+ * virtualizer.
* Some virtualizer implementations may only support binaural processing (i.e. only support
- * headphone output), some may support transaural processing (i.e. for speaker output) for the
+ * headphone output, see {@link #VIRTUALIZATION_MODE_BINAURAL}), some may support transaural
+ * processing (i.e. for speaker output, see {@link #VIRTUALIZATION_MODE_TRANSAURAL}) for the
* built-in speakers. Use this method to query the virtualizer implementation capabilities.
* @param inputChannelMask the channel mask of the content to virtualize.
- * @param deviceType the device type for which virtualization processing is to be performed.
- * Valid values are the device types defined in {@link AudioDevice}.
- * @return true if the combination of channel mask and output device type is supported, false
+ * @param virtualizationMode the mode for which virtualization processing is to be performed,
+ * one of {@link #VIRTUALIZATION_MODE_BINAURAL}, {@link #VIRTUALIZATION_MODE_TRANSAURAL}.
+ * @return true if the combination of channel mask and virtualization mode is supported, false
* otherwise.
* <br>An indication that a certain channel mask is not supported doesn't necessarily mean
* you cannot play content with that channel mask, it more likely implies the content will
@@ -268,22 +371,22 @@
* @throws IllegalArgumentException
* @throws UnsupportedOperationException
*/
- public boolean canVirtualize(int inputChannelMask, int deviceType)
+ public boolean canVirtualize(int inputChannelMask, @VirtualizationMode int virtualizationMode)
throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
- return getAnglesInt(inputChannelMask, deviceType, null);
+ return getAnglesInt(inputChannelMask, getDeviceForModeQuery(virtualizationMode), null);
}
/**
* Queries the virtual speaker angles (azimuth and elevation) for a combination of a channel
- * mask and device type.
- * If the virtualization configuration (mask and device) is supported (see
+ * mask and virtualization mode.
+ * If the virtualization configuration (mask and mode) is supported (see
* {@link #canVirtualize(int, int)}, the array angles will contain upon return the
* definition of each virtual speaker and its azimuth and elevation angles relative to the
* listener.
* <br>Note that in some virtualizer implementations, the angles may be strength-dependent.
* @param inputChannelMask the channel mask of the content to virtualize.
- * @param deviceType the device type for which virtualization processing is to be performed.
- * Valid values are the device types defined in {@link AudioDevice}.
+ * @param virtualizationMode the mode for which virtualization processing is to be performed,
+ * one of {@link #VIRTUALIZATION_MODE_BINAURAL}, {@link #VIRTUALIZATION_MODE_TRANSAURAL}.
* @param angles a non-null array whose length is 3 times the number of channels in the channel
* mask.
* If the method indicates the configuration is supported, the array will contain upon return
@@ -297,37 +400,39 @@
* <li>the element at index <code>3*i+2</code> contains its corresponding elevation angle
* where +90 is directly above the listener, 0 is the horizontal plane, and -90 is
* directly below the listener.</li>
- * @return true if the combination of channel mask and output device type is supported, false
+ * @return true if the combination of channel mask and virtualization mode is supported, false
* otherwise.
* @throws IllegalStateException
* @throws IllegalArgumentException
* @throws UnsupportedOperationException
*/
- public boolean getSpeakerAngles(int inputChannelMask, int deviceType, int[] angles)
+ public boolean getSpeakerAngles(int inputChannelMask,
+ @VirtualizationMode int virtualizationMode, int[] angles)
throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
if (angles == null) {
throw (new IllegalArgumentException(
"Virtualizer: illegal null channel / angle array"));
}
- return getAnglesInt(inputChannelMask, deviceType, angles);
+ return getAnglesInt(inputChannelMask, getDeviceForModeQuery(virtualizationMode), angles);
}
/**
- * Forces the virtualizer effect to use the processing mode used for the given device type.
+ * Forces the virtualizer effect to use the given processing mode.
* The effect must be enabled for the forced mode to be applied.
- * @param deviceType one of the device types defined in {@link AudioDevice}.
- * Use {@link AudioDevice#DEVICE_TYPE_UNKNOWN} to return to the non-forced mode.
- * @return true if the processing mode for the device type is supported, and it is successfully
- * set, or forcing was successfully disabled with {@link AudioDevice#DEVICE_TYPE_UNKNOWN},
- * false otherwise.
+ * @param virtualizationMode one of {@link #VIRTUALIZATION_MODE_BINAURAL},
+ * {@link #VIRTUALIZATION_MODE_TRANSAURAL} to force a particular processing mode, or
+ * {@value #VIRTUALIZATION_MODE_AUTO} to stop forcing a mode.
+ * @return true if the processing mode is supported, and it is successfully set, or
+ * forcing was successfully disabled, false otherwise.
* @throws IllegalStateException
* @throws IllegalArgumentException
* @throws UnsupportedOperationException
*/
- public boolean forceVirtualizationMode(int deviceType)
+ public boolean forceVirtualizationMode(@ForceVirtualizationMode int virtualizationMode)
throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
// convert Java device type to internal representation
+ int deviceType = getDeviceForModeForce(virtualizationMode);
int internalDevice = AudioDevice.convertDeviceTypeToInternalDevice(deviceType);
int status = setParameter(PARAM_FORCE_VIRTUALIZATION_MODE, internalDevice);
@@ -335,8 +440,8 @@
if (status >= 0) {
return true;
} else if (status == AudioEffect.ERROR_BAD_VALUE) {
- // a BAD_VALUE return from setParameter indicates the mode can't be forced to that
- // of this device, don't throw an exception, just return false
+ // a BAD_VALUE return from setParameter indicates the mode can't be forced
+ // don't throw an exception, just return false
return false;
} else {
// something wrong may have happened
@@ -349,31 +454,25 @@
}
/**
- * Return the device type which reflects the virtualization mode being used, if any.
- * @return a device type (as defined in {@link AudioDevice}) which reflects the virtualization
- * mode being used.
- * If virtualization is not active, the device type will be
- * {@link AudioDevice#DEVICE_TYPE_UNKNOWN}. Virtualization may not be active either because
- * the effect is not enabled or because the current output device is not compatible with
- * this virtualization implementation.
- * <p>Note that the return value may differ from a device type successfully set with
- * {@link #forceVirtualizationMode(int)} as the implementation
- * may use a single mode for multiple devices. An example of this is with
- * {@link AudioDevice#DEVICE_TYPE_WIRED_HEADSET} that would typically be handled
- * like {@link AudioDevice#DEVICE_TYPE_WIRED_HEADPHONES} from a virtualization
- * standpoint.
+ * Return the virtualization mode being used, if any.
+ * @return the virtualization mode being used.
+ * If virtualization is not active, the virtualization mode will be
+ * {@link #VIRTUALIZATION_MODE_OFF}. Otherwise the value will be
+ * {@link #VIRTUALIZATION_MODE_BINAURAL} or {@link #VIRTUALIZATION_MODE_TRANSAURAL}.
+ * Virtualization may not be active either because the effect is not enabled or
+ * because the current output device is not compatible with this virtualization
+ * implementation.
* @throws IllegalStateException
- * @throws IllegalArgumentException
* @throws UnsupportedOperationException
*/
public int getVirtualizationMode()
- throws IllegalStateException, IllegalArgumentException, UnsupportedOperationException {
+ throws IllegalStateException, UnsupportedOperationException {
int[] value = new int[1];
int status = getParameter(PARAM_VIRTUALIZATION_MODE, value);
if (status >= 0) {
- return AudioDevice.convertInternalDeviceToDeviceType(value[0]);
+ return deviceToMode(AudioDevice.convertInternalDeviceToDeviceType(value[0]));
} else if (status == AudioEffect.ERROR_BAD_VALUE) {
- return AudioDevice.DEVICE_TYPE_UNKNOWN;
+ return VIRTUALIZATION_MODE_OFF;
} else {
// something wrong may have happened
checkStatus(status);
@@ -381,7 +480,7 @@
// unexpected virtualizer behavior
Log.e(TAG, "unexpected status code " + status
+ " after getParameter(PARAM_VIRTUALIZATION_MODE)");
- return AudioDevice.DEVICE_TYPE_UNKNOWN;
+ return VIRTUALIZATION_MODE_OFF;
}
/**
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index d2deb66..b7a230c 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -709,7 +709,9 @@
}
};
try {
- mService.registerCallback(mManagerCallback, mUserId);
+ if (mService != null) {
+ mService.registerCallback(mManagerCallback, mUserId);
+ }
} catch (RemoteException e) {
Log.e(TAG, "mService.registerCallback failed: " + e);
}
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 4171e6d..213e34c 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -312,7 +312,9 @@
// is newly assigned for every createSession request and compared with
// MySessionCreateCallback.this.
mSessionCallback = new MySessionCallback(inputId, channelUri, params);
- mTvInputManager.createSession(inputId, mSessionCallback, mHandler);
+ if (mTvInputManager != null) {
+ mTvInputManager.createSession(inputId, mSessionCallback, mHandler);
+ }
}
}
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index f1e1099..1cf589d 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -62,6 +62,7 @@
jint cryptoErrorNoKey;
jint cryptoErrorKeyExpired;
jint cryptoErrorResourceBusy;
+ jint cryptoErrorInsufficientOutputProtection;
} gCryptoErrorCodes;
static struct CodecActionCodes {
@@ -756,6 +757,9 @@
case ERROR_DRM_RESOURCE_BUSY:
err = gCryptoErrorCodes.cryptoErrorResourceBusy;
break;
+ case ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
+ err = gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection;
+ break;
default: /* Other negative DRM error codes go out as is. */
break;
}
@@ -1434,6 +1438,11 @@
gCryptoErrorCodes.cryptoErrorResourceBusy =
env->GetStaticIntField(clazz.get(), field);
+ field = env->GetStaticFieldID(clazz.get(), "ERROR_INSUFFICIENT_OUTPUT_PROTECTION", "I");
+ CHECK(field != NULL);
+ gCryptoErrorCodes.cryptoErrorInsufficientOutputProtection =
+ env->GetStaticIntField(clazz.get(), field);
+
clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
CHECK(clazz.get() != NULL);
field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
diff --git a/packages/Keyguard/res/drawable-hdpi/kg_bouncer_bg_white.9.png b/packages/Keyguard/res/drawable-hdpi/kg_bouncer_bg_white.9.png
deleted file mode 100644
index cfd5db3..0000000
--- a/packages/Keyguard/res/drawable-hdpi/kg_bouncer_bg_white.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-mdpi/kg_bouncer_bg_white.9.png b/packages/Keyguard/res/drawable-mdpi/kg_bouncer_bg_white.9.png
deleted file mode 100644
index e3cb6db..0000000
--- a/packages/Keyguard/res/drawable-mdpi/kg_bouncer_bg_white.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/drawable-xhdpi/kg_bouncer_bg_white.9.png b/packages/Keyguard/res/drawable-xhdpi/kg_bouncer_bg_white.9.png
deleted file mode 100644
index b9e30e2..0000000
--- a/packages/Keyguard/res/drawable-xhdpi/kg_bouncer_bg_white.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/Keyguard/res/layout/keyguard_face_unlock_view.xml b/packages/Keyguard/res/layout/keyguard_face_unlock_view.xml
index 8c8ec7a..0c85dab 100644
--- a/packages/Keyguard/res/layout/keyguard_face_unlock_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_face_unlock_view.xml
@@ -36,7 +36,6 @@
<FrameLayout
android:id="@+id/keyguard_bouncer_frame"
- android:background="@drawable/kg_bouncer_bg_white"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
diff --git a/packages/Keyguard/res/layout/keyguard_password_view.xml b/packages/Keyguard/res/layout/keyguard_password_view.xml
index 9e886f2..b7d5d30 100644
--- a/packages/Keyguard/res/layout/keyguard_password_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_password_view.xml
@@ -42,7 +42,6 @@
<!-- Password entry field -->
<FrameLayout
android:id="@+id/keyguard_bouncer_frame"
- android:background="@drawable/kg_bouncer_bg_white"
android:layout_height="wrap_content"
android:layout_width="280dp"
android:layout_gravity="center_horizontal"
diff --git a/packages/Keyguard/res/layout/keyguard_pattern_view.xml b/packages/Keyguard/res/layout/keyguard_pattern_view.xml
index a126465..bd585b5 100644
--- a/packages/Keyguard/res/layout/keyguard_pattern_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_pattern_view.xml
@@ -49,7 +49,6 @@
<FrameLayout
android:id="@+id/keyguard_bouncer_frame"
- android:background="@drawable/kg_bouncer_bg_white"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
diff --git a/packages/Keyguard/res/layout/keyguard_selector_view.xml b/packages/Keyguard/res/layout/keyguard_selector_view.xml
index d3064ed..5330363 100644
--- a/packages/Keyguard/res/layout/keyguard_selector_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_selector_view.xml
@@ -48,8 +48,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
- android:layout_marginRight="16dp"
- android:background="@drawable/kg_bouncer_bg_white"/>
+ android:layout_marginRight="16dp"/>
<include layout="@layout/keyguard_glow_pad_container" />
diff --git a/packages/Keyguard/src/com/android/keyguard/NumPadKey.java b/packages/Keyguard/src/com/android/keyguard/NumPadKey.java
index 2d20b02..d539856 100644
--- a/packages/Keyguard/src/com/android/keyguard/NumPadKey.java
+++ b/packages/Keyguard/src/com/android/keyguard/NumPadKey.java
@@ -152,6 +152,11 @@
mKlondikeText.layout(left, top, left + mKlondikeText.getMeasuredWidth(), bottom);
}
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
// Cause a VIRTUAL_KEY vibration
public void doHapticKeyClick() {
if (mEnableHaptics) {
diff --git a/packages/Keyguard/src/com/android/keyguard/PasswordTextView.java b/packages/Keyguard/src/com/android/keyguard/PasswordTextView.java
index f3ba3a7..6497f46 100644
--- a/packages/Keyguard/src/com/android/keyguard/PasswordTextView.java
+++ b/packages/Keyguard/src/com/android/keyguard/PasswordTextView.java
@@ -145,6 +145,11 @@
}
}
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
private Rect getCharBounds() {
float textHeight = mTextHeightRaw * getResources().getDisplayMetrics().scaledDensity;
mDrawPaint.setTextSize(textHeight);
diff --git a/packages/PrintSpooler/Android.mk b/packages/PrintSpooler/Android.mk
index c4a55d1..27d1b23 100644
--- a/packages/PrintSpooler/Android.mk
+++ b/packages/PrintSpooler/Android.mk
@@ -19,7 +19,9 @@
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SRC_FILES += src/com/android/printspooler/renderer/IPdfRenderer.aidl
+LOCAL_SRC_FILES += \
+ src/com/android/printspooler/renderer/IPdfRenderer.aidl \
+ src/com/android/printspooler/renderer/IPdfEditor.aidl
LOCAL_PACKAGE_NAME := PrintSpooler
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index 9efda2f..adff596 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -54,7 +54,7 @@
</service>
<service
- android:name=".renderer.PdfRendererService"
+ android:name=".renderer.PdfManipulationService"
android:isolatedProcess="true">
</service>
diff --git a/packages/PrintSpooler/res/layout/print_activity.xml b/packages/PrintSpooler/res/layout/print_activity.xml
index 30b96292..6b8aa47 100644
--- a/packages/PrintSpooler/res/layout/print_activity.xml
+++ b/packages/PrintSpooler/res/layout/print_activity.xml
@@ -98,7 +98,7 @@
android:id="@+id/print_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginEnd="16dip"
+ android:layout_marginStart="16dip"
android:elevation="@dimen/preview_controls_elevation"
android:background="@drawable/print_button">
</ImageButton>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
index a581e8a..1d8261b 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
@@ -37,7 +37,7 @@
import android.view.View;
import com.android.internal.annotations.GuardedBy;
import com.android.printspooler.renderer.IPdfRenderer;
-import com.android.printspooler.renderer.PdfRendererService;
+import com.android.printspooler.renderer.PdfManipulationService;
import com.android.printspooler.util.BitmapSerializeUtils;
import dalvik.system.CloseGuard;
import libcore.io.IoUtils;
@@ -490,7 +490,8 @@
new AsyncTask<Void, Void, Integer>() {
@Override
protected void onPreExecute() {
- Intent intent = new Intent(mContext, PdfRendererService.class);
+ Intent intent = new Intent(PdfManipulationService.ACTION_GET_RENDERER);
+ intent.setClass(mContext, PdfManipulationService.class);
mContext.bindService(intent, AsyncRenderer.this, Context.BIND_AUTO_CREATE);
}
@@ -555,7 +556,7 @@
callback.run();
}
}
- }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, (Void[]) null);
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
}
public void destroy() {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl b/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl
new file mode 100644
index 0000000..b450ccb
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfEditor.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2014 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.printspooler.renderer;
+
+import android.os.ParcelFileDescriptor;
+import android.print.PageRange;
+
+/**
+ * Interface for communication with a remote pdf editor.
+ */
+interface IPdfEditor {
+ int openDocument(in ParcelFileDescriptor source);
+ void removePages(in PageRange[] pages);
+ void write(in ParcelFileDescriptor destination);
+ void closeDocument();
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfRenderer.aidl b/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfRenderer.aidl
index 1fba2b1..8e595d7 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfRenderer.aidl
+++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/IPdfRenderer.aidl
@@ -29,5 +29,4 @@
oneway void renderPage(int pageIndex, int bitmapWidth, int bitmapHeight,
in PrintAttributes attributes, in ParcelFileDescriptor destination);
oneway void closeDocument();
- oneway void writePages(in PageRange[] pages);
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfRendererService.java b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
similarity index 62%
rename from packages/PrintSpooler/src/com/android/printspooler/renderer/PdfRendererService.java
rename to packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
index 4d02c01..62716b2 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfRendererService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/renderer/PdfManipulationService.java
@@ -23,6 +23,7 @@
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Rect;
+import android.graphics.pdf.PdfEditor;
import android.graphics.pdf.PdfRenderer;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
@@ -32,15 +33,21 @@
import android.print.PrintAttributes.Margins;
import android.util.Log;
import android.view.View;
+import com.android.printspooler.util.PageRangeUtils;
import libcore.io.IoUtils;
import com.android.printspooler.util.BitmapSerializeUtils;
import java.io.IOException;
/**
- * Service for rendering PDF documents in an isolated process.
+ * Service for manipulation of PDF documents in an isolated process.
*/
-public final class PdfRendererService extends Service {
- private static final String LOG_TAG = "PdfRendererService";
+public final class PdfManipulationService extends Service {
+ public static final String ACTION_GET_RENDERER =
+ "com.android.printspooler.renderer.ACTION_GET_RENDERER";
+ public static final String ACTION_GET_EDITOR =
+ "com.android.printspooler.renderer.ACTION_GET_EDITOR";
+
+ private static final String LOG_TAG = "PdfManipulationService";
private static final boolean DEBUG = false;
private static final int MILS_PER_INCH = 1000;
@@ -48,7 +55,18 @@
@Override
public IBinder onBind(Intent intent) {
- return new PdfRendererImpl();
+ String action = intent.getAction();
+ switch (action) {
+ case ACTION_GET_RENDERER: {
+ return new PdfRendererImpl();
+ }
+ case ACTION_GET_EDITOR: {
+ return new PdfEditorImpl();
+ }
+ default: {
+ throw new IllegalArgumentException("Invalid intent action:" + action);
+ }
+ }
}
private final class PdfRendererImpl extends IPdfRenderer.Stub {
@@ -60,15 +78,17 @@
@Override
public int openDocument(ParcelFileDescriptor source) throws RemoteException {
synchronized (mLock) {
- throwIfOpened();
- if (DEBUG) {
- Log.i(LOG_TAG, "openDocument()");
- }
try {
+ throwIfOpened();
+ if (DEBUG) {
+ Log.i(LOG_TAG, "openDocument()");
+ }
mRenderer = new PdfRenderer(source);
return mRenderer.getPageCount();
- } catch (IOException ioe) {
- throw new RemoteException("Cannot open file");
+ } catch (IOException|IllegalStateException e) {
+ IoUtils.closeQuietly(source);
+ Log.e(LOG_TAG, "Cannot open file", e);
+ throw new RemoteException(e.toString());
}
}
}
@@ -108,7 +128,7 @@
}
matrix.postScale(displayScale, displayScale);
- Configuration configuration = PdfRendererService.this.getResources()
+ Configuration configuration = PdfManipulationService.this.getResources()
.getConfiguration();
if (configuration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
matrix.postTranslate(bitmapWidth - srcWidthPts * displayScale, 0);
@@ -147,24 +167,13 @@
synchronized (mLock) {
throwIfNotOpened();
if (DEBUG) {
- Log.i(LOG_TAG, "openDocument()");
+ Log.i(LOG_TAG, "closeDocument()");
}
mRenderer.close();
mRenderer = null;
}
}
- @Override
- public void writePages(PageRange[] pages) {
- synchronized (mLock) {
- throwIfNotOpened();
- if (DEBUG) {
- Log.i(LOG_TAG, "writePages()");
- }
- // TODO: Implement dropping undesired pages.
- }
- }
-
private Bitmap getBitmapForSize(int width, int height) {
if (mBitmap != null) {
if (mBitmap.getWidth() == width && mBitmap.getHeight() == height) {
@@ -191,6 +200,91 @@
}
}
+ private final class PdfEditorImpl extends IPdfEditor.Stub {
+ private final Object mLock = new Object();
+
+ private PdfEditor mEditor;
+
+ @Override
+ public int openDocument(ParcelFileDescriptor source) throws RemoteException {
+ synchronized (mLock) {
+ try {
+ throwIfOpened();
+ if (DEBUG) {
+ Log.i(LOG_TAG, "openDocument()");
+ }
+ mEditor = new PdfEditor(source);
+ return mEditor.getPageCount();
+ } catch (IOException|IllegalStateException e) {
+ IoUtils.closeQuietly(source);
+ Log.e(LOG_TAG, "Cannot open file", e);
+ throw new RemoteException(e.toString());
+ }
+ }
+ }
+
+ @Override
+ public void removePages(PageRange[] ranges) {
+ synchronized (mLock) {
+ throwIfNotOpened();
+ if (DEBUG) {
+ Log.i(LOG_TAG, "removePages()");
+ }
+
+ ranges = PageRangeUtils.normalize(ranges);
+
+ final int rangeCount = ranges.length;
+ for (int i = rangeCount - 1; i >= 0; i--) {
+ PageRange range = ranges[i];
+ for (int j = range.getEnd(); j >= range.getStart(); j--) {
+ mEditor.removePage(j);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void write(ParcelFileDescriptor destination) throws RemoteException {
+ synchronized (mLock) {
+ try {
+ throwIfNotOpened();
+ if (DEBUG) {
+ Log.i(LOG_TAG, "write()");
+ }
+ mEditor.write(destination);
+ } catch (IOException | IllegalStateException e) {
+ IoUtils.closeQuietly(destination);
+ Log.e(LOG_TAG, "Error writing PDF to file.", e);
+ throw new RemoteException(e.toString());
+ }
+ }
+ }
+
+ @Override
+ public void closeDocument() {
+ synchronized (mLock) {
+ throwIfNotOpened();
+ if (DEBUG) {
+ Log.i(LOG_TAG, "closeDocument()");
+ }
+ mEditor.close();
+ mEditor = null;
+ }
+ }
+
+ private void throwIfOpened() {
+ if (mEditor != null) {
+ throw new IllegalStateException("Already opened");
+ }
+ }
+
+ private void throwIfNotOpened() {
+ if (mEditor == null) {
+ throw new IllegalStateException("Not opened");
+ }
+ }
+ }
+
private static int pointsFromMils(int mils) {
return (int) (((float) mils / MILS_PER_INCH) * POINTS_IN_INCH);
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
index ce0b9b6..b6c36c7 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
@@ -442,7 +442,8 @@
* mPreviewPageMargin);
final int verticalPadding;
- if (mPageContentHeight + mFooterHeight + mPreviewListPadding > availableHeight) {
+ if (mPageContentHeight + mFooterHeight + mPreviewListPadding
+ + 2 * mPreviewPageMargin > availableHeight) {
verticalPadding = Math.max(0,
(availableHeight - mPageContentHeight - mFooterHeight) / 2
- mPreviewPageMargin);
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 535081f..c517f2d 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -23,6 +23,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.ServiceConnection;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
@@ -30,9 +31,12 @@
import android.database.DataSetObserver;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
import android.print.IPrintDocumentAdapter;
import android.print.PageRange;
import android.print.PrintAttributes;
@@ -74,6 +78,8 @@
import com.android.printspooler.model.PrintSpoolerService;
import com.android.printspooler.model.RemotePrintDocument;
import com.android.printspooler.model.RemotePrintDocument.RemotePrintDocumentInfo;
+import com.android.printspooler.renderer.IPdfEditor;
+import com.android.printspooler.renderer.PdfManipulationService;
import com.android.printspooler.util.MediaSizeUtils;
import com.android.printspooler.util.MediaSizeUtils.MediaSizeComparator;
import com.android.printspooler.util.PageRangeUtils;
@@ -81,8 +87,15 @@
import com.android.printspooler.widget.PrintContentView;
import com.android.printspooler.widget.PrintContentView.OptionsStateChangeListener;
import com.android.printspooler.widget.PrintContentView.OptionsStateController;
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -186,6 +199,7 @@
private ImageView mPrintButton;
private ProgressMessageController mProgressMessageController;
+ private MutexFileProvider mFileProvider;
private MediaSizeComparator mMediaSizeComparator;
@@ -257,9 +271,8 @@
setTitle(R.string.print_dialog);
setContentView(R.layout.print_activity);
- final MutexFileProvider fileProvider;
try {
- fileProvider = new MutexFileProvider(
+ mFileProvider = new MutexFileProvider(
PrintSpoolerService.generateFileForPrintJob(
PrintActivity.this, mPrintJob.getId()));
} catch (IOException ioe) {
@@ -268,12 +281,13 @@
}
mPrintPreviewController = new PrintPreviewController(PrintActivity.this,
- fileProvider);
+ mFileProvider);
mPrintedDocument = new RemotePrintDocument(PrintActivity.this,
IPrintDocumentAdapter.Stub.asInterface(documentAdapter),
- fileProvider, new RemotePrintDocument.DocumentObserver() {
+ mFileProvider, new RemotePrintDocument.DocumentObserver() {
@Override
public void onDestroy() {
+ setState(STATE_PRINT_CANCELED);
finish();
}
}, PrintActivity.this);
@@ -369,7 +383,7 @@
@Override
public void onRequestContentUpdate() {
if (canUpdateDocument()) {
- updateDocument(true, false);
+ updateDocument(false);
}
}
@@ -386,7 +400,7 @@
@Override
public void onActionPerformed() {
if (mState == STATE_UPDATE_FAILED
- && canUpdateDocument() && updateDocument(true, true)) {
+ && canUpdateDocument() && updateDocument(true)) {
ensurePreviewUiShown();
setState(STATE_CONFIGURING);
updateOptionsUi();
@@ -557,14 +571,13 @@
if (resultCode == RESULT_OK && data != null) {
setState(STATE_PRINT_COMPLETED);
updateOptionsUi();
- Uri uri = data.getData();
- mPrintedDocument.writeContent(getContentResolver(), uri);
+ final Uri uri = data.getData();
// Calling finish here does not invoke lifecycle callbacks but we
// update the print job in onPause if finishing, hence post a message.
mDestinationSpinner.post(new Runnable() {
@Override
public void run() {
- finish();
+ shredPagesAndFinish(uri);
}
});
} else if (resultCode == RESULT_CANCELED) {
@@ -708,7 +721,7 @@
// Update the content if needed.
if (canUpdateDocument()) {
- updateDocument(true, false);
+ updateDocument(false);
}
}
@@ -840,7 +853,7 @@
if (mCurrentPrinter == mDestinationSpinnerAdapter.getPdfPrinter()) {
startCreateDocumentActivity();
} else {
- finish();
+ shredPagesAndFinish(null);
}
}
@@ -893,7 +906,7 @@
attributes.setMinMargins(defaults.getMinMargins());
}
- private boolean updateDocument(boolean preview, boolean clearLastError) {
+ private boolean updateDocument(boolean clearLastError) {
if (!clearLastError && mPrintedDocument.hasUpdateError()) {
return false;
}
@@ -902,6 +915,7 @@
mPrintedDocument.clearUpdateError();
}
+ final boolean preview = mState != STATE_PRINT_CONFIRMED;
final PageRange[] pages;
if (preview) {
pages = mPrintPreviewController.getRequestedPages();
@@ -959,7 +973,7 @@
mPrintPreviewController.closeOptions();
if (canUpdateDocument()) {
- updateDocument(false, false);
+ updateDocument(false);
}
if (!mPrintedDocument.isUpdating()) {
@@ -1433,7 +1447,7 @@
if (mCurrentPrinter.equals(printer)) {
setState(STATE_CONFIGURING);
if (canUpdateDocument()) {
- updateDocument(true, false);
+ updateDocument(false);
}
ensurePreviewUiShown();
updateOptionsUi();
@@ -1492,6 +1506,18 @@
return true;
}
+ private void shredPagesAndFinish(final Uri writeToUri) {
+ new PageShredder(this, mPrintJob, mFileProvider, new Runnable() {
+ @Override
+ public void run() {
+ if (writeToUri != null) {
+ mPrintedDocument.writeContent(getContentResolver(), writeToUri);
+ }
+ finish();
+ }
+ }).shred();
+ }
+
private final class SpinnerItem<T> {
final T value;
final CharSequence label;
@@ -1942,7 +1968,7 @@
|| (becameActive && hasCapab) || (isActive && gotCapab));
if (updateNeeded && canUpdateDocument()) {
- updateDocument(true, false);
+ updateDocument(false);
}
updateOptionsUi();
@@ -2033,7 +2059,7 @@
}
if (canUpdateDocument()) {
- updateDocument(true, false);
+ updateDocument(false);
}
updateOptionsUi();
@@ -2158,7 +2184,7 @@
updateOptionsUi();
if (hadErrors && canUpdateDocument()) {
- updateDocument(true, false);
+ updateDocument(false);
}
}
}
@@ -2198,4 +2224,176 @@
updateOptionsUi();
}
}
+
+ private static final class PageShredder implements ServiceConnection {
+ private static final String TEMP_FILE_PREFIX = "print_job";
+ private static final String TEMP_FILE_EXTENSION = ".pdf";
+
+ private final Context mContext;
+
+ private final MutexFileProvider mFileProvider;
+
+ private final PrintJobInfo mPrintJob;
+
+ private final PageRange[] mPagesToShred;
+
+ private final Runnable mCallback;
+
+ public PageShredder(Context context, PrintJobInfo printJob,
+ MutexFileProvider fileProvider, Runnable callback) {
+ mContext = context;
+ mPrintJob = printJob;
+ mFileProvider = fileProvider;
+ mCallback = callback;
+ mPagesToShred = computePagesToShred(mPrintJob);
+ }
+
+ public void shred() {
+ // If we have only the pages we want, done.
+ if (mPagesToShred.length <= 0) {
+ mCallback.run();
+ return;
+ }
+
+ // Bind to the manipulation service and the work
+ // will be performed upon connection to the service.
+ Intent intent = new Intent(PdfManipulationService.ACTION_GET_EDITOR);
+ intent.setClass(mContext, PdfManipulationService.class);
+ mContext.bindService(intent, this, Context.BIND_AUTO_CREATE);
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ final IPdfEditor editor = IPdfEditor.Stub.asInterface(service);
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ try {
+ // It's OK to access the data members as they are
+ // final and this code is the last one to touch
+ // them as shredding is the very last step, so the
+ // UI is not interactive at this point.
+ shredPages(editor);
+ updatePrintJob();
+ } finally {
+ mContext.unbindService(PageShredder.this);
+ mCallback.run();
+ }
+ return null;
+ }
+ }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ /* do nothing */
+ }
+
+ private void shredPages(IPdfEditor editor) {
+ File tempFile = null;
+ ParcelFileDescriptor src = null;
+ ParcelFileDescriptor dst = null;
+ InputStream in = null;
+ OutputStream out = null;
+ try {
+ File jobFile = mFileProvider.acquireFile(null);
+ src = ParcelFileDescriptor.open(jobFile, ParcelFileDescriptor.MODE_READ_WRITE);
+
+ // Open the document.
+ editor.openDocument(src);
+
+ // We passed the fd over IPC, close this one.
+ src.close();
+
+ // Drop the pages.
+ editor.removePages(mPagesToShred);
+
+ // Write the modified PDF to a temp file.
+ tempFile = File.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_EXTENSION,
+ mContext.getCacheDir());
+ dst = ParcelFileDescriptor.open(tempFile, ParcelFileDescriptor.MODE_READ_WRITE);
+ editor.write(dst);
+ dst.close();
+
+ // Close the document.
+ editor.closeDocument();
+
+ // Copy the temp file over the print job file.
+ jobFile.delete();
+ in = new FileInputStream(tempFile);
+ out = new FileOutputStream(jobFile);
+ Streams.copy(in, out);
+ } catch (IOException|RemoteException e) {
+ Log.e(LOG_TAG, "Error dropping pages", e);
+ } finally {
+ IoUtils.closeQuietly(src);
+ IoUtils.closeQuietly(dst);
+ IoUtils.closeQuietly(in);
+ IoUtils.closeQuietly(out);
+ if (tempFile != null) {
+ tempFile.delete();
+ }
+ }
+ }
+
+ private void updatePrintJob() {
+ // Update the print job pages.
+ final int newPageCount = PageRangeUtils.getNormalizedPageCount(
+ mPrintJob.getPages(), 0);
+ mPrintJob.setPages(new PageRange[]{PageRange.ALL_PAGES});
+
+ // Update the print job document info.
+ PrintDocumentInfo oldDocInfo = mPrintJob.getDocumentInfo();
+ PrintDocumentInfo newDocInfo = new PrintDocumentInfo
+ .Builder(oldDocInfo.getName())
+ .setContentType(oldDocInfo.getContentType())
+ .setPageCount(newPageCount)
+ .build();
+ mPrintJob.setDocumentInfo(newDocInfo);
+ }
+
+ private static PageRange[] computePagesToShred(PrintJobInfo printJob) {
+ List<PageRange> rangesToShred = new ArrayList<>();
+ PageRange previousRange = null;
+
+ final int pageCount = printJob.getDocumentInfo().getPageCount();
+
+ PageRange[] printedPages = printJob.getPages();
+ final int rangeCount = printedPages.length;
+ for (int i = 0; i < rangeCount; i++) {
+ PageRange range = PageRangeUtils.asAbsoluteRange(printedPages[i], pageCount);
+
+ if (previousRange == null) {
+ final int startPageIdx = 0;
+ final int endPageIdx = range.getStart() - 1;
+ if (startPageIdx <= endPageIdx) {
+ PageRange removedRange = new PageRange(startPageIdx, endPageIdx);
+ rangesToShred.add(removedRange);
+ }
+ } else {
+ final int startPageIdx = previousRange.getEnd() + 1;
+ final int endPageIdx = range.getStart() - 1;
+ if (startPageIdx <= endPageIdx) {
+ PageRange removedRange = new PageRange(startPageIdx, endPageIdx);
+ rangesToShred.add(removedRange);
+ }
+ }
+
+ if (i == rangeCount - 1) {
+ final int startPageIdx = range.getEnd() + 1;
+ final int endPageIdx = printJob.getDocumentInfo().getPageCount() - 1;
+ if (startPageIdx <= endPageIdx) {
+ PageRange removedRange = new PageRange(startPageIdx, endPageIdx);
+ rangesToShred.add(removedRange);
+ }
+ }
+
+ previousRange = range;
+ }
+
+ PageRange[] result = new PageRange[rangesToShred.size()];
+ rangesToShred.toArray(result);
+ return result;
+ }
+ }
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
index a25e05e..5d858ca 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java
@@ -185,8 +185,10 @@
public void run() {
// At this point the other end will write to the file, hence
// we have to close it and reopen after the write completes.
- Message operation = mHandler.obtainMessage(MyHandler.MSG_CLOSE);
- mHandler.enqueueOperation(operation);
+ if (mPageAdapter.isOpened()) {
+ Message operation = mHandler.obtainMessage(MyHandler.MSG_CLOSE);
+ mHandler.enqueueOperation(operation);
+ }
}
});
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
index c84b06a..970e3c0 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintContentView.java
@@ -283,8 +283,13 @@
mDynamicContent.layout(left, dynContentTop, right, dynContentBottom);
MarginLayoutParams params = (MarginLayoutParams) mPrintButton.getLayoutParams();
- final int rightMargin = params.rightMargin;
- final int printButtonLeft = right - mPrintButton.getMeasuredWidth() - rightMargin;
+
+ final int printButtonLeft;
+ if (getLayoutDirection() == View.LAYOUT_DIRECTION_LTR) {
+ printButtonLeft = right - mPrintButton.getMeasuredWidth() - params.getMarginStart();
+ } else {
+ printButtonLeft = left + params.getMarginStart();
+ }
final int printButtonTop = dynContentBottom - mPrintButton.getMeasuredHeight() / 2;
final int printButtonRight = printButtonLeft + mPrintButton.getMeasuredWidth();
final int printButtonBottom = printButtonTop + mPrintButton.getMeasuredHeight();
diff --git a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintOptionsLayout.java b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintOptionsLayout.java
index 71f4aa7..7a80a8b 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/widget/PrintOptionsLayout.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/widget/PrintOptionsLayout.java
@@ -89,7 +89,7 @@
columnWidth - childParams.getMarginStart() - childParams.getMarginEnd(),
MeasureSpec.EXACTLY);
} else {
- childWidthMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
+ childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
getPaddingStart() + getPaddingEnd() + width, childParams.width);
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 17593fe..6d08970 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -70,7 +70,7 @@
// database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
// is properly propagated through your change. Not doing so will result in a loss of user
// settings.
- private static final int DATABASE_VERSION = 110;
+ private static final int DATABASE_VERSION = 111;
private Context mContext;
private int mUserHandle;
@@ -1770,6 +1770,24 @@
upgradeVersion = 110;
}
+ if (upgradeVersion < 111) {
+ // reset ringer mode, so it doesn't force zen mode to follow
+ if (mUserHandle == UserHandle.USER_OWNER) {
+ db.beginTransaction();
+ SQLiteStatement stmt = null;
+ try {
+ stmt = db.compileStatement("INSERT OR REPLACE INTO global(name,value)"
+ + " VALUES(?,?);");
+ loadSetting(stmt, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ if (stmt != null) stmt.close();
+ }
+ }
+ upgradeVersion = 111;
+ }
+
// *** Remember to update DATABASE_VERSION above!
if (upgradeVersion != currentVersion) {
diff --git a/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_bounce.xml b/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_bounce.xml
new file mode 100644
index 0000000..a571cbc
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_bounce.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.6"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@android:interpolator/accelerate_cubic"
+ android:duration="133"/>
+
+ <translate android:fromYDelta="0" android:toYDelta="10%"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@android:interpolator/accelerate_cubic"
+ android:duration="350"/>
+
+ <scale android:fromXScale="1.0" android:toXScale="0.9"
+ android:fromYScale="1.0" android:toYScale="0.9"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:pivotX="50%p" android:pivotY="50%p"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="350" />
+
+ <alpha android:fromAlpha="1.0" android:toAlpha="1.6666666666"
+ android:fillEnabled="true" android:fillBefore="false" android:fillAfter="true"
+ android:interpolator="@android:interpolator/decelerate_cubic"
+ android:startOffset="350"
+ android:duration="133"/>
+
+ <translate android:fromYDelta="0%" android:toYDelta="-8.8888888888%"
+ android:fillEnabled="true" android:fillBefore="false" android:fillAfter="true"
+ android:interpolator="@android:interpolator/decelerate_cubic"
+ android:startOffset="350"
+ android:duration="350"/>
+
+ <scale android:fromXScale="1.0" android:toXScale="1.1111111111"
+ android:fromYScale="1.0" android:toYScale="1.1111111111"
+ android:fillEnabled="true" android:fillBefore="false" android:fillAfter="true"
+ android:pivotX="50%p" android:pivotY="50%p"
+ android:interpolator="@android:interpolator/decelerate_cubic"
+ android:startOffset="350"
+ android:duration="350" />
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_source.xml b/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_source.xml
new file mode 100644
index 0000000..f0fd684
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_source.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+
+ <alpha android:fromAlpha="1.0" android:toAlpha="0.6"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@android:interpolator/accelerate_cubic"
+ android:duration="150"/>
+
+ <scale android:fromXScale="1.0" android:toXScale="0.9"
+ android:fromYScale="1.0" android:toYScale="0.9"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:pivotX="50%p" android:pivotY="50%p"
+ android:interpolator="@android:interpolator/fast_out_slow_in"
+ android:duration="300" />
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_target.xml b/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_target.xml
new file mode 100644
index 0000000..170ac82
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_launch_next_affiliated_task_target.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
+
+ <translate android:fromYDelta="110%" android:toYDelta="0%"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@android:interpolator/decelerate_quint"
+ android:startOffset="50"
+ android:duration="250" />
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_bounce.xml b/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_bounce.xml
new file mode 100644
index 0000000..46045ac
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_bounce.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
+
+ <translate android:fromYDelta="0%" android:toYDelta="10%"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@android:interpolator/decelerate_quint"
+ android:duration="300" />
+
+ <translate android:fromYDelta="10%" android:toYDelta="0%"
+ android:fillEnabled="true" android:fillBefore="false" android:fillAfter="true"
+ android:interpolator="@android:interpolator/accelerate_quint"
+ android:startOffset="300"
+ android:duration="300" />
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_source.xml b/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_source.xml
new file mode 100644
index 0000000..ad5341b
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_source.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="top">
+
+ <translate android:fromYDelta="0%" android:toYDelta="110%"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@android:interpolator/accelerate_quint"
+ android:duration="300" />
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_target.xml b/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_target.xml
new file mode 100644
index 0000000..7687f02
--- /dev/null
+++ b/packages/SystemUI/res/anim/recents_launch_prev_affiliated_task_target.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2014, 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="#ff000000" android:shareInterpolator="false" android:zAdjustment="normal">
+
+ <alpha android:fromAlpha="0.6" android:toAlpha="1.0"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@android:interpolator/decelerate_cubic"
+ android:startOffset="75"
+ android:duration="150"/>
+
+ <scale android:fromXScale="0.9" android:toXScale="1.0"
+ android:fromYScale="0.9" android:toYScale="1.0"
+ android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
+ android:interpolator="@android:interpolator/linear_out_slow_in"
+ android:pivotX="50%p" android:pivotY="50%p"
+ android:startOffset="75"
+ android:duration="225" />
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/recents_button_bg.xml b/packages/SystemUI/res/drawable/recents_button_bg.xml
index a4cb088..7456365 100644
--- a/packages/SystemUI/res/drawable/recents_button_bg.xml
+++ b/packages/SystemUI/res/drawable/recents_button_bg.xml
@@ -15,4 +15,5 @@
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="?android:attr/colorControlHighlight" />
\ No newline at end of file
+ android:color="#40ffffff">
+</ripple>
diff --git a/packages/SystemUI/res/layout/notification_public_default.xml b/packages/SystemUI/res/layout/notification_public_default.xml
new file mode 100644
index 0000000..acfc4bb
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_public_default.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2014 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
+ -->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:internal="http://schemas.android.com/apk/prv/res/android"
+ android:id="@+id/status_bar_latest_event_content"
+ android:layout_width="match_parent"
+ android:layout_height="64dp"
+ internal:layout_minHeight="64dp"
+ internal:layout_maxHeight="64dp"
+ >
+ <ImageView android:id="@+id/icon"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:layout_marginTop="12dp"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="12dp"
+ android:scaleType="centerInside"
+ />
+ <DateTimeView android:id="@+id/time"
+ android:textAppearance="@android:style/TextAppearance.Material.Notification.Time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="8dp"
+ android:layout_alignParentEnd="true"
+ android:layout_alignBaseline="@id/title"
+ android:singleLine="true"
+ android:gravity="center"
+ android:paddingStart="8dp"
+ android:visibility="gone"
+ />
+ <TextView android:id="@+id/title"
+ android:textAppearance="@android:style/TextAppearance.Material.Notification.Title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_toEndOf="@id/icon"
+ android:layout_toStartOf="@id/time"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ />
+ <ImageView android:id="@+id/profile_badge_line3"
+ android:layout_width="@*android:dimen/notification_badge_size"
+ android:layout_height="@*android:dimen/notification_badge_size"
+ android:layout_below="@id/title"
+ android:layout_marginStart="4dp"
+ android:layout_marginEnd="8dp"
+ android:layout_alignParentEnd="true"
+ android:scaleType="fitCenter"
+ android:visibility="gone"
+ />
+ <TextView android:id="@+id/text"
+ android:textAppearance="@android:style/TextAppearance.Material.Notification"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignStart="@id/title"
+ android:layout_below="@id/title"
+ android:layout_toStartOf="@id/profile_badge_line3"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ />
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
index 5cdf819..2eb99ba 100644
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -40,7 +40,6 @@
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:minWidth="132dp"
- android:text="@string/quick_settings_more_settings"
android:textAppearance="@style/TextAppearance.QS.DetailButton"
android:focusable="true" />
@@ -50,9 +49,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="88dp"
- android:text="@string/quick_settings_done"
android:textAppearance="@style/TextAppearance.QS.DetailButton"
android:focusable="true"/>
</LinearLayout>
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 6b829e5..e9d86d6 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -52,9 +52,10 @@
android:paddingStart="8dp"
/>
- <include
- layout="@layout/notification_guts"
- android:id="@+id/notification_guts"
+ <ViewStub
+ android:layout="@layout/notification_guts"
+ android:id="@+id/notification_guts_stub"
+ android:inflatedId="@+id/notification_guts"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 5aafb66..83477c0 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -33,6 +33,8 @@
<!-- Set to true to enable the user switcher on the keyguard. -->
<bool name="config_keyguardUserSwitcher">true</bool>
- <!-- Transposes the recents layout in landscape. -->
- <bool name="recents_transpose_layout_with_orientation">false</bool>
+ <!-- Transposes the search bar layout in landscape. -->
+ <bool name="recents_has_transposed_search_bar">true</bool>
+ <!-- Transposes the nav bar in landscape (only used for purposes of layout). -->
+ <bool name="recents_has_transposed_nav_bar">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml
index d8bb8d7d..fbeadcd 100644
--- a/packages/SystemUI/res/values-sw720dp/config.xml
+++ b/packages/SystemUI/res/values-sw720dp/config.xml
@@ -39,5 +39,10 @@
<!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
card. -->
<integer name="keyguard_max_notification_count">5</integer>
+
+ <!-- Transposes the search bar layout in landscape. -->
+ <bool name="recents_has_transposed_search_bar">false</bool>
+ <!-- Transposes the nav bar in landscape (only used for purposes of layout). -->
+ <bool name="recents_has_transposed_nav_bar">false</bool>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index c0e2b10..5a1c318 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -155,8 +155,10 @@
<integer name="recents_max_task_stack_view_dim">96</integer>
<!-- The delay to enforce between each alt-tab key press. -->
<integer name="recents_alt_tab_key_delay">200</integer>
- <!-- Transposes the recents layout in landscape. -->
- <bool name="recents_transpose_layout_with_orientation">true</bool>
+ <!-- Transposes the search bar layout in landscape. -->
+ <bool name="recents_has_transposed_search_bar">true</bool>
+ <!-- Transposes the nav bar in landscape (only used for purposes of layout). -->
+ <bool name="recents_has_transposed_nav_bar">true</bool>
<!-- Whether to enable KeyguardService or not -->
<bool name="config_enableKeyguardService">true</bool>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 147efaf..0445fe8 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -736,9 +736,6 @@
<!-- Shows when people have clicked at the right edge of the screen to explain how to open the phone. In right-to-left languages, this is the opposite direction. [CHAR LIMIT=60] -->
<string name="camera_hint">Swipe left for camera</string>
- <!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] -->
- <string name="zen_mode_forever">Indefinitely</string>
-
<!-- Interruption level: None. [CHAR LIMIT=20] -->
<string name="interruption_level_none">None</string>
@@ -805,18 +802,6 @@
<string name="user_add_user_message_short" msgid="1511354412249044381">When you add a new user, that person needs to set up their space.\n\nAny user can update apps for all other users. </string>
- <!-- Zen mode condition: time duration in minutes. [CHAR LIMIT=NONE] -->
- <plurals name="zen_mode_duration_minutes">
- <item quantity="one">For one minute</item>
- <item quantity="other">For %d minutes</item>
- </plurals>
-
- <!-- Zen mode condition: time duration in hours. [CHAR LIMIT=NONE] -->
- <plurals name="zen_mode_duration_hours">
- <item quantity="one">For one hour</item>
- <item quantity="other">For %d hours</item>
- </plurals>
-
<!-- Battery saver notification title. [CHAR LIMIT=60]-->
<string name="battery_saver_notification_title">Battery saver is on</string>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDualTileLabel.java b/packages/SystemUI/src/com/android/systemui/qs/QSDualTileLabel.java
index 377fcc0..a9fdc86 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDualTileLabel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDualTileLabel.java
@@ -23,7 +23,6 @@
import android.text.TextUtils.TruncateAt;
import android.view.Gravity;
import android.view.View;
-import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -41,7 +40,7 @@
* truncate.
* Second line: ellipsis if necessary
*/
-public class QSDualTileLabel extends FrameLayout {
+public class QSDualTileLabel extends LinearLayout {
private final Context mContext;
private final TextView mFirstLine;
@@ -54,12 +53,13 @@
public QSDualTileLabel(Context context) {
super(context);
mContext = context;
+ setOrientation(LinearLayout.VERTICAL);
mHorizontalPaddingPx = mContext.getResources()
.getDimensionPixelSize(R.dimen.qs_dual_tile_padding_horizontal);
mFirstLine = initTextView();
- mFirstLine.setPadding(mHorizontalPaddingPx, 0, 0, 0);
+ mFirstLine.setPadding(mHorizontalPaddingPx, 0, mHorizontalPaddingPx, 0);
final LinearLayout firstLineLayout = new LinearLayout(mContext);
firstLineLayout.setPadding(0, 0, 0, 0);
firstLineLayout.setOrientation(LinearLayout.HORIZONTAL);
@@ -70,13 +70,13 @@
mFirstLineCaret.setScaleType(ImageView.ScaleType.MATRIX);
mFirstLineCaret.setClickable(false);
firstLineLayout.addView(mFirstLineCaret);
- addView(firstLineLayout, newFrameLayoutParams());
+ addView(firstLineLayout, newLinearLayoutParams());
mSecondLine = initTextView();
mSecondLine.setPadding(mHorizontalPaddingPx, 0, mHorizontalPaddingPx, 0);
mSecondLine.setEllipsize(TruncateAt.END);
mSecondLine.setVisibility(GONE);
- addView(mSecondLine, newFrameLayoutParams());
+ addView(mSecondLine, newLinearLayoutParams());
addOnLayoutChangeListener(new OnLayoutChangeListener() {
@Override
@@ -89,7 +89,7 @@
});
}
- private static LayoutParams newFrameLayoutParams() {
+ private static LayoutParams newLinearLayoutParams() {
final LayoutParams lp =
new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER_HORIZONTAL;
@@ -104,6 +104,7 @@
lp.topMargin = h * 4 / 5;
mSecondLine.setLayoutParams(lp);
mFirstLine.setMinHeight(h);
+ mFirstLine.setPadding(mHorizontalPaddingPx, 0, 0, 0);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 6bfe0a4..2fafb2c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -89,6 +89,7 @@
mDetailContent = (ViewGroup) mDetail.findViewById(android.R.id.content);
mDetailSettingsButton = (TextView) mDetail.findViewById(android.R.id.button2);
mDetailDoneButton = (TextView) mDetail.findViewById(android.R.id.button1);
+ updateDetailText();
mDetail.setVisibility(GONE);
mDetail.setClickable(true);
mBrightnessView = LayoutInflater.from(context).inflate(
@@ -112,6 +113,11 @@
});
}
+ private void updateDetailText() {
+ mDetailDoneButton.setText(R.string.quick_settings_done);
+ mDetailSettingsButton.setText(R.string.quick_settings_more_settings);
+ }
+
public void setBrightnessMirror(BrightnessMirrorController c) {
super.onFinishInflate();
ToggleSlider brightnessSlider = (ToggleSlider) findViewById(R.id.brightness_slider);
@@ -150,6 +156,7 @@
if (mListening) {
refreshAllTiles();
}
+ updateDetailText();
}
@Override
@@ -525,6 +532,12 @@
};
private final AnimatorListenerAdapter mHideGridContentWhenDone = new AnimatorListenerAdapter() {
+ public void onAnimationCancel(Animator animation) {
+ // If we have been cancelled, remove the listener so that onAnimationEnd doesn't get
+ // called, this will avoid accidentally turning off the grid when we don't want to.
+ animation.removeListener(this);
+ };
+
@Override
public void onAnimationEnd(Animator animation) {
setGridContentVisibility(false);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
index 5fa9fa4..787de4e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java
@@ -139,7 +139,8 @@
// Notify recents to hide itself
Intent intent = new Intent(ACTION_HIDE_RECENTS_ACTIVITY);
intent.setPackage(mContext.getPackageName());
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
+ Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, triggeredFromAltTab);
intent.putExtra(EXTRA_TRIGGERED_FROM_HOME_KEY, triggeredFromHomeKey);
mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
@@ -190,10 +191,14 @@
Task.TaskKey toTaskKey;
if (showNextTask) {
toTaskKey = group.getNextTaskInGroup(task);
- // XXX: We will actually set the appropriate launch animations here
+ launchOpts = ActivityOptions.makeCustomAnimation(mContext,
+ R.anim.recents_launch_next_affiliated_task_target,
+ R.anim.recents_launch_next_affiliated_task_source);
} else {
toTaskKey = group.getPrevTaskInGroup(task);
- // XXX: We will actually set the appropriate launch animations here
+ launchOpts = ActivityOptions.makeCustomAnimation(mContext,
+ R.anim.recents_launch_prev_affiliated_task_target,
+ R.anim.recents_launch_prev_affiliated_task_source);
}
if (toTaskKey != null) {
toTask = stack.findTaskWithId(toTaskKey.id);
@@ -204,7 +209,11 @@
// Return early if there is no next task
if (toTask == null) {
- // XXX: We will actually show a bounce animation here
+ if (showNextTask) {
+ // XXX: Show the next-task bounce animation
+ } else {
+ // XXX: Show the prev-task bounce animation
+ }
return;
}
@@ -243,8 +252,8 @@
mConfig = RecentsConfiguration.reinitialize(mContext, mSystemServicesProxy);
mConfig.updateOnConfigurationChange();
mConfig.getTaskStackBounds(mWindowRect.width(), mWindowRect.height(), mStatusBarHeight,
- mNavBarWidth, mTaskStackBounds);
- if (mConfig.isLandscape && mConfig.transposeRecentsLayoutWithOrientation) {
+ (mConfig.hasTransposedNavBar ? mNavBarWidth : 0), mTaskStackBounds);
+ if (mConfig.isLandscape && mConfig.hasTransposedNavBar) {
mSystemInsets.set(0, mStatusBarHeight, mNavBarWidth, 0);
} else {
mSystemInsets.set(0, mStatusBarHeight, 0, mNavBarHeight);
@@ -316,7 +325,8 @@
// Notify recents to toggle itself
Intent intent = new Intent(ACTION_TOGGLE_RECENTS_ACTIVITY);
intent.setPackage(mContext.getPackageName());
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
+ Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
mLastToggleTime = System.currentTimeMillis();
return;
@@ -590,7 +600,8 @@
// Send the broadcast to notify Recents that the animation has started
Intent intent = new Intent(ACTION_START_ENTER_ANIMATION);
intent.setPackage(mContext.getPackageName());
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
+ Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null,
fallbackReceiver, null, Activity.RESULT_CANCELED, null, null);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 396be3b..ed5c126 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -57,7 +57,8 @@
/** Layout */
boolean isLandscape;
- boolean transposeRecentsLayoutWithOrientation;
+ boolean hasTransposedSearchBar;
+ boolean hasTransposedNavBar;
/** Loading */
public int maxNumTasksToLoad;
@@ -174,8 +175,8 @@
// Layout
isLandscape = res.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
- transposeRecentsLayoutWithOrientation =
- res.getBoolean(R.bool.recents_transpose_layout_with_orientation);
+ hasTransposedSearchBar = res.getBoolean(R.bool.recents_has_transposed_search_bar);
+ hasTransposedNavBar = res.getBoolean(R.bool.recents_has_transposed_nav_bar);
// Insets
displayRect.set(0, 0, dm.widthPixels, dm.heightPixels);
@@ -329,13 +330,12 @@
/** Returns whether the nav bar scrim should be visible. */
public boolean hasNavBarScrim() {
// Only show the scrim if we have recent tasks, and if the nav bar is not transposed
- return !launchedWithNoRecentTasks &&
- (!transposeRecentsLayoutWithOrientation || !isLandscape);
+ return !launchedWithNoRecentTasks && (!hasTransposedNavBar || !isLandscape);
}
/** Returns whether the current layout is horizontal. */
public boolean hasHorizontalLayout() {
- return isLandscape && transposeRecentsLayoutWithOrientation;
+ return isLandscape && hasTransposedSearchBar;
}
/**
@@ -346,7 +346,7 @@
Rect taskStackBounds) {
Rect searchBarBounds = new Rect();
getSearchBarBounds(windowWidth, windowHeight, topInset, searchBarBounds);
- if (isLandscape && transposeRecentsLayoutWithOrientation) {
+ if (isLandscape && hasTransposedSearchBar) {
// In landscape, the search bar appears on the left
taskStackBounds.set(searchBarBounds.right, topInset, windowWidth - rightInset, windowHeight);
} else {
@@ -367,7 +367,7 @@
searchBarSize = 0;
}
- if (isLandscape && transposeRecentsLayoutWithOrientation) {
+ if (isLandscape && hasTransposedSearchBar) {
// In landscape, the search bar appears on the left
searchBarSpaceBounds.set(0, topInset, searchBarSize, windowHeight);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 887cbac..bbd0a0d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -56,6 +56,7 @@
import android.view.DisplayInfo;
import android.view.SurfaceControl;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
import com.android.systemui.recents.Constants;
import java.io.IOException;
@@ -73,6 +74,7 @@
final static BitmapFactory.Options sBitmapOptions;
+ AccessibilityManager mAccm;
ActivityManager mAm;
IActivityManager mIam;
AppWidgetManager mAwm;
@@ -97,6 +99,7 @@
/** Private constructor */
public SystemServicesProxy(Context context) {
+ mAccm = AccessibilityManager.getInstance(context);
mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
mIam = ActivityManagerNative.getDefault();
mAwm = AppWidgetManager.getInstance(context);
@@ -442,6 +445,15 @@
}
/**
+ * Returns whether touch exploration is currently enabled.
+ */
+ public boolean isTouchExplorationEnabled() {
+ if (mAccm == null) return false;
+
+ return mAccm.isEnabled() && mAccm.isTouchExplorationEnabled();
+ }
+
+ /**
* Returns a global setting.
*/
public int getGlobalSetting(Context context, String setting) {
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 dbed136..895b9d1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -22,11 +22,15 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
import com.android.systemui.R;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.misc.DozeTrigger;
+import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.model.RecentsPackageMonitor;
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
@@ -67,6 +71,7 @@
DebugOverlayView mDebugOverlay;
Rect mTaskStackBounds = new Rect();
int mFocusedTaskIndex = -1;
+ int mPrevAccessibilityFocusedIndex = -1;
// Optimizations
int mStackViewsAnimationDuration;
@@ -244,6 +249,9 @@
/** Synchronizes the views with the model */
boolean synchronizeStackViewsWithModel() {
if (mStackViewsDirty) {
+ RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+ SystemServicesProxy ssp = loader.getSystemServicesProxy();
+
// Get all the task transforms
ArrayList<Task> tasks = mStack.getTasks();
float stackScroll = mStackScroller.getStackScroll();
@@ -293,6 +301,18 @@
// Animate the task into place
tv.updateViewPropertiesToTaskTransform(mCurrentTaskTransforms.get(taskIndex),
mStackViewsAnimationDuration);
+
+ // Request accessibility focus on the next view if we removed the task
+ // that previously held accessibility focus
+ childCount = getChildCount();
+ if (childCount > 0 && ssp.isTouchExplorationEnabled()) {
+ TaskView atv = (TaskView) getChildAt(childCount - 1);
+ int indexOfTask = mStack.indexOfTask(atv.getTask());
+ if (mPrevAccessibilityFocusedIndex != indexOfTask) {
+ tv.requestAccessibilityFocus();
+ mPrevAccessibilityFocusedIndex = indexOfTask;
+ }
+ }
}
// Reset the request-synchronize params
@@ -432,6 +452,22 @@
}
@Override
+ public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+ super.onInitializeAccessibilityEvent(event);
+ int childCount = getChildCount();
+ if (childCount > 0) {
+ TaskView backMostTask = (TaskView) getChildAt(0);
+ TaskView frontMostTask = (TaskView) getChildAt(childCount - 1);
+ event.setFromIndex(mStack.indexOfTask(backMostTask.getTask()));
+ event.setToIndex(mStack.indexOfTask(frontMostTask.getTask()));
+ event.setContentDescription(frontMostTask.getTask().activityLabel);
+ }
+ event.setItemCount(mStack.getTaskCount());
+ event.setScrollY(mStackScroller.mScroller.getCurrY());
+ event.setMaxScrollY(mStackScroller.progressToScrollRange(mLayoutAlgorithm.mMaxScrollP));
+ }
+
+ @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mTouchHandler.onInterceptTouchEvent(ev);
}
@@ -447,6 +483,8 @@
// Synchronize the views
synchronizeStackViewsWithModel();
clipTaskViews();
+ // Notify accessibility
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED);
}
/** Computes the stack and task rects */
@@ -623,6 +661,15 @@
mStartEnterAnimationCompleted = true;
// Start dozing
mUIDozeTrigger.startDozing();
+ // Focus the first view if accessibility is enabled
+ RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+ SystemServicesProxy ssp = loader.getSystemServicesProxy();
+ int childCount = getChildCount();
+ if (childCount > 0 && ssp.isTouchExplorationEnabled()) {
+ TaskView tv = ((TaskView) getChildAt(childCount - 1));
+ tv.requestAccessibilityFocus();
+ mPrevAccessibilityFocusedIndex = mStack.indexOfTask(tv.getTask());
+ }
}
});
}
@@ -812,6 +859,11 @@
public void prepareViewToEnterPool(TaskView tv) {
Task task = tv.getTask();
+ // Clear the accessibility focus for that view
+ if (tv.isAccessibilityFocused()) {
+ tv.clearAccessibilityFocus();
+ }
+
// Report that this tasks's data is no longer being used
RecentsTaskLoader.getInstance().unloadTaskData(task);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 6fe86be..4563597 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -840,7 +840,7 @@
@Override
public void onClick(final View v) {
final TaskView tv = this;
- final boolean delayViewClick = (v != this);
+ final boolean delayViewClick = (v != this) && (v != mActionButtonView);
if (delayViewClick) {
// We purposely post the handler delayed to allow for the touch feedback to draw
postDelayed(new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 4d85352..907a13f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -69,6 +69,7 @@
import android.view.ViewAnimationUtils;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
+import android.view.ViewStub;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.accessibility.AccessibilityManager;
@@ -764,17 +765,95 @@
}, false /* afterKeyguardGone */);
}
+ private void inflateGuts(ExpandableNotificationRow row) {
+ ViewStub stub = (ViewStub) row.findViewById(R.id.notification_guts_stub);
+ if (stub != null) {
+ stub.inflate();
+ }
+ final StatusBarNotification sbn = row.getStatusBarNotification();
+ PackageManager pmUser = getPackageManagerForUser(
+ sbn.getUser().getIdentifier());
+ row.setTag(sbn.getPackageName());
+ final View guts = row.findViewById(R.id.notification_guts);
+ final String pkg = sbn.getPackageName();
+ String appname = pkg;
+ Drawable pkgicon = null;
+ int appUid = -1;
+ try {
+ final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
+ PackageManager.GET_UNINSTALLED_PACKAGES
+ | PackageManager.GET_DISABLED_COMPONENTS);
+ if (info != null) {
+ appname = String.valueOf(pmUser.getApplicationLabel(info));
+ pkgicon = pmUser.getApplicationIcon(info);
+ appUid = info.uid;
+ }
+ } catch (NameNotFoundException e) {
+ // app is gone, just show package name and generic icon
+ pkgicon = pmUser.getDefaultActivityIcon();
+ }
+ ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(pkgicon);
+ ((DateTimeView) row.findViewById(R.id.timestamp)).setTime(sbn.getPostTime());
+ ((TextView) row.findViewById(R.id.pkgname)).setText(appname);
+ final View settingsButton = guts.findViewById(R.id.notification_inspect_item);
+ final View appSettingsButton
+ = guts.findViewById(R.id.notification_inspect_app_provided_settings);
+ if (appUid >= 0) {
+ final int appUidF = appUid;
+ settingsButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ startAppNotificationSettingsActivity(pkg, appUidF);
+ }
+ });
+
+ final Intent appSettingsQueryIntent
+ = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES)
+ .setPackage(pkg);
+ List<ResolveInfo> infos = pmUser.queryIntentActivities(appSettingsQueryIntent, 0);
+ if (infos.size() > 0) {
+ appSettingsButton.setVisibility(View.VISIBLE);
+ appSettingsButton.setContentDescription(
+ mContext.getResources().getString(
+ R.string.status_bar_notification_app_settings_title,
+ appname
+ ));
+ final Intent appSettingsLaunchIntent = new Intent(appSettingsQueryIntent)
+ .setClassName(pkg, infos.get(0).activityInfo.name);
+ appSettingsButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ startAppOwnNotificationSettingsActivity(appSettingsLaunchIntent,
+ sbn.getId(),
+ sbn.getTag(),
+ appUidF);
+ }
+ });
+ } else {
+ appSettingsButton.setVisibility(View.GONE);
+ }
+ } else {
+ settingsButton.setVisibility(View.GONE);
+ appSettingsButton.setVisibility(View.GONE);
+ }
+
+ }
+
protected SwipeHelper.LongPressListener getNotificationLongClicker() {
return new SwipeHelper.LongPressListener() {
@Override
public boolean onLongPress(View v, int x, int y) {
dismissPopups();
+ if (!(v instanceof ExpandableNotificationRow)) {
+ return false;
+ }
if (v.getWindowToken() == null) {
Log.e(TAG, "Trying to show notification guts, but not attached to window");
return false;
}
+ inflateGuts((ExpandableNotificationRow) v);
+
// Assume we are a status_bar_notification_row
final NotificationGuts guts = (NotificationGuts) v.findViewById(
R.id.notification_guts);
@@ -1190,67 +1269,6 @@
row.setExpansionLogger(this, entry.notification.getKey());
}
- // the notification inspector (see SwipeHelper.setLongPressListener)
- row.setTag(sbn.getPackageName());
- final View guts = row.findViewById(R.id.notification_guts);
- final String pkg = entry.notification.getPackageName();
- String appname = pkg;
- Drawable pkgicon = null;
- int appUid = -1;
- try {
- final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
- PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS);
- if (info != null) {
- appname = String.valueOf(pmUser.getApplicationLabel(info));
- pkgicon = pmUser.getApplicationIcon(info);
- appUid = info.uid;
- }
- } catch (NameNotFoundException e) {
- // app is gone, just show package name and generic icon
- pkgicon = pmUser.getDefaultActivityIcon();
- }
- ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(pkgicon);
- ((DateTimeView) row.findViewById(R.id.timestamp)).setTime(entry.notification.getPostTime());
- ((TextView) row.findViewById(R.id.pkgname)).setText(appname);
- final View settingsButton = guts.findViewById(R.id.notification_inspect_item);
- final View appSettingsButton
- = guts.findViewById(R.id.notification_inspect_app_provided_settings);
- if (appUid >= 0) {
- final int appUidF = appUid;
- settingsButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- startAppNotificationSettingsActivity(pkg, appUidF);
- }
- });
-
- final Intent appSettingsQueryIntent
- = new Intent(Intent.ACTION_MAIN)
- .addCategory(Notification.INTENT_CATEGORY_NOTIFICATION_PREFERENCES)
- .setPackage(pkg);
- List<ResolveInfo> infos = pmUser.queryIntentActivities(appSettingsQueryIntent, 0);
- if (infos.size() > 0) {
- appSettingsButton.setVisibility(View.VISIBLE);
- appSettingsButton.setContentDescription(
- mContext.getResources().getString(
- R.string.status_bar_notification_app_settings_title,
- appname
- ));
- final Intent appSettingsLaunchIntent = new Intent(appSettingsQueryIntent)
- .setClassName(pkg, infos.get(0).activityInfo.name);
- appSettingsButton.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- startAppOwnNotificationSettingsActivity(appSettingsLaunchIntent,
- sbn.getId(),
- sbn.getTag(),
- appUidF);
- }
- });
- }
- } else {
- settingsButton.setVisibility(View.GONE);
- appSettingsButton.setVisibility(View.GONE);
- }
-
workAroundBadLayerDrawableOpacity(row);
View vetoButton = updateNotificationVetoButton(row, sbn);
vetoButton.setContentDescription(mContext.getString(
@@ -1331,12 +1349,12 @@
if (publicViewLocal == null) {
// Add a basic notification template
publicViewLocal = LayoutInflater.from(mContext).inflate(
- com.android.internal.R.layout.notification_template_material_base,
+ R.layout.notification_public_default,
expandedPublic, false);
publicViewLocal.setIsRootNamespace(true);
expandedPublic.setContractedChild(publicViewLocal);
- final TextView title = (TextView) publicViewLocal.findViewById(com.android.internal.R.id.title);
+ final TextView title = (TextView) publicViewLocal.findViewById(R.id.title);
try {
title.setText(pmUser.getApplicationLabel(
pmUser.getApplicationInfo(entry.notification.getPackageName(), 0)));
@@ -1344,10 +1362,9 @@
title.setText(entry.notification.getPackageName());
}
- final ImageView icon = (ImageView) publicViewLocal.findViewById(
- com.android.internal.R.id.icon);
+ final ImageView icon = (ImageView) publicViewLocal.findViewById(R.id.icon);
final ImageView profileBadge = (ImageView) publicViewLocal.findViewById(
- com.android.internal.R.id.profile_badge_line3);
+ R.id.profile_badge_line3);
final StatusBarIcon ic = new StatusBarIcon(entry.notification.getPackageName(),
entry.notification.getUser(),
@@ -1383,16 +1400,13 @@
}
final View privateTime = contentViewLocal.findViewById(com.android.internal.R.id.time);
+ final DateTimeView time = (DateTimeView) publicViewLocal.findViewById(R.id.time);
if (privateTime != null && privateTime.getVisibility() == View.VISIBLE) {
- final View timeStub = publicViewLocal.findViewById(com.android.internal.R.id.time);
- timeStub.setVisibility(View.VISIBLE);
- final DateTimeView dateTimeView = (DateTimeView)
- publicViewLocal.findViewById(com.android.internal.R.id.time);
- dateTimeView.setTime(entry.notification.getNotification().when);
+ time.setVisibility(View.VISIBLE);
+ time.setTime(entry.notification.getNotification().when);
}
- final TextView text = (TextView) publicViewLocal.findViewById(
- com.android.internal.R.id.text);
+ final TextView text = (TextView) publicViewLocal.findViewById(R.id.text);
if (text != null) {
text.setText(R.string.notification_hidden_text);
text.setTextAppearance(mContext,
@@ -1432,7 +1446,7 @@
row.setUserExpanded(userExpanded);
}
row.setUserLocked(userLocked);
-
+ row.setStatusBarNotification(entry.notification);
return true;
}
@@ -1946,6 +1960,7 @@
} else {
entry.row.setOnClickListener(null);
}
+ entry.row.setStatusBarNotification(notification);
entry.row.notifyContentUpdated();
entry.row.resetHeight();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index c13593a..2ad6859 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -20,9 +20,11 @@
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
+import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewStub;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
@@ -67,6 +69,8 @@
private boolean mWasReset;
private NotificationGuts mGuts;
+ private StatusBarNotification mStatusBarNotification;
+
public void setIconAnimationRunning(boolean running) {
setIconAnimationRunning(running, mPublicLayout);
setIconAnimationRunning(running, mPrivateLayout);
@@ -112,6 +116,14 @@
}
}
+ public void setStatusBarNotification(StatusBarNotification statusBarNotification) {
+ mStatusBarNotification = statusBarNotification;
+ }
+
+ public StatusBarNotification getStatusBarNotification() {
+ return mStatusBarNotification;
+ }
+
public interface ExpansionLogger {
public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
}
@@ -155,7 +167,15 @@
super.onFinishInflate();
mPublicLayout = (NotificationContentView) findViewById(R.id.expandedPublic);
mPrivateLayout = (NotificationContentView) findViewById(R.id.expanded);
- mGuts = (NotificationGuts) findViewById(R.id.notification_guts);
+ ViewStub gutsStub = (ViewStub) findViewById(R.id.notification_guts_stub);
+ gutsStub.setOnInflateListener(new ViewStub.OnInflateListener() {
+ @Override
+ public void onInflate(ViewStub stub, View inflated) {
+ mGuts = (NotificationGuts) inflated;
+ mGuts.setClipTopAmount(getClipTopAmount());
+ mGuts.setActualHeight(getActualHeight());
+ }
+ });
mVetoButton = findViewById(R.id.veto);
}
@@ -421,7 +441,9 @@
public void setActualHeight(int height, boolean notifyListeners) {
mPrivateLayout.setActualHeight(height);
mPublicLayout.setActualHeight(height);
- mGuts.setActualHeight(height);
+ if (mGuts != null) {
+ mGuts.setActualHeight(height);
+ }
invalidate();
super.setActualHeight(height, notifyListeners);
}
@@ -443,7 +465,9 @@
super.setClipTopAmount(clipTopAmount);
mPrivateLayout.setClipTopAmount(clipTopAmount);
mPublicLayout.setClipTopAmount(clipTopAmount);
- mGuts.setClipTopAmount(clipTopAmount);
+ if (mGuts != null) {
+ mGuts.setClipTopAmount(clipTopAmount);
+ }
}
public void notifyContentUpdated() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index fc737be..70b6952 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -17,14 +17,10 @@
package com.android.systemui.statusbar.phone;
import android.content.Context;
-import android.os.SystemClock;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardViewBase;
@@ -33,7 +29,7 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import static com.android.keyguard.KeyguardHostView.OnDismissAction;
-import static com.android.keyguard.KeyguardSecurityModel.*;
+import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
/**
* A class which manages the bouncer on the lockscreen.
@@ -62,6 +58,10 @@
public void show() {
ensureView();
if (mRoot.getVisibility() == View.VISIBLE) {
+
+ // show() updates the current security method. This is needed in case we are already
+ // showing and the current security method changed.
+ mKeyguardView.show();
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarViewTaskSwitchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarViewTaskSwitchHelper.java
index b633453..79bb1cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarViewTaskSwitchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarViewTaskSwitchHelper.java
@@ -31,7 +31,6 @@
private final GestureDetector mTaskSwitcherDetector;
private final int mScrollTouchSlop;
private final int mMinFlingVelocity;
- private boolean mInterceptTouches;
private int mTouchDownX;
private int mTouchDownY;
@@ -56,11 +55,11 @@
// task switcher detector
mTaskSwitcherDetector.onTouchEvent(event);
int action = event.getAction();
+ boolean interceptTouches = false;
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
mTouchDownX = (int) event.getX();
mTouchDownY = (int) event.getY();
- mInterceptTouches = false;
break;
}
case MotionEvent.ACTION_MOVE: {
@@ -72,21 +71,19 @@
? xDiff > mScrollTouchSlop && xDiff > yDiff
: yDiff > mScrollTouchSlop && yDiff > xDiff;
if (exceededTouchSlop) {
- mInterceptTouches = true;
+ interceptTouches = true;
return true;
}
break;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
- mInterceptTouches = false;
break;
}
- return mInterceptTouches;
+ return interceptTouches;
}
public boolean onTouchEvent(MotionEvent event) {
- if (!mInterceptTouches) return false;
return mTaskSwitcherDetector.onTouchEvent(event);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 0499b14..902123d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -23,6 +23,8 @@
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
import android.util.AttributeSet;
import android.util.MathUtils;
import android.view.MotionEvent;
@@ -60,6 +62,10 @@
private static final float HEADER_RUBBERBAND_FACTOR = 2.05f;
private static final float LOCK_ICON_ACTIVE_SCALE = 1.2f;
+ private static final int DOZE_BACKGROUND_COLOR = 0xff000000;
+ private static final int TAG_KEY_ANIM = R.id.scrim;
+ private static final long DOZE_BACKGROUND_ANIM_DURATION = ScrimController.ANIMATION_DURATION;
+
private KeyguardAffordanceHelper mAfforanceHelper;
private StatusBarHeaderView mHeader;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
@@ -625,9 +631,10 @@
}
private boolean isInQsArea(float x, float y) {
- return mStatusBarState != StatusBarState.SHADE
- || y <= mNotificationStackScroller.getBottomMostNotificationBottom()
- || y <= mQsContainer.getY() + mQsContainer.getHeight();
+ return mStatusBarState != StatusBarState.SHADE ||
+ (x >= mScrollView.getLeft() && x <= mScrollView.getRight()) &&
+ (y <= mNotificationStackScroller.getBottomMostNotificationBottom()
+ || y <= mQsContainer.getY() + mQsContainer.getHeight());
}
private void handleQsDown(MotionEvent event) {
@@ -1724,13 +1731,58 @@
if (dozing == mDozing) return;
mDozing = dozing;
if (mDozing) {
- setBackgroundColor(0xff000000);
+ setBackgroundColorAlpha(this, DOZE_BACKGROUND_COLOR, 0xff, false /*animate*/);
} else {
- setBackground(null);
+ setBackgroundColorAlpha(this, DOZE_BACKGROUND_COLOR, 0, true /*animate*/);
}
updateKeyguardStatusBarVisibility();
}
+ private static void setBackgroundColorAlpha(final View target, int rgb, int targetAlpha,
+ boolean animate) {
+ int currentAlpha = getBackgroundAlpha(target);
+ if (currentAlpha == targetAlpha) {
+ return;
+ }
+ final int r = Color.red(rgb);
+ final int g = Color.green(rgb);
+ final int b = Color.blue(rgb);
+ Object runningAnim = target.getTag(TAG_KEY_ANIM);
+ if (runningAnim instanceof ValueAnimator) {
+ ((ValueAnimator) runningAnim).cancel();
+ }
+ if (!animate) {
+ target.setBackgroundColor(Color.argb(targetAlpha, r, g, b));
+ return;
+ }
+ ValueAnimator anim = ValueAnimator.ofInt(currentAlpha, targetAlpha);
+ anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ int value = (int) animation.getAnimatedValue();
+ target.setBackgroundColor(Color.argb(value, r, g, b));
+ }
+ });
+ anim.setDuration(DOZE_BACKGROUND_ANIM_DURATION);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ target.setTag(TAG_KEY_ANIM, null);
+ }
+ });
+ anim.start();
+ target.setTag(TAG_KEY_ANIM, anim);
+ }
+
+ private static int getBackgroundAlpha(View view) {
+ if (view.getBackground() instanceof ColorDrawable) {
+ ColorDrawable drawable = (ColorDrawable) view.getBackground();
+ return Color.alpha(drawable.getColor());
+ } else {
+ return 0;
+ }
+ }
+
public void setShadeEmpty(boolean shadeEmpty) {
mShadeEmpty = shadeEmpty;
updateEmptyShadeView();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 7261ea1..006e480 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -684,25 +684,27 @@
removeCallbacks(mPeekRunnable);
mPeekRunnable.run();
}
- } else if (!isFullyCollapsed() && !mTracking) {
+ } else if (!isFullyCollapsed() && !mTracking && !mClosing) {
if (mHeightAnimator != null) {
mHeightAnimator.cancel();
}
mClosing = true;
notifyExpandingStarted();
if (delayed) {
- postDelayed(new Runnable() {
- @Override
- public void run() {
- fling(0, false /* expand */);
- }
- }, 120);
+ postDelayed(mFlingCollapseRunnable, 120);
} else {
fling(0, false /* expand */);
}
}
}
+ private final Runnable mFlingCollapseRunnable = new Runnable() {
+ @Override
+ public void run() {
+ fling(0, false /* expand */);
+ }
+ };
+
public void expand() {
if (DEBUG) logf("expand: " + this);
if (isFullyCollapsed()) {
@@ -728,7 +730,9 @@
public void instantExpand() {
mInstantExpanding = true;
+ mUpdateFlingOnLayout = false;
abortAnimations();
+ cancelPeek();
if (mTracking) {
onTrackingStopped(true /* expands */); // The panel is expanded after this call.
}
@@ -761,6 +765,8 @@
if (mHeightAnimator != null) {
mHeightAnimator.cancel();
}
+ removeCallbacks(mPostCollapseRunnable);
+ removeCallbacks(mFlingCollapseRunnable);
}
protected void startUnlockHintAnimation() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index e939057..5d4c831 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -3948,6 +3948,13 @@
return !mNotificationData.getActiveNotifications().isEmpty();
}
+ public void wakeUpIfDozing(long time) {
+ if (mDozeServiceHost != null && mDozeServiceHost.isDozing()) {
+ PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ pm.wakeUp(time);
+ }
+ }
+
private final class ShadeUpdates {
private final ArraySet<String> mVisibleNotifications = new ArraySet<String>();
private final ArraySet<String> mNewVisibleNotifications = new ArraySet<String>();
@@ -3992,6 +3999,10 @@
+ mCurrentDozeService + "]";
}
+ public boolean isDozing() {
+ return mCurrentDozeService != null;
+ }
+
public void firePowerSaveChanged(boolean active) {
for (Callback callback : mCallbacks) {
callback.onPowerSaveChanged(active);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 455c336..be48df7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -38,11 +38,12 @@
private static final String TAG = "ScrimController";
private static final boolean DEBUG = false;
+ public static final long ANIMATION_DURATION = 220;
+
private static final float SCRIM_BEHIND_ALPHA = 0.62f;
private static final float SCRIM_BEHIND_ALPHA_KEYGUARD = 0.55f;
private static final float SCRIM_BEHIND_ALPHA_UNLOCKING = 0.2f;
private static final float SCRIM_IN_FRONT_ALPHA = 0.75f;
- private static final long ANIMATION_DURATION = 220;
private static final int TAG_KEY_ANIM = R.id.scrim;
private static final long PULSE_IN_ANIMATION_DURATION = 1000;
@@ -131,6 +132,7 @@
mDozing = dozing;
if (!mDozing) {
cancelPulsing();
+ mAnimateChange = true;
}
scheduleUpdate();
}
@@ -163,7 +165,7 @@
if (mAnimateKeyguardFadingOut) {
setScrimInFrontColor(0f);
setScrimBehindColor(0f);
- }else if (!mKeyguardShowing && !mBouncerShowing) {
+ } else if (!mKeyguardShowing && !mBouncerShowing) {
updateScrimNormal();
setScrimInFrontColor(0);
} else {
@@ -217,8 +219,8 @@
mScrimInFront.setClickable(false);
} else {
- // Eat touch events.
- mScrimInFront.setClickable(true);
+ // Eat touch events (unless dozing).
+ mScrimInFront.setClickable(!mDozing);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 1811d8d..a5217ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -128,6 +128,10 @@
&& mService.getBarState() == StatusBarState.KEYGUARD
&& !mService.isBouncerShowing()) {
intercept = mDragDownHelper.onInterceptTouchEvent(ev);
+ // wake up on a touch down event, if dozing
+ if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mService.wakeUpIfDozing(ev.getEventTime());
+ }
}
if (!intercept) {
super.onInterceptTouchEvent(ev);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 5088089..4d248c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -337,7 +337,9 @@
@Override
public DataUsageInfo getDataUsageInfo() {
final DataUsageInfo info = mMobileDataController.getDataUsageInfo();
- info.carrier = mNetworkName;
+ if (info != null) {
+ info.carrier = mNetworkName;
+ }
return info;
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index 6949ffb..fa43f32 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -431,6 +431,9 @@
public void onConfigurationChanged(Configuration newConfig) {
updateWidth();
+ if (mZenPanel != null) {
+ mZenPanel.updateLocale();
+ }
}
private void updateWidth() {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index ac7fc25..f829994 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -60,7 +60,7 @@
private static final int[] MINUTE_BUCKETS = DEBUG
? new int[] { 0, 1, 2, 5, 15, 30, 45, 60, 120, 180, 240, 480 }
- : new int[] { 15, 30, 45, 60, 120, 180, 240, 480 };
+ : ZenModeConfig.MINUTE_BUCKETS;
private static final int MIN_BUCKET_MINUTES = MINUTE_BUCKETS[0];
private static final int MAX_BUCKET_MINUTES = MINUTE_BUCKETS[MINUTE_BUCKETS.length - 1];
private static final int DEFAULT_BUCKET_INDEX = Arrays.binarySearch(MINUTE_BUCKETS, 60);
@@ -68,7 +68,6 @@
private static final int TIME_CONDITION_INDEX = 1;
private static final int FIRST_CONDITION_INDEX = 2;
private static final float SILENT_HINT_PULSE_SCALE = 1.1f;
- private static final int ZERO_VALUE_MS = 20 * SECONDS_MS;
public static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
@@ -121,10 +120,7 @@
super.onFinishInflate();
mZenButtons = (SegmentedButtons) findViewById(R.id.zen_buttons);
- mZenButtons.addButton(R.string.interruption_level_none, Global.ZEN_MODE_NO_INTERRUPTIONS);
- mZenButtons.addButton(R.string.interruption_level_priority,
- Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
- mZenButtons.addButton(R.string.interruption_level_all, Global.ZEN_MODE_OFF);
+ addZenButtons();
mZenButtons.setCallback(mZenButtonsCallback);
mZenSubhead = findViewById(R.id.zen_subhead);
@@ -174,6 +170,13 @@
setExpanded(false);
}
+ private void addZenButtons() {
+ mZenButtons.addButton(R.string.interruption_level_none, Global.ZEN_MODE_NO_INTERRUPTIONS);
+ mZenButtons.addButton(R.string.interruption_level_priority,
+ Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ mZenButtons.addButton(R.string.interruption_level_all, Global.ZEN_MODE_OFF);
+ }
+
public void setHidden(boolean hidden) {
if (mHidden == hidden) return;
mHidden = hidden;
@@ -213,7 +216,7 @@
mBucketIndex = -1;
} else {
mBucketIndex = DEFAULT_BUCKET_INDEX;
- mTimeCondition = newTimeCondition(MINUTE_BUCKETS[mBucketIndex]);
+ mTimeCondition = ZenModeConfig.toTimeCondition(MINUTE_BUCKETS[mBucketIndex]);
}
if (DEBUG) Log.d(mTag, "Initial bucket index: " + mBucketIndex);
mConditions = null; // reset conditions
@@ -234,6 +237,11 @@
mController.addCallback(mZenCallback);
}
+ public void updateLocale() {
+ mZenButtons.removeAllViews();
+ addZenButtons();
+ }
+
private void setExitCondition(Condition exitCondition) {
if (sameConditionId(mExitCondition, exitCondition)) return;
mExitCondition = exitCondition;
@@ -254,7 +262,7 @@
}
private void refreshExitConditionText() {
- final String forever = mContext.getString(R.string.zen_mode_forever);
+ final String forever = mContext.getString(com.android.internal.R.string.zen_mode_forever);
if (mExitCondition == null) {
mExitConditionText = forever;
} else if (ZenModeConfig.isValidCountdownConditionId(mExitCondition.id)) {
@@ -330,24 +338,7 @@
if (time == 0) return null;
final long span = time - System.currentTimeMillis();
if (span <= 0 || span > MAX_BUCKET_MINUTES * MINUTES_MS) return null;
- return timeCondition(time, Math.round(span / (float)MINUTES_MS));
- }
-
- private Condition newTimeCondition(int minutesFromNow) {
- final long now = System.currentTimeMillis();
- final long millis = minutesFromNow == 0 ? ZERO_VALUE_MS : minutesFromNow * MINUTES_MS;
- return timeCondition(now + millis, minutesFromNow);
- }
-
- private Condition timeCondition(long time, int minutes) {
- final int num = minutes < 60 ? minutes : Math.round(minutes / 60f);
- final int resId = minutes < 60
- ? R.plurals.zen_mode_duration_minutes
- : R.plurals.zen_mode_duration_hours;
- final String caption = mContext.getResources().getQuantityString(resId, num, num);
- final Uri id = ZenModeConfig.toCountdownConditionId(time);
- return new Condition(id, caption, "", "", 0, Condition.STATE_TRUE,
- Condition.FLAG_RELEVANT_NOW);
+ return ZenModeConfig.toTimeCondition(time, Math.round(span / (float) MINUTES_MS));
}
private void handleUpdateConditions(Condition[] conditions) {
@@ -401,7 +392,7 @@
if (favoriteIndex == -1) {
getConditionTagAt(FOREVER_CONDITION_INDEX).rb.setChecked(true);
} else {
- mTimeCondition = newTimeCondition(MINUTE_BUCKETS[favoriteIndex]);
+ mTimeCondition = ZenModeConfig.toTimeCondition(MINUTE_BUCKETS[favoriteIndex]);
mBucketIndex = favoriteIndex;
bind(mTimeCondition, mZenConditions.getChildAt(TIME_CONDITION_INDEX));
getConditionTagAt(TIME_CONDITION_INDEX).rb.setChecked(true);
@@ -457,7 +448,7 @@
});
final TextView title = (TextView) row.findViewById(android.R.id.title);
if (condition == null) {
- title.setText(R.string.zen_mode_forever);
+ title.setText(mContext.getString(com.android.internal.R.string.zen_mode_forever));
} else {
title.setText(condition.summary);
}
@@ -494,7 +485,7 @@
} else {
final long span = time - System.currentTimeMillis();
button1.setEnabled(span > MIN_BUCKET_MINUTES * MINUTES_MS);
- final Condition maxCondition = newTimeCondition(MAX_BUCKET_MINUTES);
+ final Condition maxCondition = ZenModeConfig.toTimeCondition(MAX_BUCKET_MINUTES);
button2.setEnabled(!Objects.equals(condition.summary, maxCondition.summary));
}
@@ -520,18 +511,18 @@
final long bucketTime = now + bucketMinutes * MINUTES_MS;
if (up && bucketTime > time || !up && bucketTime < time) {
mBucketIndex = j;
- newCondition = timeCondition(bucketTime, bucketMinutes);
+ newCondition = ZenModeConfig.toTimeCondition(bucketTime, bucketMinutes);
break;
}
}
if (newCondition == null) {
mBucketIndex = DEFAULT_BUCKET_INDEX;
- newCondition = newTimeCondition(MINUTE_BUCKETS[mBucketIndex]);
+ newCondition = ZenModeConfig.toTimeCondition(MINUTE_BUCKETS[mBucketIndex]);
}
} else {
// on a known index, simply increment or decrement
mBucketIndex = Math.max(0, Math.min(N - 1, mBucketIndex + (up ? 1 : -1)));
- newCondition = newTimeCondition(MINUTE_BUCKETS[mBucketIndex]);
+ newCondition = ZenModeConfig.toTimeCondition(MINUTE_BUCKETS[mBucketIndex]);
}
mTimeCondition = newCondition;
bind(mTimeCondition, row);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 3062a92..75090db 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4746,6 +4746,11 @@
private void updateNetworkScore(NetworkAgentInfo nai, int score) {
if (DBG) log("updateNetworkScore for " + nai.name() + " to " + score);
+ if (score < 0) {
+ loge("updateNetworkScore for " + nai.name() + " got a negative score (" + score +
+ "). Bumping score to min of 0");
+ score = 0;
+ }
nai.currentScore = score;
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index c8718e3e..060c8e3 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -106,6 +106,7 @@
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
+import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
@@ -3455,9 +3456,14 @@
parser.getAttributeValue(null, ATTR_IME_SUBTYPE_EXTRA_VALUE);
final boolean isAuxiliary = "1".equals(String.valueOf(
parser.getAttributeValue(null, ATTR_IS_AUXILIARY)));
- final InputMethodSubtype subtype =
- new InputMethodSubtype(label, icon, imeSubtypeLocale,
- imeSubtypeMode, imeSubtypeExtraValue, isAuxiliary);
+ final InputMethodSubtype subtype = new InputMethodSubtypeBuilder()
+ .setSubtypeNameResId(label)
+ .setSubtypeIconResId(icon)
+ .setSubtypeLocale(imeSubtypeLocale)
+ .setSubtypeMode(imeSubtypeMode)
+ .setSubtypeExtraValue(imeSubtypeExtraValue)
+ .setIsAuxiliary(isAuxiliary)
+ .build();
tempSubtypesArray.add(subtype);
}
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 0bdb964..599c3b9 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -308,7 +308,14 @@
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
}
+
ServiceRecord r = res.record;
+
+ if (!mAm.getUserManagerLocked().exists(r.userId)) {
+ Slog.d(TAG, "Trying to start service with non-existent user! " + r.userId);
+ return null;
+ }
+
NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
callingUid, r.packageName, service, service.getFlags(), null, r.userId);
if (unscheduleServiceRestartLocked(r, callingUid, false)) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a9a4732..5845ad0 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -888,6 +888,8 @@
boolean mProcessesReady = false;
boolean mSystemReady = false;
boolean mBooting = false;
+ boolean mCallFinishBooting = false;
+ boolean mBootAnimationComplete = false;
boolean mWaitingUpdate = false;
boolean mDidUpdate = false;
boolean mOnBattery = false;
@@ -6195,6 +6197,14 @@
}
final void finishBooting() {
+ synchronized (this) {
+ if (!mBootAnimationComplete) {
+ mCallFinishBooting = true;
+ return;
+ }
+ mCallFinishBooting = false;
+ }
+
// Register receivers to handle package update events
mPackageMonitor.register(mContext, Looper.getMainLooper(), false);
@@ -6253,6 +6263,18 @@
}
}
+ @Override
+ public void bootAnimationComplete() {
+ final boolean callFinishBooting;
+ synchronized (this) {
+ callFinishBooting = mCallFinishBooting;
+ mBootAnimationComplete = true;
+ }
+ if (callFinishBooting) {
+ finishBooting();
+ }
+ }
+
final void ensureBootCompleted() {
boolean booting;
boolean enableScreen;
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index f6beb9a..9292d45 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -16,6 +16,7 @@
package com.android.server.content;
+import android.Manifest;
import android.accounts.Account;
import android.accounts.AccountAndUser;
import android.accounts.AccountManager;
@@ -478,7 +479,7 @@
mContext.registerReceiverAsUser(mAccountsUpdatedReceiver,
UserHandle.ALL,
new IntentFilter(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION),
- null, null);
+ Manifest.permission.ACCOUNT_MANAGER, null);
}
// Pick a random second in a day to seed all periodic syncs
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 38c6fb3..5cd7c01 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -256,7 +256,7 @@
private List<HdmiDeviceInfo> mMhlDevices;
@Nullable
- private HdmiMhlController mMhlController;
+ private HdmiMhlControllerStub mMhlController;
// Last input port before switching to the MHL port. Should switch back to this port
// when the mobile device sends the request one touch play with off.
@@ -305,7 +305,7 @@
Slog.i(TAG, "Device does not support HDMI-CEC.");
}
- mMhlController = HdmiMhlController.create(this);
+ mMhlController = HdmiMhlControllerStub.create(this);
if (!mMhlController.isReady()) {
Slog.i(TAG, "Device does not support MHL-control.");
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiMhlControllerStub.java b/services/core/java/com/android/server/hdmi/HdmiMhlControllerStub.java
new file mode 100644
index 0000000..c27cf18
--- /dev/null
+++ b/services/core/java/com/android/server/hdmi/HdmiMhlControllerStub.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2014 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.hdmi;
+
+import android.hardware.hdmi.HdmiPortInfo;
+import android.util.SparseArray;
+
+import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
+
+/**
+ * A handler class for MHL control command. It converts user's command into MHL command and pass it
+ * to MHL HAL layer.
+ * <p>
+ * It can be created only by {@link HdmiMhlControllerStub#create}.
+ */
+final class HdmiMhlControllerStub {
+
+ private static final SparseArray<HdmiMhlLocalDevice> mLocalDevices = new SparseArray<>();
+ private static final HdmiPortInfo[] EMPTY_PORT_INFO = new HdmiPortInfo[0];
+ private static final int INVALID_MHL_VERSION = 0;
+ private static final int NO_SUPPORTED_FEATURES = 0;
+ private static final int INVALID_DEVICE_ROLES = 0;
+
+ // Private constructor. Use HdmiMhlControllerStub.create().
+ private HdmiMhlControllerStub(HdmiControlService service) {
+ }
+
+ // Returns true if MHL controller is initialized and ready to use.
+ boolean isReady() {
+ return false;
+ }
+
+ static HdmiMhlControllerStub create(HdmiControlService service) {
+ return new HdmiMhlControllerStub(service);
+ }
+
+ HdmiPortInfo[] getPortInfos() {
+ return EMPTY_PORT_INFO;
+ }
+
+ /**
+ * Return {@link HdmiMhlLocalDevice} matched with the given port id.
+ *
+ * @return null if has no matched port id
+ */
+ HdmiMhlLocalDevice getLocalDevice(int portId) {
+ return null;
+ }
+
+ /**
+ * Return {@link HdmiMhlLocalDevice} matched with the given device id.
+ *
+ * @return null if has no matched id
+ */
+ HdmiMhlLocalDevice getLocalDeviceById(int deviceId) {
+ return null;
+ }
+
+ SparseArray<HdmiMhlLocalDevice> getAllLocalDevices() {
+ return mLocalDevices;
+ }
+
+ /**
+ * Remove a {@link HdmiMhlLocalDevice} matched with the given port id.
+ *
+ * @return removed {@link HdmiMhlLocalDevice}. Return null if no matched port id.
+ */
+ HdmiMhlLocalDevice removeLocalDevice(int portId) {
+ return null;
+ }
+
+ /**
+ * Add a new {@link HdmiMhlLocalDevice}.
+ *
+ * @return old {@link HdmiMhlLocalDevice} having same port id
+ */
+ HdmiMhlLocalDevice addLocalDevice(HdmiMhlLocalDevice device) {
+ return null;
+ }
+
+ void clearAllLocalDevices() {
+ }
+
+ /**
+ * Send MHL MSC-Subcommand to the device connected to the given port.
+ */
+ void sendSubcommand(int portId, HdmiMhlSubcommand command) {
+ }
+
+ void sendSubcommand(final int portId, final HdmiMhlSubcommand command,
+ SendMessageCallback callback) {
+ }
+
+
+ void sendScratchpadCommand(int portId, int offset, int length, byte[] data) {
+ }
+
+ void setOption(int flag, int value) {
+ }
+
+ /**
+ * Get the MHL version supported by underlying hardware port of the given {@code portId}.
+ * MHL specification version 2.0 returns 0x20, 3.0 will return 0x30 respectively.
+ * The return value is stored in 'version'. Return INVALID_VERSION if MHL hardware layer
+ * is not ready.
+ */
+ int getMhlVersion(int portId) {
+ return INVALID_MHL_VERSION;
+ }
+
+ /**
+ * Get MHL version of a device which is connected to a port of the given {@code portId}.
+ * MHL specification version 2.0 returns 0x20, 3.0 will return 0x30 respectively.
+ * The return value is stored in 'version'.
+ */
+ int getPeerMhlVersion(int portId) {
+ return INVALID_MHL_VERSION;
+ }
+
+ /**
+ * Get the bit flags describing the features supported by the system. Refer to feature support
+ * flag register info in MHL specification.
+ */
+ int getSupportedFeatures(int portId) {
+ return NO_SUPPORTED_FEATURES;
+ }
+
+ /**
+ * Get the bit flags describing the roles which ECBUS device can play. Refer to the
+ * ECBUS_DEV_ROLES Register info MHL3.0 specification
+ */
+ int getEcbusDeviceRoles(int portId) {
+ return INVALID_DEVICE_ROLES;
+ }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index a56f783..c09eff8 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -49,6 +49,7 @@
import android.database.ContentObserver;
import android.media.AudioAttributes;
import android.media.AudioManager;
+import android.media.AudioSystem;
import android.media.IRingtonePlayer;
import android.net.Uri;
import android.os.Binder;
@@ -1945,14 +1946,19 @@
}
private static AudioAttributes audioAttributesForNotification(Notification n) {
- if (n.audioAttributes != null
- && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) {
+ if (n.audioAttributes != null) {
return n.audioAttributes;
+ } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
+ // the stream type is valid, use it
+ return new AudioAttributes.Builder()
+ .setInternalLegacyStreamType(n.audioStreamType)
+ .build();
+ } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) {
+ return Notification.AUDIO_ATTRIBUTES_DEFAULT;
+ } else {
+ Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
+ return Notification.AUDIO_ATTRIBUTES_DEFAULT;
}
- return new AudioAttributes.Builder()
- .setLegacyStreamType(n.audioStreamType)
- .setUsage(AudioAttributes.usageForLegacyStreamType(n.audioStreamType))
- .build();
}
void showNextToastLocked() {
@@ -2965,15 +2971,18 @@
*/
private static final class StatusBarNotificationHolder
extends IStatusBarNotificationHolder.Stub {
- private final StatusBarNotification mValue;
+ private StatusBarNotification mValue;
public StatusBarNotificationHolder(StatusBarNotification value) {
mValue = value;
}
+ /** Get the held value and clear it. This function should only be called once per holder */
@Override
public StatusBarNotification get() {
- return mValue;
+ StatusBarNotification value = mValue;
+ mValue = null;
+ return value;
}
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 5639dad..41d7fa8f 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -301,8 +301,8 @@
final int ringerMode = mAudioManager.getRingerMode();
int newZen = -1;
if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
- if (mZenMode != Global.ZEN_MODE_NO_INTERRUPTIONS) {
- newZen = Global.ZEN_MODE_NO_INTERRUPTIONS;
+ if (mZenMode == Global.ZEN_MODE_OFF) {
+ newZen = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
}
} else if ((ringerMode == AudioManager.RINGER_MODE_NORMAL
|| ringerMode == AudioManager.RINGER_MODE_VIBRATE)
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index adca46a..06f550d 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -579,8 +579,7 @@
try {
apk = PackageParser.parseApkLite(file, PackageParser.PARSE_COLLECT_CERTIFICATES);
} catch (PackageParserException e) {
- throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
- "Failed to parse " + file + ": " + e);
+ throw PackageManagerException.from(e);
}
if (!stagedSplits.add(apk.splitName)) {
@@ -646,8 +645,7 @@
existingBase = PackageParser.parseApkLite(new File(app.getBaseCodePath()),
PackageParser.PARSE_COLLECT_CERTIFICATES);
} catch (PackageParserException e) {
- throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
- "Failed to parse existing package " + app.getCodePath() + ": " + e);
+ throw PackageManagerException.from(e);
}
assertApkConsistent("Existing base", existingBase);
@@ -699,8 +697,7 @@
try {
baseApk = PackageParser.parseApkLite(mResolvedBaseFile, 0);
} catch (PackageParserException e) {
- throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
- "Failed to parse base package " + mResolvedBaseFile + ": " + e);
+ throw PackageManagerException.from(e);
}
final List<String> splitPaths = new ArrayList<>();
diff --git a/services/core/java/com/android/server/pm/PackageManagerException.java b/services/core/java/com/android/server/pm/PackageManagerException.java
index 0cbdcdc..a41636e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerException.java
+++ b/services/core/java/com/android/server/pm/PackageManagerException.java
@@ -16,6 +16,8 @@
package com.android.server.pm;
+import android.content.pm.PackageParser.PackageParserException;
+
/** {@hide} */
public class PackageManagerException extends Exception {
public final int error;
@@ -29,4 +31,9 @@
super(detailMessage, throwable);
this.error = error;
}
+
+ public static PackageManagerException from(PackageParserException e)
+ throws PackageManagerException {
+ throw new PackageManagerException(e.error, e.getMessage(), e.getCause());
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d1bc35b..d821fc1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4162,8 +4162,7 @@
pp.collectCertificates(pkg, parseFlags);
pp.collectManifestDigest(pkg);
} catch (PackageParserException e) {
- throw new PackageManagerException(e.error, "Failed to collect certificates for "
- + pkg.packageName + ": " + e.getMessage());
+ throw PackageManagerException.from(e);
}
}
@@ -4188,8 +4187,7 @@
try {
pkg = pp.parsePackage(scanFile, parseFlags);
} catch (PackageParserException e) {
- throw new PackageManagerException(e.error,
- "Failed to scan " + scanFile + ": " + e.getMessage());
+ throw PackageManagerException.from(e);
}
PackageSetting ps = null;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 4a2cece..d032d29 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -21,7 +21,6 @@
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
-import android.app.ActivityThread;
import android.app.IStopUserCallback;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -92,6 +91,7 @@
private static final String ATTR_SERIAL_NO = "serialNumber";
private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber";
private static final String ATTR_PARTIAL = "partial";
+ private static final String ATTR_GUEST_TO_REMOVE = "guestToRemove";
private static final String ATTR_USER_VERSION = "version";
private static final String ATTR_PROFILE_GROUP_ID = "profileGroupId";
private static final String TAG_GUEST_RESTRICTIONS = "guestRestrictions";
@@ -228,7 +228,7 @@
ArrayList<UserInfo> partials = new ArrayList<UserInfo>();
for (int i = 0; i < mUsers.size(); i++) {
UserInfo ui = mUsers.valueAt(i);
- if (ui.partial && i != 0) {
+ if ((ui.partial || ui.guestToRemove) && i != 0) {
partials.add(ui);
}
}
@@ -759,6 +759,9 @@
if (userInfo.partial) {
serializer.attribute(null, ATTR_PARTIAL, "true");
}
+ if (userInfo.guestToRemove) {
+ serializer.attribute(null, ATTR_GUEST_TO_REMOVE, "true");
+ }
if (userInfo.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID) {
serializer.attribute(null, ATTR_PROFILE_GROUP_ID,
Integer.toString(userInfo.profileGroupId));
@@ -806,7 +809,7 @@
serializer.attribute(null, ATTR_NEXT_SERIAL_NO, Integer.toString(mNextSerialNumber));
serializer.attribute(null, ATTR_USER_VERSION, Integer.toString(mUserVersion));
- serializer.startTag(null, TAG_GUEST_RESTRICTIONS);
+ serializer.startTag(null, TAG_GUEST_RESTRICTIONS);
writeRestrictionsLocked(serializer, mGuestRestrictions);
serializer.endTag(null, TAG_GUEST_RESTRICTIONS);
for (int i = 0; i < mUsers.size(); i++) {
@@ -855,6 +858,8 @@
writeBoolean(serializer, restrictions, UserManager.DISALLOW_OUTGOING_CALLS);
writeBoolean(serializer, restrictions, UserManager.DISALLOW_SMS);
writeBoolean(serializer, restrictions, UserManager.DISALLOW_CREATE_WINDOWS);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
+ writeBoolean(serializer, restrictions, UserManager.DISALLOW_OUTGOING_BEAM);
serializer.endTag(null, TAG_RESTRICTIONS);
}
@@ -871,6 +876,7 @@
int profileGroupId = UserInfo.NO_PROFILE_GROUP_ID;
long lastAttemptTime = 0L;
boolean partial = false;
+ boolean guestToRemove = false;
Bundle restrictions = new Bundle();
FileInputStream fis = null;
@@ -918,6 +924,10 @@
if ("true".equals(valueString)) {
partial = true;
}
+ valueString = parser.getAttributeValue(null, ATTR_GUEST_TO_REMOVE);
+ if ("true".equals(valueString)) {
+ guestToRemove = true;
+ }
int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -942,6 +952,7 @@
userInfo.creationTime = creationTime;
userInfo.lastLoggedInTime = lastLoggedInTime;
userInfo.partial = partial;
+ userInfo.guestToRemove = guestToRemove;
userInfo.profileGroupId = profileGroupId;
mUserRestrictions.append(id, restrictions);
if (salt != 0L) {
@@ -999,6 +1010,8 @@
readBoolean(parser, restrictions, UserManager.DISALLOW_OUTGOING_CALLS);
readBoolean(parser, restrictions, UserManager.DISALLOW_SMS);
readBoolean(parser, restrictions, UserManager.DISALLOW_CREATE_WINDOWS);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
+ readBoolean(parser, restrictions, UserManager.DISALLOW_OUTGOING_BEAM);
}
private void readBoolean(XmlPullParser parser, Bundle restrictions,
@@ -1119,7 +1132,7 @@
return null;
}
// If we're adding a guest and there already exists one, bail.
- if (isGuest && numberOfUsersOfTypeLocked(UserInfo.FLAG_GUEST, true) > 0) {
+ if (isGuest && findCurrentGuestUserLocked() != null) {
return null;
}
// Limit number of managed profiles that can be created
@@ -1180,6 +1193,23 @@
}
/**
+ * Find the current guest user. If the Guest user is partial,
+ * then do not include it in the results as it is about to die.
+ * This is different than {@link #numberOfUsersOfTypeLocked(int, boolean)} due to
+ * the special handling of Guests being removed.
+ */
+ private UserInfo findCurrentGuestUserLocked() {
+ final int size = mUsers.size();
+ for (int i = 0; i < size; i++) {
+ final UserInfo user = mUsers.valueAt(i);
+ if (user.isGuest() && !user.guestToRemove && !mRemovingUserIds.get(user.id)) {
+ return user;
+ }
+ }
+ return null;
+ }
+
+ /**
* Mark this guest user for deletion to allow us to create another guest
* and switch to that user before actually removing this guest.
* @param userHandle the userid of the current guest
@@ -1204,14 +1234,15 @@
if (!user.isGuest()) {
return false;
}
- // Set this to a partially created user, so that the user will be purged
- // on next startup, in case the runtime stops now before stopping and
- // removing the user completely.
- user.partial = true;
+ // We set this to a guest user that is to be removed. This is a temporary state
+ // where we are allowed to add new Guest users, even if this one is still not
+ // removed. This user will still show up in getUserInfo() calls.
+ // If we don't get around to removing this Guest user, it will be purged on next
+ // startup.
+ user.guestToRemove = true;
// Mark it as disabled, so that it isn't returned any more when
// profiles are queried.
user.flags |= UserInfo.FLAG_DISABLED;
- user.flags &= ~UserInfo.FLAG_GUEST;
writeUserLocked(user);
}
} finally {
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 5f97a00..7808800 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -91,8 +91,6 @@
private static final int MSG_SANDMAN = 2;
// Message: Sent when the screen on blocker is released.
private static final int MSG_SCREEN_ON_BLOCKER_RELEASED = 3;
- // Message: Sent to poll whether the boot animation has terminated.
- private static final int MSG_CHECK_IF_BOOT_ANIMATION_FINISHED = 4;
// Dirty bit: mWakeLocks changed
private static final int DIRTY_WAKE_LOCKS = 1 << 0;
@@ -154,12 +152,6 @@
// provider populates the actual default value (R.integer.def_screen_off_timeout).
private static final int DEFAULT_SCREEN_OFF_TIMEOUT = 15 * 1000;
- // The name of the boot animation service in init.rc.
- private static final String BOOT_ANIMATION_SERVICE = "bootanim";
-
- // Poll interval in milliseconds for watching boot animation finished.
- private static final int BOOT_ANIMATION_POLL_INTERVAL = 200;
-
// Power hints defined in hardware/libhardware/include/hardware/power.h.
private static final int POWER_HINT_INTERACTION = 2;
private static final int POWER_HINT_LOW_POWER = 5;
@@ -478,14 +470,15 @@
@Override
public void onBootPhase(int phase) {
- if (phase == PHASE_BOOT_COMPLETED) {
- // This is our early signal that the system thinks it has finished booting.
- // However, the boot animation may still be running for a few more seconds
- // since it is ultimately in charge of when it terminates.
- // Defer transitioning into the boot completed state until the animation exits.
- // We do this so that the screen does not start to dim prematurely before
- // the user has actually had a chance to interact with the device.
- startWatchingForBootAnimationFinished();
+ synchronized (mLock) {
+ if (phase == PHASE_BOOT_COMPLETED) {
+ final long now = SystemClock.uptimeMillis();
+ mBootCompleted = true;
+ mDirty |= DIRTY_BOOT_COMPLETED;
+ userActivityNoUpdateLocked(
+ now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
+ updatePowerStateLocked();
+ }
}
}
@@ -2076,38 +2069,6 @@
updatePowerStateLocked();
}
- private void startWatchingForBootAnimationFinished() {
- mHandler.sendEmptyMessage(MSG_CHECK_IF_BOOT_ANIMATION_FINISHED);
- }
-
- private void checkIfBootAnimationFinished() {
- if (DEBUG) {
- Slog.d(TAG, "Check if boot animation finished...");
- }
-
- if (SystemService.isRunning(BOOT_ANIMATION_SERVICE)) {
- mHandler.sendEmptyMessageDelayed(MSG_CHECK_IF_BOOT_ANIMATION_FINISHED,
- BOOT_ANIMATION_POLL_INTERVAL);
- return;
- }
-
- synchronized (mLock) {
- if (!mBootCompleted) {
- Slog.i(TAG, "Boot animation finished.");
- handleBootCompletedLocked();
- }
- }
- }
-
- private void handleBootCompletedLocked() {
- final long now = SystemClock.uptimeMillis();
- mBootCompleted = true;
- mDirty |= DIRTY_BOOT_COMPLETED;
- userActivityNoUpdateLocked(
- now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
- updatePowerStateLocked();
- }
-
private void shutdownOrRebootInternal(final boolean shutdown, final boolean confirm,
final String reason, boolean wait) {
if (mHandler == null || !mSystemReady) {
@@ -2528,9 +2489,6 @@
case MSG_SCREEN_ON_BLOCKER_RELEASED:
handleScreenOnBlockerReleased();
break;
- case MSG_CHECK_IF_BOOT_ANIMATION_FINISHED:
- checkIfBootAnimationFinished();
- break;
}
}
}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index c8b5b3e..fefbe0a 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -33,6 +33,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
@@ -48,6 +49,7 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.service.trust.TrustAgentService;
import android.util.ArraySet;
import android.util.AttributeSet;
@@ -97,6 +99,7 @@
private final SparseBooleanArray mUserHasAuthenticatedSinceBoot = new SparseBooleanArray();
/* package */ final TrustArchive mArchive = new TrustArchive();
private final Context mContext;
+ private final LockPatternUtils mLockPatternUtils;
private UserManager mUserManager;
@@ -104,6 +107,7 @@
super(context);
mContext = context;
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ mLockPatternUtils = new LockPatternUtils(context);
}
@Override
@@ -116,6 +120,7 @@
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY && !isSafeMode()) {
mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
mReceiver.register(mContext);
+ maybeEnableFactoryTrustAgents(mLockPatternUtils, UserHandle.USER_OWNER);
refreshAgentList(UserHandle.USER_ALL);
}
}
@@ -159,6 +164,11 @@
void refreshAgentList(int userId) {
if (DEBUG) Slog.d(TAG, "refreshAgentList()");
+ if (userId != UserHandle.USER_ALL && userId < UserHandle.USER_OWNER) {
+ Log.e(TAG, "refreshAgentList(userId=" + userId + "): Invalid user handle,"
+ + " must be USER_ALL or a specific user.", new Throwable("here"));
+ userId = UserHandle.USER_ALL;
+ }
PackageManager pm = mContext.getPackageManager();
List<UserInfo> userInfos;
@@ -168,12 +178,13 @@
userInfos = new ArrayList<>();
userInfos.add(mUserManager.getUserInfo(userId));
}
- LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
+ LockPatternUtils lockPatternUtils = mLockPatternUtils;
ArraySet<AgentInfo> obsoleteAgents = new ArraySet<>();
obsoleteAgents.addAll(mActiveAgents);
for (UserInfo userInfo : userInfos) {
+ if (!userInfo.supportsSwitchTo()) continue;
if (lockPatternUtils.getKeyguardStoredPasswordQuality(userInfo.id)
== DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) continue;
if (!mUserHasAuthenticatedSinceBoot.get(userInfo.id)) continue;
@@ -186,22 +197,11 @@
if (enabledAgents == null) {
continue;
}
- List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(TRUST_AGENT_INTENT,
- PackageManager.GET_META_DATA, userInfo.id);
+ List<ResolveInfo> resolveInfos = resolveAllowedTrustAgents(pm, userInfo.id);
for (ResolveInfo resolveInfo : resolveInfos) {
- if (resolveInfo.serviceInfo == null) continue;
-
- String packageName = resolveInfo.serviceInfo.packageName;
- if (pm.checkPermission(PERMISSION_PROVIDE_AGENT, packageName)
- != PackageManager.PERMISSION_GRANTED) {
- Log.w(TAG, "Skipping agent because package " + packageName
- + " does not have permission " + PERMISSION_PROVIDE_AGENT + ".");
- continue;
- }
-
ComponentName name = getComponentName(resolveInfo);
- if (!enabledAgents.contains(name)) continue;
+ if (!enabledAgents.contains(name)) continue;
if (disableTrustAgents) {
List<String> features =
dpm.getTrustAgentFeaturesEnabled(null /* admin */, name);
@@ -228,11 +228,13 @@
boolean trustMayHaveChanged = false;
for (int i = 0; i < obsoleteAgents.size(); i++) {
AgentInfo info = obsoleteAgents.valueAt(i);
- if (info.agent.isManagingTrust()) {
- trustMayHaveChanged = true;
+ if (userId == UserHandle.USER_ALL || userId == info.userId) {
+ if (info.agent.isManagingTrust()) {
+ trustMayHaveChanged = true;
+ }
+ info.agent.unbind();
+ mActiveAgents.remove(info);
}
- info.agent.unbind();
- mActiveAgents.remove(info);
}
if (trustMayHaveChanged) {
@@ -342,6 +344,54 @@
return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
}
+ private void maybeEnableFactoryTrustAgents(LockPatternUtils utils, int userId) {
+ if (0 != Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.TRUST_AGENTS_INITIALIZED, 0, userId)) {
+ return;
+ }
+ PackageManager pm = mContext.getPackageManager();
+ List<ResolveInfo> resolveInfos = resolveAllowedTrustAgents(pm, userId);
+ ArraySet<ComponentName> discoveredAgents = new ArraySet<>();
+ for (ResolveInfo resolveInfo : resolveInfos) {
+ ComponentName componentName = getComponentName(resolveInfo);
+ int applicationInfoFlags = resolveInfo.serviceInfo.applicationInfo.flags;
+ if ((applicationInfoFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ Log.i(TAG, "Leaving agent " + componentName + " disabled because package "
+ + "is not a system package.");
+ continue;
+ }
+ discoveredAgents.add(componentName);
+ }
+
+ List<ComponentName> previouslyEnabledAgents = utils.getEnabledTrustAgents(userId);
+ if (previouslyEnabledAgents != null) {
+ discoveredAgents.addAll(previouslyEnabledAgents);
+ }
+ utils.setEnabledTrustAgents(discoveredAgents, userId);
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.TRUST_AGENTS_INITIALIZED, 1, userId);
+ }
+
+ private List<ResolveInfo> resolveAllowedTrustAgents(PackageManager pm, int userId) {
+ List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(TRUST_AGENT_INTENT,
+ 0 /* flags */, userId);
+ ArrayList<ResolveInfo> allowedAgents = new ArrayList<>(resolveInfos.size());
+ for (ResolveInfo resolveInfo : resolveInfos) {
+ if (resolveInfo.serviceInfo == null) continue;
+ if (resolveInfo.serviceInfo.applicationInfo == null) continue;
+ String packageName = resolveInfo.serviceInfo.packageName;
+ if (pm.checkPermission(PERMISSION_PROVIDE_AGENT, packageName)
+ != PackageManager.PERMISSION_GRANTED) {
+ ComponentName name = getComponentName(resolveInfo);
+ Log.w(TAG, "Skipping agent " + name + " because package does not have"
+ + " permission " + PERMISSION_PROVIDE_AGENT + ".");
+ continue;
+ }
+ allowedAgents.add(resolveInfo);
+ }
+ return allowedAgents;
+ }
+
// Agent dispatch and aggregation
private boolean aggregateIsTrusted(int userId) {
@@ -414,6 +464,7 @@
}
}
mTrustListeners.add(listener);
+ updateTrustAll();
}
private void removeListener(ITrustListener listener) {
@@ -616,12 +667,19 @@
@Override
public void onReceive(Context context, Intent intent) {
- if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(
- intent.getAction())) {
+ String action = intent.getAction();
+ if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action)) {
refreshAgentList(getSendingUserId());
updateDevicePolicyFeatures();
- } else if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
+ } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
updateUserHasAuthenticated(getSendingUserId());
+ } else if (Intent.ACTION_USER_ADDED.equals(action)) {
+ int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -100);
+ if (userId > 0) {
+ maybeEnableFactoryTrustAgents(mLockPatternUtils, userId);
+ } else {
+ Log.wtf(TAG, "EXTRA_USER_HANDLE missing or invalid, value=" + userId);
+ }
}
}
@@ -629,6 +687,7 @@
IntentFilter filter = new IntentFilter();
filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
filter.addAction(Intent.ACTION_USER_PRESENT);
+ filter.addAction(Intent.ACTION_USER_ADDED);
context.registerReceiverAsUser(this,
UserHandle.ALL,
filter,
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 434e48f..54af851 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -21,6 +21,7 @@
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import android.app.AppOpsManager;
import android.os.Build;
+import android.os.SystemService;
import android.util.ArraySet;
import android.util.TimeUtils;
import android.view.IWindowId;
@@ -272,6 +273,12 @@
// Default input dispatching timeout in nanoseconds.
static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L;
+ // Poll interval in milliseconds for watching boot animation finished.
+ private static final int BOOT_ANIMATION_POLL_INTERVAL = 200;
+
+ // The name of the boot animation service in init.rc.
+ private static final String BOOT_ANIMATION_SERVICE = "bootanim";
+
/** Minimum value for attachStack and resizeStack weight value */
public static final float STACK_WEIGHT_MIN = 0.2f;
@@ -458,6 +465,7 @@
boolean mSystemBooted = false;
boolean mForceDisplayEnabled = false;
boolean mShowingBootMessages = false;
+ boolean mBootAnimationStopped = false;
String mLastANRState;
@@ -5607,17 +5615,70 @@
performEnableScreen();
}
+ private boolean checkWaitingForWindowsLocked() {
+
+ boolean haveBootMsg = false;
+ boolean haveApp = false;
+ // if the wallpaper service is disabled on the device, we're never going to have
+ // wallpaper, don't bother waiting for it
+ boolean haveWallpaper = false;
+ boolean wallpaperEnabled = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_enableWallpaperService)
+ && !mOnlyCore;
+ boolean haveKeyguard = true;
+ // TODO(multidisplay): Expand to all displays?
+ final WindowList windows = getDefaultWindowListLocked();
+ final int N = windows.size();
+ for (int i=0; i<N; i++) {
+ WindowState w = windows.get(i);
+ if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
+ return true;
+ }
+ if (w.isDrawnLw()) {
+ if (w.mAttrs.type == TYPE_BOOT_PROGRESS) {
+ haveBootMsg = true;
+ } else if (w.mAttrs.type == TYPE_APPLICATION) {
+ haveApp = true;
+ } else if (w.mAttrs.type == TYPE_WALLPAPER) {
+ haveWallpaper = true;
+ } else if (w.mAttrs.type == TYPE_STATUS_BAR) {
+ haveKeyguard = mPolicy.isKeyguardDrawnLw();
+ }
+ }
+ }
+
+ if (DEBUG_SCREEN_ON || DEBUG_BOOT) {
+ Slog.i(TAG, "******** booted=" + mSystemBooted + " msg=" + mShowingBootMessages
+ + " haveBoot=" + haveBootMsg + " haveApp=" + haveApp
+ + " haveWall=" + haveWallpaper + " wallEnabled=" + wallpaperEnabled
+ + " haveKeyguard=" + haveKeyguard);
+ }
+
+ // If we are turning on the screen to show the boot message,
+ // don't do it until the boot message is actually displayed.
+ if (!mSystemBooted && !haveBootMsg) {
+ return true;
+ }
+
+ // If we are turning on the screen after the boot is completed
+ // normally, don't do so until we have the application and
+ // wallpaper.
+ if (mSystemBooted && ((!haveApp && !haveKeyguard) ||
+ (wallpaperEnabled && !haveWallpaper))) {
+ return true;
+ }
+
+ return false;
+ }
+
public void performEnableScreen() {
synchronized(mWindowMap) {
- if (DEBUG_BOOT) {
- RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
- Slog.i(TAG, "performEnableScreen: mDisplayEnabled=" + mDisplayEnabled
- + " mForceDisplayEnabled=" + mForceDisplayEnabled
- + " mShowingBootMessages=" + mShowingBootMessages
- + " mSystemBooted=" + mSystemBooted
- + " mOnlyCore=" + mOnlyCore, here);
- }
+ if (DEBUG_BOOT) Slog.i(TAG, "performEnableScreen: mDisplayEnabled=" + mDisplayEnabled
+ + " mForceDisplayEnabled=" + mForceDisplayEnabled
+ + " mShowingBootMessages=" + mShowingBootMessages
+ + " mSystemBooted=" + mSystemBooted
+ + " mOnlyCore=" + mOnlyCore,
+ new RuntimeException("here").fillInStackTrace());
if (mDisplayEnabled) {
return;
}
@@ -5625,94 +5686,64 @@
return;
}
- if (!mForceDisplayEnabled) {
- // Don't enable the screen until all existing windows
- // have been drawn.
- boolean haveBootMsg = false;
- boolean haveApp = false;
- // if the wallpaper service is disabled on the device, we're never going to have
- // wallpaper, don't bother waiting for it
- boolean haveWallpaper = false;
- boolean wallpaperEnabled = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_enableWallpaperService)
- && !mOnlyCore;
- boolean haveKeyguard = true;
- // TODO(multidisplay): Expand to all displays?
- final WindowList windows = getDefaultWindowListLocked();
- final int N = windows.size();
- for (int i=0; i<N; i++) {
- WindowState w = windows.get(i);
- if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
- return;
+ // Don't enable the screen until all existing windows have been drawn.
+ if (!mForceDisplayEnabled && checkWaitingForWindowsLocked()) {
+ return;
+ }
+
+ if (!mBootAnimationStopped) {
+ // Do this one time.
+ try {
+ IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
+ if (surfaceFlinger != null) {
+ //Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken("android.ui.ISurfaceComposer");
+ surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
+ data, null, 0);
+ data.recycle();
}
- if (w.isDrawnLw()) {
- if (w.mAttrs.type == TYPE_BOOT_PROGRESS) {
- haveBootMsg = true;
- } else if (w.mAttrs.type == TYPE_APPLICATION) {
- haveApp = true;
- } else if (w.mAttrs.type == TYPE_WALLPAPER) {
- haveWallpaper = true;
- } else if (w.mAttrs.type == TYPE_STATUS_BAR) {
- haveKeyguard = mPolicy.isKeyguardDrawnLw();
- }
- }
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
}
+ mBootAnimationStopped = true;
+ }
- if (DEBUG_SCREEN_ON || DEBUG_BOOT) {
- Slog.i(TAG, "******** booted=" + mSystemBooted + " msg=" + mShowingBootMessages
- + " haveBoot=" + haveBootMsg + " haveApp=" + haveApp
- + " haveWall=" + haveWallpaper + " wallEnabled=" + wallpaperEnabled
- + " haveKeyguard=" + haveKeyguard);
- }
-
- // If we are turning on the screen to show the boot message,
- // don't do it until the boot message is actually displayed.
- if (!mSystemBooted && !haveBootMsg) {
- return;
- }
-
- // If we are turning on the screen after the boot is completed
- // normally, don't do so until we have the application and
- // wallpaper.
- if (mSystemBooted && ((!haveApp && !haveKeyguard) ||
- (wallpaperEnabled && !haveWallpaper))) {
- return;
- }
+ if (!mForceDisplayEnabled && !checkBootAnimationCompleteLocked()) {
+ if (DEBUG_BOOT) Slog.i(TAG, "performEnableScreen: Waiting for anim complete");
+ return;
}
mDisplayEnabled = true;
if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG, "******************** ENABLING SCREEN!");
- if (false) {
- StringWriter sw = new StringWriter();
- PrintWriter pw = new FastPrintWriter(sw, false, 1024);
- this.dump(null, pw, null);
- pw.flush();
- Slog.i(TAG, sw.toString());
- }
- try {
- IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
- if (surfaceFlinger != null) {
- //Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
- Parcel data = Parcel.obtain();
- data.writeInterfaceToken("android.ui.ISurfaceComposer");
- surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
- data, null, 0);
- data.recycle();
- }
- } catch (RemoteException ex) {
- Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
- }
// Enable input dispatch.
mInputMonitor.setEventDispatchingLw(mEventDispatchingEnabled);
}
+ try {
+ mActivityManager.bootAnimationComplete();
+ } catch (RemoteException e) {
+ }
+
mPolicy.enableScreenAfterBoot();
// Make sure the last requested orientation has been applied.
updateRotationUnchecked(false, false);
}
+ private boolean checkBootAnimationCompleteLocked() {
+ if (SystemService.isRunning(BOOT_ANIMATION_SERVICE)) {
+ mH.removeMessages(H.CHECK_IF_BOOT_ANIMATION_FINISHED);
+ mH.sendEmptyMessageDelayed(H.CHECK_IF_BOOT_ANIMATION_FINISHED,
+ BOOT_ANIMATION_POLL_INTERVAL);
+ if (DEBUG_BOOT) Slog.i(TAG, "checkBootAnimationComplete: Waiting for anim complete");
+ return false;
+ }
+ if (DEBUG_BOOT) Slog.i(TAG, "checkBootAnimationComplete: Animation complete!");
+ return true;
+ }
+
public void showBootMessage(final CharSequence msg, final boolean always) {
boolean first = false;
synchronized(mWindowMap) {
@@ -5931,7 +5962,7 @@
@Override
public Bitmap screenshotApplications(IBinder appToken, int displayId, int width,
int height, boolean force565) {
- if (!checkCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
+ if (!checkCallingPermission(Manifest.permission.READ_FRAME_BUFFER,
"screenshotApplications()")) {
throw new SecurityException("Requires READ_FRAME_BUFFER permission");
}
@@ -5951,7 +5982,7 @@
return null;
}
- Bitmap rawss = null;
+ Bitmap bm = null;
int maxLayer = 0;
final Rect frame = new Rect();
@@ -6092,10 +6123,8 @@
// The screenshot API does not apply the current screen rotation.
rot = getDefaultDisplayContentLocked().getDisplay().getRotation();
+
if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
- final int tmp = width;
- width = height;
- height = tmp;
rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
}
@@ -6121,9 +6150,9 @@
if (DEBUG_SCREENSHOT && inRotation) Slog.v(TAG,
"Taking screenshot while rotating");
- rawss = SurfaceControl.screenshot(crop, width, height, minLayer, maxLayer,
- inRotation);
- if (rawss == null) {
+ bm = SurfaceControl.screenshot(crop, width, height, minLayer, maxLayer,
+ inRotation, rot);
+ if (bm == null) {
Slog.w(TAG, "Screenshot failure taking screenshot for (" + dw + "x" + dh
+ ") to layer " + maxLayer);
return null;
@@ -6133,17 +6162,6 @@
break;
}
- Bitmap bm = Bitmap.createBitmap(width, height, force565 ?
- Config.RGB_565 : rawss.getConfig());
- if (DEBUG_SCREENSHOT) {
- bm.eraseColor(0xFF000000);
- }
- Matrix matrix = new Matrix();
- ScreenRotationAnimation.createRotationMatrix(rot, width, height, matrix);
- Canvas canvas = new Canvas(bm);
- canvas.drawBitmap(rawss, matrix, null);
- canvas.setBitmap(null);
-
if (DEBUG_SCREENSHOT) {
// TEST IF IT's ALL BLACK
int[] buffer = new int[bm.getWidth() * bm.getHeight()];
@@ -6164,9 +6182,12 @@
}
}
- rawss.recycle();
-
- return bm;
+ // Copy the screenshot bitmap to another buffer so that the gralloc backed
+ // bitmap will not have a long lifetime. Gralloc memory can be pinned or
+ // duplicated and might have a higher cost than a skia backed buffer.
+ Bitmap ret = bm.copy(bm.getConfig(),true);
+ bm.recycle();
+ return ret;
}
/**
@@ -7467,6 +7488,8 @@
public static final int SHOW_CIRCULAR_DISPLAY_MASK = 35;
public static final int SHOW_EMULATOR_DISPLAY_OVERLAY = 36;
+ public static final int CHECK_IF_BOOT_ANIMATION_FINISHED = 37;
+
@Override
public void handleMessage(Message msg) {
if (DEBUG_WINDOW_TRACE) {
@@ -7951,6 +7974,17 @@
}
}
break;
+ case CHECK_IF_BOOT_ANIMATION_FINISHED: {
+ final boolean bootAnimationComplete;
+ synchronized (mWindowMap) {
+ if (DEBUG_BOOT) Slog.i(TAG, "CHECK_IF_BOOT_ANIMATION_FINISHED:");
+ bootAnimationComplete = checkBootAnimationCompleteLocked();
+ }
+ if (bootAnimationComplete) {
+ performEnableScreen();
+ }
+ }
+ break;
}
if (DEBUG_WINDOW_TRACE) {
Slog.v(TAG, "handleMessage: exit");
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 1f377c7..d81cdd9 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -11,7 +11,6 @@
$(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
$(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
$(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecController.cpp \
- $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiMhlController.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 39b70a8..7b2e408 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -38,7 +38,6 @@
int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
int register_android_server_connectivity_Vpn(JNIEnv* env);
int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
-int register_android_server_hdmi_HdmiMhlController(JNIEnv* env);
int register_android_server_tv_TvInputHal(JNIEnv* env);
int register_android_server_PersistentDataBlockService(JNIEnv* env);
int register_android_server_fingerprint_FingerprintService(JNIEnv* env);
@@ -76,7 +75,6 @@
register_android_server_ConsumerIrService(env);
register_android_server_BatteryStatsService(env);
register_android_server_hdmi_HdmiCecController(env);
- register_android_server_hdmi_HdmiMhlController(env);
register_android_server_tv_TvInputHal(env);
register_android_server_PersistentDataBlockService(env);
register_android_server_fingerprint_FingerprintService(env);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
index 376230b..ad38b22 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java
@@ -67,7 +67,7 @@
final ModuleProperties moduleProperties;
/** The properties for the DSP module */
- private final SoundTriggerModule mModule;
+ private SoundTriggerModule mModule;
private final Object mLock = new Object();
private final Context mContext;
private final TelephonyManager mTelephonyManager;
@@ -105,7 +105,6 @@
} else {
// TODO: Figure out how to determine which module corresponds to the DSP hardware.
moduleProperties = modules.get(0);
- mModule = SoundTrigger.attachModule(moduleProperties.id, this, null);
}
}
@@ -155,10 +154,17 @@
mIsPowerSaveMode = mPowerManager.isPowerSaveMode();
}
- if (moduleProperties == null || mModule == null) {
+ if (moduleProperties == null) {
Slog.w(TAG, "Attempting startRecognition without the capability");
return STATUS_ERROR;
}
+ if (mModule == null) {
+ mModule = SoundTrigger.attachModule(moduleProperties.id, this, null);
+ if (mModule == null) {
+ Slog.w(TAG, "startRecognition cannot attach to sound trigger module");
+ return STATUS_ERROR;
+ }
+ }
if (mCurrentSoundModelHandle != INVALID_VALUE
&& !soundModel.uuid.equals(mCurrentSoundModelUuid)) {
@@ -446,6 +452,10 @@
Slog.w(TAG, "RemoteException in onError", e);
} finally {
internalClearStateLocked();
+ if (mModule != null) {
+ mModule.detach();
+ mModule = null;
+ }
}
}
diff --git a/telecomm/java/android/telecomm/Conference.java b/telecomm/java/android/telecomm/Conference.java
index f9c3ac3..a4f9c2c 100644
--- a/telecomm/java/android/telecomm/Conference.java
+++ b/telecomm/java/android/telecomm/Conference.java
@@ -50,22 +50,47 @@
private int mCapabilities;
private String mDisconnectMessage;
+ /**
+ * Constructs a new Conference with a mandatory {@link PhoneAccountHandle}
+ *
+ * @param phoneAccount The {@code PhoneAccountHandle} associated with the conference.
+ */
public Conference(PhoneAccountHandle phoneAccount) {
mPhoneAccount = phoneAccount;
}
+ /**
+ * Returns the {@link PhoneAccountHandle} the conference call is being placed through.
+ *
+ * @return A {@code PhoneAccountHandle} object representing the PhoneAccount of the conference.
+ */
public final PhoneAccountHandle getPhoneAccountHandle() {
return mPhoneAccount;
}
+ /**
+ * Returns the list of connections currently associated with the conference call.
+ *
+ * @return A list of {@code Connection} objects which represent the children of the conference.
+ */
public final List<Connection> getConnections() {
return mUnmodifiableChildConnections;
}
+ /**
+ * Gets the state of the conference call. See {@link Connection} for valid values.
+ *
+ * @return A constant representing the state the conference call is currently in.
+ */
public final int getState() {
return mState;
}
+ /**
+ * Returns the capabilities of a conference. See {@link PhoneCapabilities} for valid values.
+ *
+ * @return A bitmask of the {@code PhoneCapabilities} of the conference call.
+ */
public final int getCapabilities() {
return mCapabilities;
}
@@ -135,7 +160,9 @@
}
/**
- * Sets the capabilities of a conference.
+ * Sets the capabilities of a conference. See {@link PhoneCapabilities} for valid values.
+ *
+ * @param capabilities A bitmask of the {@code PhoneCapabilities} of the conference call.
*/
public final void setCapabilities(int capabilities) {
if (capabilities != mCapabilities) {
@@ -170,7 +197,6 @@
* Removes the specified connection as a child of this conference.
*
* @param connection The connection to remove.
- * @return True if the connection was successfully removed.
*/
public final void removeConnection(Connection connection) {
Log.d(this, "removing %s from %s", connection, mChildConnections);
diff --git a/telecomm/java/android/telecomm/PhoneAccount.java b/telecomm/java/android/telecomm/PhoneAccount.java
index d3da2ec..f709a86 100644
--- a/telecomm/java/android/telecomm/PhoneAccount.java
+++ b/telecomm/java/android/telecomm/PhoneAccount.java
@@ -246,7 +246,6 @@
* {@link #getAddress()}. For the majority of {@code PhoneAccount}s this should be registered
* as {@code null}. It is used by the system for SIM-based {@code PhoneAccount} registration
* where {@link android.telephony.TelephonyManager#setLine1NumberForDisplay(String, String)}
- * or {@link android.telephony.TelephonyManager#setLine1NumberForDisplay(long, String, String)}
* has been used to alter the callback number.
* <p>
*
diff --git a/telecomm/java/android/telecomm/RemoteConnectionService.java b/telecomm/java/android/telecomm/RemoteConnectionService.java
index 348c36c..8b8e8eb 100644
--- a/telecomm/java/android/telecomm/RemoteConnectionService.java
+++ b/telecomm/java/android/telecomm/RemoteConnectionService.java
@@ -60,13 +60,14 @@
if (connection != NULL_CONNECTION && mPendingConnections.contains(connection)) {
mPendingConnections.remove(connection);
// Unconditionally initialize the connection ...
- connection.setState(parcel.getState());
connection.setCallCapabilities(parcel.getCapabilities());
connection.setHandle(
parcel.getHandle(), parcel.getHandlePresentation());
connection.setCallerDisplayName(
parcel.getCallerDisplayName(),
parcel.getCallerDisplayNamePresentation());
+ // Set state after handle so that the client can identify the connection.
+ connection.setState(parcel.getState());
List<RemoteConnection> conferenceable = new ArrayList<>();
for (String confId : parcel.getConferenceableConnectionIds()) {
if (mConnectionById.containsKey(confId)) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 164fc3c..d53be4f 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1704,7 +1704,7 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getLine1Number() {
- return getLine1Number(getDefaultSubscription());
+ return getLine1NumberForSubscriber(getDefaultSubscription());
}
/**
@@ -1717,7 +1717,7 @@
* @param subId whose phone number for line 1 is returned
*/
/** {@hide} */
- public String getLine1Number(long subId) {
+ public String getLine1NumberForSubscriber(long subId) {
String number = null;
try {
number = getITelephony().getLine1NumberForDisplay(subId);
@@ -1751,7 +1751,7 @@
* @param number The dialing number
*/
public void setLine1NumberForDisplay(String alphaTag, String number) {
- setLine1NumberForDisplay(getDefaultSubscription(), alphaTag, number);
+ setLine1NumberForDisplayForSubscriber(getDefaultSubscription(), alphaTag, number);
}
/**
@@ -1767,10 +1767,11 @@
* @param subId the subscriber that the alphatag and dialing number belongs to.
* @param alphaTag alpha-tagging of the dailing nubmer
* @param number The dialing number
+ * @hide
*/
- public void setLine1NumberForDisplay(long subId, String alphaTag, String number) {
+ public void setLine1NumberForDisplayForSubscriber(long subId, String alphaTag, String number) {
try {
- getITelephony().setLine1NumberForDisplay(subId, alphaTag, number);
+ getITelephony().setLine1NumberForDisplayForSubscriber(subId, alphaTag, number);
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
}
@@ -1786,7 +1787,7 @@
* nobody seems to call this.
*/
public String getLine1AlphaTag() {
- return getLine1AlphaTag(getDefaultSubscription());
+ return getLine1AlphaTagForSubscriber(getDefaultSubscription());
}
/**
@@ -1800,7 +1801,7 @@
* nobody seems to call this.
*/
/** {@hide} */
- public String getLine1AlphaTag(long subId) {
+ public String getLine1AlphaTagForSubscriber(long subId) {
String alphaTag = null;
try {
alphaTag = getITelephony().getLine1AlphaTagForDisplay(subId);
@@ -3369,7 +3370,7 @@
* @hide
*/
public void enableSimplifiedNetworkSettings(boolean enable) {
- enableSimplifiedNetworkSettings(getDefaultSubscription(), enable);
+ enableSimplifiedNetworkSettingsForSubscriber(getDefaultSubscription(), enable);
}
/**
@@ -3384,9 +3385,9 @@
* @param enable true means enabling the simplified UI.
* @hide
*/
- public void enableSimplifiedNetworkSettings(long subId, boolean enable) {
+ public void enableSimplifiedNetworkSettingsForSubscriber(long subId, boolean enable) {
try {
- getITelephony().enableSimplifiedNetworkSettings(subId, enable);
+ getITelephony().enableSimplifiedNetworkSettingsForSubscriber(subId, enable);
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
}
@@ -3402,7 +3403,7 @@
* @hide
*/
public boolean getSimplifiedNetworkSettingsEnabled() {
- return getSimplifiedNetworkSettingsEnabled(getDefaultSubscription());
+ return getSimplifiedNetworkSettingsEnabledForSubscriber(getDefaultSubscription());
}
/**
@@ -3415,9 +3416,9 @@
* @return true if the simplified UI is enabled.
* @hide
*/
- public boolean getSimplifiedNetworkSettingsEnabled(long subId) {
+ public boolean getSimplifiedNetworkSettingsEnabledForSubscriber(long subId) {
try {
- return getITelephony().getSimplifiedNetworkSettingsEnabled(subId);
+ return getITelephony().getSimplifiedNetworkSettingsEnabledForSubscriber(subId);
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 5b280ff..fa9cad4 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -715,7 +715,7 @@
* @param subId for which the simplified UI should be enabled or disabled.
* @param enable true means enabling the simplified UI.
*/
- void enableSimplifiedNetworkSettings(long subId, boolean enable);
+ void enableSimplifiedNetworkSettingsForSubscriber(long subId, boolean enable);
/**
* Get whether a simplified Mobile Network Settings UI is enabled.
@@ -723,7 +723,7 @@
* @param subId for which the simplified UI should be enabled or disabled.
* @return true if the simplified UI is enabled.
*/
- boolean getSimplifiedNetworkSettingsEnabled(long subId);
+ boolean getSimplifiedNetworkSettingsEnabledForSubscriber(long subId);
/**
* Set the phone number string and its alphatag for line 1 for display
@@ -735,7 +735,7 @@
* @param alphaTag alpha-tagging of the dailing nubmer
* @param number The dialing number
*/
- void setLine1NumberForDisplay(long subId, String alphaTag, String number);
+ void setLine1NumberForDisplayForSubscriber(long subId, String alphaTag, String number);
/**
* Returns the displayed dialing number string if it was set previously via
diff --git a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
index 5bf59c7..a2e9117 100644
--- a/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
+++ b/tests/Compatibility/src/com/android/compatibilitytest/AppCompatibility.java
@@ -208,6 +208,12 @@
Log.d(TAG, "Found process " + app.processName);
return true;
}
+ for (String relatedPackage : app.pkgList) {
+ if (relatedPackage.equalsIgnoreCase(processName)) {
+ Log.d(TAG, "Found process " + app.processName);
+ return true;
+ }
+ }
}
Log.d(TAG, "Failed to find process " + processName + " with package name "
+ packageName);
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index b3c364b..8341de6 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -2574,8 +2574,12 @@
continue;
}
const size_t N = t->getOrderedConfigs().size();
- sp<AaptSymbols> typeSymbols;
- typeSymbols = outSymbols->addNestedSymbol(String8(t->getName()), t->getPos());
+ sp<AaptSymbols> typeSymbols =
+ outSymbols->addNestedSymbol(String8(t->getName()), t->getPos());
+ if (typeSymbols == NULL) {
+ return UNKNOWN_ERROR;
+ }
+
for (size_t ci=0; ci<N; ci++) {
sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci);
if (c == NULL) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 130500a..0ed6ab1 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -174,6 +174,11 @@
}
@Override
+ public void setWallpaperDisplayOffset(IBinder windowToken, int x, int y) {
+ // pass for now.
+ }
+
+ @Override
public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
int z, Bundle extras, boolean sync) {
// pass for now.
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 21f200f..aeaff71 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -367,9 +367,9 @@
/**
* @hide
- * Uid of app owning the BSSID
+ * Uid used by autoJoin
*/
- public int bssidOwnerUid;
+ public String autoJoinBSSID;
/**
* @hide
@@ -467,8 +467,10 @@
public int rssi24; // strongest 2.4GHz RSSI
public int num5; // number of BSSIDs on 5GHz
public int num24; // number of BSSIDs on 2.4GHz
- public long age5; // timestamp of the strongest 5GHz BSSID (last time it was seen)
- public long age24; // timestamp of the strongest 2.4GHz BSSID (last time it was seen)
+ public long age5; // timestamp of the strongest 5GHz BSSID (last time it was seen)
+ public long age24; // timestamp of the strongest 2.4GHz BSSID (last time it was seen)
+ public String BSSID24;
+ public String BSSID5;
public Visibility() {
rssi5 = INVALID_RSSI;
@@ -482,6 +484,8 @@
age5 = source.age5;
num24 = source.num24;
num5 = source.num5;
+ BSSID5 = source.BSSID5;
+ BSSID24 = source.BSSID24;
}
@Override
@@ -492,6 +496,7 @@
sbuf.append(Integer.toString(rssi24));
sbuf.append(",");
sbuf.append(Integer.toString(num24));
+ if (BSSID24 != null) sbuf.append(",").append(BSSID24);
} else {
sbuf.append("*");
}
@@ -500,6 +505,7 @@
sbuf.append(Integer.toString(rssi5));
sbuf.append(",");
sbuf.append(Integer.toString(num5));
+ if (BSSID5 != null) sbuf.append(",").append(BSSID5);
}
sbuf.append("]");
return sbuf.toString();
@@ -549,11 +555,13 @@
if (result.level > status.rssi5) {
status.rssi5 = result.level;
status.age5 = result.seen;
+ status.BSSID5 = result.BSSID;
}
} else if (result.is24GHz()) {
if (result.level > status.rssi24) {
status.rssi24 = result.level;
status.age24 = result.seen;
+ status.BSSID24 = result.BSSID;
}
}
}
@@ -949,7 +957,7 @@
sbuf.append(mIpConfiguration.toString());
if (this.creatorUid != 0) sbuf.append("uid=" + Integer.toString(creatorUid));
-
+ if (this.autoJoinBSSID != null) sbuf.append("autoJoinBSSID=" + autoJoinBSSID);
if (this.blackListTimestamp != 0) {
long now_ms = System.currentTimeMillis();
long diff = now_ms - this.blackListTimestamp;
@@ -1284,7 +1292,6 @@
didSelfAdd = source.didSelfAdd;
lastConnectUid = source.lastConnectUid;
lastUpdateUid = source.lastUpdateUid;
- bssidOwnerUid = source.bssidOwnerUid;
creatorUid = source.creatorUid;
peerWifiConfiguration = source.peerWifiConfiguration;
blackListTimestamp = source.blackListTimestamp;
@@ -1302,6 +1309,7 @@
numTicksAtBadRSSI = source.numTicksAtBadRSSI;
numTicksAtNotHighRSSI = source.numTicksAtNotHighRSSI;
numUserTriggeredJoinAttempts = source.numUserTriggeredJoinAttempts;
+ autoJoinBSSID = source.autoJoinBSSID;
}
}
@@ -1318,6 +1326,7 @@
dest.writeInt(disableReason);
dest.writeString(SSID);
dest.writeString(BSSID);
+ dest.writeString(autoJoinBSSID);
dest.writeString(FQDN);
dest.writeString(naiRealm);
dest.writeString(preSharedKey);
@@ -1348,7 +1357,6 @@
dest.writeInt(creatorUid);
dest.writeInt(lastConnectUid);
dest.writeInt(lastUpdateUid);
- dest.writeInt(bssidOwnerUid);
dest.writeLong(blackListTimestamp);
dest.writeLong(lastConnectionFailure);
dest.writeInt(numConnectionFailures);
@@ -1375,6 +1383,7 @@
config.disableReason = in.readInt();
config.SSID = in.readString();
config.BSSID = in.readString();
+ config.autoJoinBSSID = in.readString();
config.FQDN = in.readString();
config.naiRealm = in.readString();
config.preSharedKey = in.readString();
@@ -1405,7 +1414,6 @@
config.creatorUid = in.readInt();
config.lastConnectUid = in.readInt();
config.lastUpdateUid = in.readInt();
- config.bssidOwnerUid = in.readInt();
config.blackListTimestamp = in.readLong();
config.lastConnectionFailure = in.readLong();
config.numConnectionFailures = in.readInt();
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 65c00bd..aaa2f98 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -76,6 +76,8 @@
public static final int REASON_INVALID_LISTENER = -2;
/** Invalid request */
public static final int REASON_INVALID_REQUEST = -3;
+ /** Invalid request */
+ public static final int REASON_NOT_AUTHORIZED = -4;
/** @hide */
public static final String GET_AVAILABLE_CHANNELS_EXTRA = "Channels";