Merge "Make AccountManagerServiceTest work again" into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index 53738dc..732c500 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -19857,8 +19857,8 @@
public class AudioRecord implements android.media.AudioRouting {
ctor public AudioRecord(int, int, int, int, int) throws java.lang.IllegalArgumentException;
+ method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public deprecated void addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler);
- method public void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public int getAudioFormat();
method public int getAudioSessionId();
method public int getAudioSource();
@@ -19883,8 +19883,8 @@
method public int read(java.nio.ByteBuffer, int);
method public int read(java.nio.ByteBuffer, int, int);
method public void release();
+ method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
method public deprecated void removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener);
- method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
method public int setNotificationMarkerPosition(int);
method public int setPositionNotificationPeriod(int);
method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
@@ -19918,8 +19918,9 @@
method public abstract void onPeriodicNotification(android.media.AudioRecord);
}
- public static abstract interface AudioRecord.OnRoutingChangedListener {
+ public static abstract deprecated interface AudioRecord.OnRoutingChangedListener implements android.media.AudioRouting.OnRoutingChangedListener {
method public abstract void onRoutingChanged(android.media.AudioRecord);
+ method public default void onRoutingChanged(android.media.AudioRouting);
}
public final class AudioRecordingConfiguration implements android.os.Parcelable {
@@ -19934,10 +19935,10 @@
}
public abstract interface AudioRouting {
- method public abstract void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
+ method public abstract void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public abstract android.media.AudioDeviceInfo getPreferredDevice();
method public abstract android.media.AudioDeviceInfo getRoutedDevice();
- method public abstract void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
+ method public abstract void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
method public abstract boolean setPreferredDevice(android.media.AudioDeviceInfo);
}
@@ -19957,8 +19958,8 @@
ctor public AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
ctor public AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
+ method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
- method public void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public int attachAuxEffect(int);
method public void flush();
method public int getAudioFormat();
@@ -19990,8 +19991,8 @@
method public void play() throws java.lang.IllegalStateException;
method public void release();
method public int reloadStaticData();
+ method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
method public deprecated void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
- method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
method public int setAuxEffectSendLevel(float);
method public int setBufferSizeInFrames(int);
method public int setLoopPoints(int, int, int);
@@ -20045,8 +20046,9 @@
method public abstract void onPeriodicNotification(android.media.AudioTrack);
}
- public static abstract deprecated interface AudioTrack.OnRoutingChangedListener {
- method public abstract deprecated void onRoutingChanged(android.media.AudioTrack);
+ public static abstract deprecated interface AudioTrack.OnRoutingChangedListener implements android.media.AudioRouting.OnRoutingChangedListener {
+ method public abstract void onRoutingChanged(android.media.AudioTrack);
+ method public default void onRoutingChanged(android.media.AudioRouting);
}
public class CamcorderProfile {
@@ -20722,10 +20724,12 @@
field public static final int VP9Level6 = 1024; // 0x400
field public static final int VP9Level61 = 2048; // 0x800
field public static final int VP9Level62 = 4096; // 0x1000
- field public static final int VP9Profile0 = 0; // 0x0
- field public static final int VP9Profile1 = 1; // 0x1
- field public static final int VP9Profile2 = 2; // 0x2
- field public static final int VP9Profile3 = 3; // 0x3
+ field public static final int VP9Profile0 = 1; // 0x1
+ field public static final int VP9Profile1 = 2; // 0x2
+ field public static final int VP9Profile2 = 4; // 0x4
+ field public static final int VP9Profile2HDR = 4096; // 0x1000
+ field public static final int VP9Profile3 = 8; // 0x8
+ field public static final int VP9Profile3HDR = 8192; // 0x2000
field public int level;
field public int profile;
}
diff --git a/api/system-current.txt b/api/system-current.txt
index ea83257..56b2f58 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -21336,8 +21336,8 @@
public class AudioRecord implements android.media.AudioRouting {
ctor public AudioRecord(int, int, int, int, int) throws java.lang.IllegalArgumentException;
ctor public AudioRecord(android.media.AudioAttributes, android.media.AudioFormat, int, int) throws java.lang.IllegalArgumentException;
+ method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public deprecated void addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler);
- method public void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public int getAudioFormat();
method public int getAudioSessionId();
method public int getAudioSource();
@@ -21362,8 +21362,8 @@
method public int read(java.nio.ByteBuffer, int);
method public int read(java.nio.ByteBuffer, int, int);
method public void release();
+ method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
method public deprecated void removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener);
- method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
method public int setNotificationMarkerPosition(int);
method public int setPositionNotificationPeriod(int);
method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
@@ -21399,8 +21399,9 @@
method public abstract void onPeriodicNotification(android.media.AudioRecord);
}
- public static abstract interface AudioRecord.OnRoutingChangedListener {
+ public static abstract deprecated interface AudioRecord.OnRoutingChangedListener implements android.media.AudioRouting.OnRoutingChangedListener {
method public abstract void onRoutingChanged(android.media.AudioRecord);
+ method public default void onRoutingChanged(android.media.AudioRouting);
}
public final class AudioRecordingConfiguration implements android.os.Parcelable {
@@ -21415,10 +21416,10 @@
}
public abstract interface AudioRouting {
- method public abstract void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
+ method public abstract void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public abstract android.media.AudioDeviceInfo getPreferredDevice();
method public abstract android.media.AudioDeviceInfo getRoutedDevice();
- method public abstract void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
+ method public abstract void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
method public abstract boolean setPreferredDevice(android.media.AudioDeviceInfo);
}
@@ -21438,8 +21439,8 @@
ctor public AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
ctor public AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
+ method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
- method public void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public int attachAuxEffect(int);
method public void flush();
method public int getAudioFormat();
@@ -21471,8 +21472,8 @@
method public void play() throws java.lang.IllegalStateException;
method public void release();
method public int reloadStaticData();
+ method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
method public deprecated void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
- method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
method public int setAuxEffectSendLevel(float);
method public int setBufferSizeInFrames(int);
method public int setLoopPoints(int, int, int);
@@ -21526,8 +21527,9 @@
method public abstract void onPeriodicNotification(android.media.AudioTrack);
}
- public static abstract deprecated interface AudioTrack.OnRoutingChangedListener {
- method public abstract deprecated void onRoutingChanged(android.media.AudioTrack);
+ public static abstract deprecated interface AudioTrack.OnRoutingChangedListener implements android.media.AudioRouting.OnRoutingChangedListener {
+ method public abstract void onRoutingChanged(android.media.AudioTrack);
+ method public default void onRoutingChanged(android.media.AudioRouting);
}
public class CamcorderProfile {
@@ -22203,10 +22205,12 @@
field public static final int VP9Level6 = 1024; // 0x400
field public static final int VP9Level61 = 2048; // 0x800
field public static final int VP9Level62 = 4096; // 0x1000
- field public static final int VP9Profile0 = 0; // 0x0
- field public static final int VP9Profile1 = 1; // 0x1
- field public static final int VP9Profile2 = 2; // 0x2
- field public static final int VP9Profile3 = 3; // 0x3
+ field public static final int VP9Profile0 = 1; // 0x1
+ field public static final int VP9Profile1 = 2; // 0x2
+ field public static final int VP9Profile2 = 4; // 0x4
+ field public static final int VP9Profile2HDR = 4096; // 0x1000
+ field public static final int VP9Profile3 = 8; // 0x8
+ field public static final int VP9Profile3HDR = 8192; // 0x2000
field public int level;
field public int profile;
}
diff --git a/api/test-current.txt b/api/test-current.txt
index caf3231..e837cd0 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -19923,8 +19923,8 @@
public class AudioRecord implements android.media.AudioRouting {
ctor public AudioRecord(int, int, int, int, int) throws java.lang.IllegalArgumentException;
+ method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public deprecated void addOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener, android.os.Handler);
- method public void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public int getAudioFormat();
method public int getAudioSessionId();
method public int getAudioSource();
@@ -19949,8 +19949,8 @@
method public int read(java.nio.ByteBuffer, int);
method public int read(java.nio.ByteBuffer, int, int);
method public void release();
+ method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
method public deprecated void removeOnRoutingChangedListener(android.media.AudioRecord.OnRoutingChangedListener);
- method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
method public int setNotificationMarkerPosition(int);
method public int setPositionNotificationPeriod(int);
method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
@@ -19984,8 +19984,9 @@
method public abstract void onPeriodicNotification(android.media.AudioRecord);
}
- public static abstract interface AudioRecord.OnRoutingChangedListener {
+ public static abstract deprecated interface AudioRecord.OnRoutingChangedListener implements android.media.AudioRouting.OnRoutingChangedListener {
method public abstract void onRoutingChanged(android.media.AudioRecord);
+ method public default void onRoutingChanged(android.media.AudioRouting);
}
public final class AudioRecordingConfiguration implements android.os.Parcelable {
@@ -20000,10 +20001,10 @@
}
public abstract interface AudioRouting {
- method public abstract void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
+ method public abstract void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public abstract android.media.AudioDeviceInfo getPreferredDevice();
method public abstract android.media.AudioDeviceInfo getRoutedDevice();
- method public abstract void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
+ method public abstract void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
method public abstract boolean setPreferredDevice(android.media.AudioDeviceInfo);
}
@@ -20023,8 +20024,8 @@
ctor public AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
ctor public AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
+ method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
- method public void addOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public int attachAuxEffect(int);
method public void flush();
method public int getAudioFormat();
@@ -20056,8 +20057,8 @@
method public void play() throws java.lang.IllegalStateException;
method public void release();
method public int reloadStaticData();
+ method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
method public deprecated void removeOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener);
- method public void removeOnRoutingListener(android.media.AudioRouting.OnRoutingChangedListener);
method public int setAuxEffectSendLevel(float);
method public int setBufferSizeInFrames(int);
method public int setLoopPoints(int, int, int);
@@ -20111,8 +20112,9 @@
method public abstract void onPeriodicNotification(android.media.AudioTrack);
}
- public static abstract deprecated interface AudioTrack.OnRoutingChangedListener {
- method public abstract deprecated void onRoutingChanged(android.media.AudioTrack);
+ public static abstract deprecated interface AudioTrack.OnRoutingChangedListener implements android.media.AudioRouting.OnRoutingChangedListener {
+ method public abstract void onRoutingChanged(android.media.AudioTrack);
+ method public default void onRoutingChanged(android.media.AudioRouting);
}
public class CamcorderProfile {
@@ -20788,10 +20790,12 @@
field public static final int VP9Level6 = 1024; // 0x400
field public static final int VP9Level61 = 2048; // 0x800
field public static final int VP9Level62 = 4096; // 0x1000
- field public static final int VP9Profile0 = 0; // 0x0
- field public static final int VP9Profile1 = 1; // 0x1
- field public static final int VP9Profile2 = 2; // 0x2
- field public static final int VP9Profile3 = 3; // 0x3
+ field public static final int VP9Profile0 = 1; // 0x1
+ field public static final int VP9Profile1 = 2; // 0x2
+ field public static final int VP9Profile2 = 4; // 0x4
+ field public static final int VP9Profile2HDR = 4096; // 0x1000
+ field public static final int VP9Profile3 = 8; // 0x8
+ field public static final int VP9Profile3HDR = 8192; // 0x2000
field public int level;
field public int profile;
}
diff --git a/core/java/android/hardware/location/NanoApp.java b/core/java/android/hardware/location/NanoApp.java
index 8d50be6..03ac4a2 100644
--- a/core/java/android/hardware/location/NanoApp.java
+++ b/core/java/android/hardware/location/NanoApp.java
@@ -192,7 +192,7 @@
* @return publisher name
*/
public String getPublisher() {
- return mPublisher;
+ return mPublisher;
}
/**
@@ -201,7 +201,7 @@
* @return app name
*/
public String getName() {
- return mName;
+ return mName;
}
/**
@@ -210,7 +210,7 @@
* @return identifier for this app
*/
public int getAppId() {
- return mAppId;
+ return mAppId;
}
/**
@@ -219,7 +219,7 @@
* @return app version
*/
public int getAppVersion() {
- return mAppVersion;
+ return mAppVersion;
}
/**
@@ -228,7 +228,7 @@
* @return readable memory needed in bytes
*/
public int getNeededReadMemBytes() {
- return mNeededReadMemBytes;
+ return mNeededReadMemBytes;
}
/**
@@ -237,7 +237,7 @@
* @return writable memory needed in bytes
*/
public int getNeededWriteMemBytes() {
- return mNeededWriteMemBytes;
+ return mNeededWriteMemBytes;
}
/**
@@ -246,7 +246,7 @@
* @return executable memory needed in bytes
*/
public int getNeededExecMemBytes() {
- return mNeededExecMemBytes;
+ return mNeededExecMemBytes;
}
/**
@@ -255,7 +255,7 @@
* @return sensors needed
*/
public int[] getNeededSensors() {
- return mNeededSensors;
+ return mNeededSensors;
}
/**
@@ -264,7 +264,7 @@
* @return generated events
*/
public int[] getOutputEvents() {
- return mOutputEvents;
+ return mOutputEvents;
}
/**
@@ -273,7 +273,7 @@
* @return app binary
*/
public byte[] getAppBinary() {
- return mAppBinary;
+ return mAppBinary;
}
private NanoApp(Parcel in) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2a3c3fe..638be51 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6666,6 +6666,17 @@
public static final String DEVICE_PROVISIONED = "device_provisioned";
/**
+ * Whether mobile data should be allowed while the device is being provisioned.
+ * This allows the provisioning process to turn off mobile data before the user
+ * has an opportunity to set things up, preventing other processes from burning
+ * precious bytes before wifi is setup.
+ * (0 = false, 1 = true)
+ * @hide
+ */
+ public static final String DEVICE_PROVISIONING_MOBILE_DATA_ENABLED =
+ "device_provisioning_mobile_data";
+
+ /**
* The saved value for WindowManagerService.setForcedDisplaySize().
* Two integers separated by a comma. If unset, then use the real display size.
* @hide
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index f44d4c1a..c972476 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -485,25 +485,15 @@
}
/**
- * Halts any current rendering into the surface. Use this if it is unclear whether
+ * Stops any rendering into the surface. Use this if it is unclear whether
* or not the surface used by the HardwareRenderer will be changing. It
- * Suspends any rendering into the surface, but will not do any destruction.
- *
- * Any subsequent draws will override the pause, resuming normal operation.
+ * Suspends any rendering into the surface, but will not do any destruction
*/
boolean pauseSurface(Surface surface) {
return nPauseSurface(mNativeProxy, surface);
}
/**
- * Hard stops or resumes rendering into the surface. This flag is used to
- * determine whether or not it is safe to use the given surface *at all*
- */
- void setStopped(boolean stopped) {
- nSetStopped(mNativeProxy, stopped);
- }
-
- /**
* Destroys all hardware rendering resources associated with the specified
* view hierarchy.
*
@@ -998,7 +988,6 @@
private static native void nInitialize(long nativeProxy, Surface window);
private static native void nUpdateSurface(long nativeProxy, Surface window);
private static native boolean nPauseSurface(long nativeProxy, Surface window);
- private static native void nSetStopped(long nativeProxy, boolean stopped);
private static native void nSetup(long nativeProxy, int width, int height,
float lightRadius, int ambientShadowAlpha, int spotShadowAlpha);
private static native void nSetLightCenter(long nativeProxy,
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 94c4cef..a324767 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1079,16 +1079,13 @@
void setWindowStopped(boolean stopped) {
if (mStopped != stopped) {
mStopped = stopped;
- final ThreadedRenderer renderer = mAttachInfo.mHardwareRenderer;
- if (renderer != null) {
- if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped);
- renderer.setStopped(mStopped);
- }
if (!mStopped) {
scheduleTraversals();
} else {
- if (renderer != null) {
- renderer.destroyHardwareResources(mView);
+ if (mAttachInfo.mHardwareRenderer != null) {
+ if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle());
+ mAttachInfo.mHardwareRenderer.updateSurface(null);
+ mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
}
}
}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
index 46b49de..8d11783 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
@@ -16,6 +16,7 @@
package com.android.internal.inputmethod;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.PackageManager;
import android.text.TextUtils;
@@ -284,8 +285,22 @@
return -1;
}
+ /**
+ * Provides the basic operation to implement bi-directional IME rotation.
+ * @param onlyCurrentIme {@code true} to limit the search space to IME subtypes that belong
+ * to {@code imi}.
+ * @param imi {@link InputMethodInfo} that will be used in conjunction with {@code subtype}
+ * from which we find the adjacent IME subtype.
+ * @param subtype {@link InputMethodSubtype} that will be used in conjunction with
+ * {@code imi} from which we find the next IME subtype. {@code null} if the input method
+ * does not have a subtype.
+ * @param forward {@code true} to do forward search the next IME subtype. Specify
+ * {@code false} to do backward search.
+ * @return The IME subtype found. {@code null} if no IME subtype is found.
+ */
+ @Nullable
public ImeSubtypeListItem getNextInputMethodLocked(boolean onlyCurrentIme,
- InputMethodInfo imi, InputMethodSubtype subtype, boolean forward) {
+ InputMethodInfo imi, @Nullable InputMethodSubtype subtype, boolean forward) {
if (imi == null) {
return null;
}
@@ -298,7 +313,7 @@
}
final int N = mImeSubtypeList.size();
for (int i = 1; i < N; ++i) {
- // Start searching the next IME/subtype from the next of the current index.
+ // Start searching the next IME/subtype from +/- 1 indices.
final int offset = forward ? i : N - i;
final int candidateIndex = (currentIndex + offset) % N;
final ImeSubtypeListItem candidate = mImeSubtypeList.get(candidateIndex);
@@ -371,8 +386,22 @@
mUsageHistoryOfSubtypeListItemIndex[0] = currentItemIndex;
}
+ /**
+ * Provides the basic operation to implement bi-directional IME rotation.
+ * @param onlyCurrentIme {@code true} to limit the search space to IME subtypes that belong
+ * to {@code imi}.
+ * @param imi {@link InputMethodInfo} that will be used in conjunction with {@code subtype}
+ * from which we find the adjacent IME subtype.
+ * @param subtype {@link InputMethodSubtype} that will be used in conjunction with
+ * {@code imi} from which we find the next IME subtype. {@code null} if the input method
+ * does not have a subtype.
+ * @param forward {@code true} to do forward search the next IME subtype. Specify
+ * {@code false} to do backward search.
+ * @return The IME subtype found. {@code null} if no IME subtype is found.
+ */
+ @Nullable
public ImeSubtypeListItem getNextInputMethodLocked(boolean onlyCurrentIme,
- InputMethodInfo imi, InputMethodSubtype subtype, boolean forward) {
+ InputMethodInfo imi, @Nullable InputMethodSubtype subtype, boolean forward) {
int currentUsageRank = getUsageRank(imi, subtype);
if (currentUsageRank < 0) {
if (DEBUG) {
@@ -456,8 +485,22 @@
mSwitchingUnawareRotationList = switchingUnawareRotationList;
}
+ /**
+ * Provides the basic operation to implement bi-directional IME rotation.
+ * @param onlyCurrentIme {@code true} to limit the search space to IME subtypes that belong
+ * to {@code imi}.
+ * @param imi {@link InputMethodInfo} that will be used in conjunction with {@code subtype}
+ * from which we find the adjacent IME subtype.
+ * @param subtype {@link InputMethodSubtype} that will be used in conjunction with
+ * {@code imi} from which we find the next IME subtype. {@code null} if the input method
+ * does not have a subtype.
+ * @param forward {@code true} to do forward search the next IME subtype. Specify
+ * {@code false} to do backward search.
+ * @return The IME subtype found. {@code null} if no IME subtype is found.
+ */
+ @Nullable
public ImeSubtypeListItem getNextInputMethod(boolean onlyCurrentIme, InputMethodInfo imi,
- InputMethodSubtype subtype, boolean forward) {
+ @Nullable InputMethodSubtype subtype, boolean forward) {
if (imi == null) {
return null;
}
diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp
index 91a3b4f..90d69d2 100644
--- a/core/jni/android_hardware_location_ContextHubService.cpp
+++ b/core/jni/android_hardware_location_ContextHubService.cpp
@@ -21,8 +21,8 @@
#include <inttypes.h>
#include <jni.h>
-#include <map>
#include <queue>
+#include <unordered_map>
#include <string.h>
#include <stdint.h>
#include <stdio.h>
@@ -105,7 +105,7 @@
context_hub_info_s hubInfo;
jniInfo_s jniInfo;
std::queue<int> freeIds;
- std::map<int, app_instance_info_s *> appInstances;
+ std::unordered_map<int, app_instance_info_s> appInstances;
};
} // unnamed namespace
@@ -137,7 +137,7 @@
const context_hub_t *info = get_hub_info(hubHandle);
if (info) {
- msg->app = info->os_app_name;
+ msg->app_name = info->os_app_name;
return 0;
} else {
ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle);
@@ -154,23 +154,23 @@
}
static int get_hub_id_for_app_instance(int id) {
- if (db.appInstances.find(id) == db.appInstances.end()) {
+ if (!db.appInstances.count(id)) {
ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id);
return -1;
}
- int hubHandle = db.appInstances[id]->hubHandle;
+ int hubHandle = db.appInstances[id].hubHandle;
return db.hubInfo.hubs[hubHandle].hub_id;
}
static int set_dest_app(hub_message_t *msg, int id) {
- if (db.appInstances.find(id) == db.appInstances.end()) {
+ if (!db.appInstances.count(id)) {
ALOGD("%s: Cannod find app for app instance %d", __FUNCTION__, id);
return -1;
}
- msg->app = db.appInstances[id]->appInfo.name;
+ msg->app_name = db.appInstances[id].appInfo.app_name;
return 0;
}
@@ -210,76 +210,43 @@
int add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle, JNIEnv *env) {
// Not checking if the apps are indeed distinct
-
- app_instance_info_s *entry;
- void *appName;
- hub_app_name_t *name;
-
- assert(appInfo && appInfo->name && appInfo->name->app_name);
-
- entry = (app_instance_info_s *) malloc(sizeof(app_instance_info_s));
- appName = malloc(appInfo->name->app_name_len);
- name = (hub_app_name_t *) malloc(sizeof(hub_app_name_t));
-
+ app_instance_info_s entry;
int appInstanceHandle = generate_id();
- if (appInstanceHandle < 0 || !appName || !entry || !name) {
- ALOGE("Cannot find resources to add app instance %d, %p, %p",
- appInstanceHandle, appName, entry);
+ assert(appInfo);
- free(appName);
- free(entry);
- free(name);
-
- if (appInstanceHandle >= 0) {
- return_id(appInstanceHandle);
- }
-
+ if (appInstanceHandle < 0) {
+ ALOGE("Cannot find resources to add app instance %d",
+ appInstanceHandle);
return -1;
}
- memcpy(&(entry->appInfo), appInfo, sizeof(entry->appInfo));
- memcpy(appName, appInfo->name->app_name, appInfo->name->app_name_len);
- name->app_name = appName;
- name->app_name_len = appInfo->name->app_name_len;
- entry->appInfo.name = name;
- entry->truncName = 0;
- memcpy(&(entry->truncName), name->app_name,
- sizeof(entry->truncName) < name->app_name_len ?
- sizeof(entry->truncName) : name->app_name_len);
-
- // Not checking for sanity of hubId
- entry->hubHandle = hubHandle;
- entry->instanceId = appInstanceHandle;
+ entry.appInfo = *appInfo;
+ entry.instanceId = appInstanceHandle;
+ entry.truncName = appInfo->app_name.id;
+ entry.hubHandle = hubHandle;
db.appInstances[appInstanceHandle] = entry;
// Finally - let the service know of this app instance
env->CallIntMethod(db.jniInfo.jContextHubService,
db.jniInfo.contextHubServiceAddAppInstance,
- hubHandle, entry->instanceId, entry->truncName,
- entry->appInfo.version);
+ hubHandle, entry.instanceId, entry.truncName,
+ entry.appInfo.version);
ALOGW("Added App 0x%" PRIx64 " on hub Handle %" PRId32
- " as appInstance %d, original name_length %" PRId32, entry->truncName,
- entry->hubHandle, appInstanceHandle, name->app_name_len);
+ " as appInstance %d", entry.truncName,
+ entry.hubHandle, appInstanceHandle);
return appInstanceHandle;
}
int delete_app_instance(int id) {
- if (db.appInstances.find(id) == db.appInstances.end()) {
+ if (!db.appInstances.count(id)) {
return -1;
}
return_id(id);
-
- if (db.appInstances[id]) {
- // Losing the const cast below. This is intentional.
- free((void *)db.appInstances[id]->appInfo.name->app_name);
- free((void *)db.appInstances[id]->appInfo.name);
- free(db.appInstances[id]);
- db.appInstances.erase(id);
- }
+ db.appInstances.erase(id);
return 0;
}
@@ -353,27 +320,20 @@
}
int handle_query_apps_response(char *msg, int msgLen, uint32_t hubHandle) {
- int i;
JNIEnv *env;
if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
return -1;
}
int numApps = msgLen/sizeof(hub_app_info);
- hub_app_info *info = (hub_app_info *)malloc(msgLen); // handle possible alignment
+ hub_app_info info;
+ hub_app_info *unalignedInfoAddr = (hub_app_info*)msg;
- if (!info) {
- return -1;
+ for (int i = 0; i < numApps; i++, unalignedInfoAddr++) {
+ memcpy(&info, unalignedInfoAddr, sizeof(info));
+ add_app_instance(&info, hubHandle, env);
}
- memcpy(info, msg, msgLen);
- for (i = 0; i < numApps; i++) {
- add_app_instance(info, hubHandle, env);
- info++;
- }
-
- free(info);
-
return 0;
}
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index ef45c87..3d65209 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -479,12 +479,6 @@
return proxy->pauseSurface(surface);
}
-static void android_view_ThreadedRenderer_setStopped(JNIEnv* env, jobject clazz,
- jlong proxyPtr, jboolean stopped) {
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- proxy->setStopped(stopped);
-}
-
static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr,
jint width, jint height, jfloat lightRadius, jint ambientShadowAlpha, jint spotShadowAlpha) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
@@ -738,7 +732,6 @@
{ "nInitialize", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_initialize },
{ "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
{ "nPauseSurface", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_pauseSurface },
- { "nSetStopped", "(JZ)V", (void*) android_view_ThreadedRenderer_setStopped },
{ "nSetup", "(JIIFII)V", (void*) android_view_ThreadedRenderer_setup },
{ "nSetLightCenter", "(JFFF)V", (void*) android_view_ThreadedRenderer_setLightCenter },
{ "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index e209e2a..aba5d4b 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -137,6 +137,9 @@
// whether children with non-zero Z in the chunk should be reordered
bool reorderChildren;
+#if HWUI_NEW_OPS
+ const ClipBase* reorderClip;
+#endif
};
DisplayList();
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index f12e523..6fc74a5 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -269,7 +269,8 @@
}
template <typename V>
-void FrameBuilder::defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes) {
+void FrameBuilder::defer3dChildren(const ClipBase* reorderClip, ChildrenSelectMode mode,
+ const V& zTranslatedNodes) {
const int size = zTranslatedNodes.size();
if (size == 0
|| (mode == ChildrenSelectMode::Negative&& zTranslatedNodes[0].key > 0.0f)
@@ -305,7 +306,7 @@
// attempt to render the shadow if the caster about to be drawn is its caster,
// OR if its caster's Z value is similar to the previous potential caster
if (shadowIndex == drawIndex || casterZ - lastCasterZ < 0.1f) {
- deferShadow(*casterNodeOp);
+ deferShadow(reorderClip, *casterNodeOp);
lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
shadowIndex++;
@@ -319,7 +320,7 @@
}
}
-void FrameBuilder::deferShadow(const RenderNodeOp& casterNodeOp) {
+void FrameBuilder::deferShadow(const ClipBase* reorderClip, const RenderNodeOp& casterNodeOp) {
auto& node = *casterNodeOp.renderNode;
auto& properties = node.properties();
@@ -365,6 +366,10 @@
casterPath = frameAllocatedPath;
}
+ // apply reorder clip to shadow, so it respects clip at beginning of reorderable chunk
+ int restoreTo = mCanvasState.save(SaveFlags::MatrixClip);
+ mCanvasState.writableSnapshot()->applyClip(reorderClip,
+ *mCanvasState.currentSnapshot()->transform);
if (CC_LIKELY(!mCanvasState.getRenderTargetClipBounds().isEmpty())) {
Matrix4 shadowMatrixXY(casterNodeOp.localMatrix);
Matrix4 shadowMatrixZ(casterNodeOp.localMatrix);
@@ -386,6 +391,7 @@
currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Shadow);
}
}
+ mCanvasState.restoreToCount(restoreTo);
}
void FrameBuilder::deferProjectedChildren(const RenderNode& renderNode) {
@@ -438,11 +444,11 @@
// can't be null, since DL=null node rejection happens before deferNodePropsAndOps
const DisplayList& displayList = *(renderNode.getDisplayList());
- for (const DisplayList::Chunk& chunk : displayList.getChunks()) {
+ for (auto& chunk : displayList.getChunks()) {
FatVector<ZRenderNodeOpPair, 16> zTranslatedNodes;
buildZSortedChildList(&zTranslatedNodes, displayList, chunk);
- defer3dChildren(ChildrenSelectMode::Negative, zTranslatedNodes);
+ defer3dChildren(chunk.reorderClip, ChildrenSelectMode::Negative, zTranslatedNodes);
for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
const RecordedOp* op = displayList.getOps()[opIndex];
receivers[op->opId](*this, *op);
@@ -453,7 +459,7 @@
deferProjectedChildren(renderNode);
}
}
- defer3dChildren(ChildrenSelectMode::Positive, zTranslatedNodes);
+ defer3dChildren(chunk.reorderClip, ChildrenSelectMode::Positive, zTranslatedNodes);
}
}
diff --git a/libs/hwui/FrameBuilder.h b/libs/hwui/FrameBuilder.h
index 039ab6b..a6fd761 100644
--- a/libs/hwui/FrameBuilder.h
+++ b/libs/hwui/FrameBuilder.h
@@ -193,9 +193,10 @@
void deferNodePropsAndOps(RenderNode& node);
template <typename V>
- void defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes);
+ void defer3dChildren(const ClipBase* reorderClip, ChildrenSelectMode mode,
+ const V& zTranslatedNodes);
- void deferShadow(const RenderNodeOp& casterOp);
+ void deferShadow(const ClipBase* reorderClip, const RenderNodeOp& casterOp);
void deferProjectedChildren(const RenderNode& renderNode);
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index b78497d..ab733f1 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -57,6 +57,16 @@
return displayList;
}
+void RecordingCanvas::insertReorderBarrier(bool enableReorder) {
+ if (enableReorder) {
+ mDeferredBarrierType = DeferredBarrierType::OutOfOrder;
+ mDeferredBarrierClip = getRecordedClip();
+ } else {
+ mDeferredBarrierType = DeferredBarrierType::InOrder;
+ mDeferredBarrierClip = nullptr;
+ }
+}
+
SkCanvas* RecordingCanvas::asSkCanvas() {
LOG_ALWAYS_FATAL_IF(!mDisplayList,
"attempting to get an SkCanvas when we are not recording!");
@@ -610,6 +620,7 @@
newChunk.beginOpIndex = insertIndex;
newChunk.endOpIndex = insertIndex + 1;
newChunk.reorderChildren = (mDeferredBarrierType == DeferredBarrierType::OutOfOrder);
+ newChunk.reorderClip = mDeferredBarrierClip;
int nextChildIndex = mDisplayList->children.size();
newChunk.beginChildIndex = newChunk.endChildIndex = nextChildIndex;
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index acb88e2..219296c 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -55,10 +55,7 @@
// ----------------------------------------------------------------------------
// MISC HWUI OPERATIONS - TODO: CATEGORIZE
// ----------------------------------------------------------------------------
- virtual void insertReorderBarrier(bool enableReorder) override {
- mDeferredBarrierType = enableReorder
- ? DeferredBarrierType::OutOfOrder : DeferredBarrierType::InOrder;
- }
+ virtual void insertReorderBarrier(bool enableReorder) override;
virtual void drawLayer(DeferredLayerUpdater* layerHandle) override;
virtual void drawRenderNode(RenderNode* renderNode) override;
@@ -312,6 +309,7 @@
std::unique_ptr<SkiaCanvasProxy> mSkiaCanvasProxy;
ResourceCache& mResourceCache;
DeferredBarrierType mDeferredBarrierType = DeferredBarrierType::None;
+ const ClipBase* mDeferredBarrierClip = nullptr;
DisplayList* mDisplayList = nullptr;
bool mHighContrastText = false;
SkAutoTUnref<SkDrawFilter> mDrawFilter;
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index b39de26..a455f57 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -24,7 +24,8 @@
MinikinFontSkia::MinikinFontSkia(SkTypeface* typeface, const void* fontData, size_t fontSize,
int ttcIndex) :
- mTypeface(typeface), mFontData(fontData), mFontSize(fontSize), mTtcIndex(ttcIndex) {
+ MinikinFont(typeface->uniqueID()), mTypeface(typeface), mFontData(fontData),
+ mFontSize(fontSize), mTtcIndex(ttcIndex) {
}
MinikinFontSkia::~MinikinFontSkia() {
@@ -99,10 +100,6 @@
return mTtcIndex;
}
-int32_t MinikinFontSkia::GetUniqueId() const {
- return mTypeface->uniqueID();
-}
-
uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) {
uint32_t flags = paint->getFlags();
SkPaint::Hinting hinting = paint->getHinting();
diff --git a/libs/hwui/hwui/MinikinSkia.h b/libs/hwui/hwui/MinikinSkia.h
index dbc65f9..a7c9fb0 100644
--- a/libs/hwui/hwui/MinikinSkia.h
+++ b/libs/hwui/hwui/MinikinSkia.h
@@ -41,8 +41,6 @@
const void* GetTable(uint32_t tag, size_t* size, MinikinDestroyFunc* destroy);
- int32_t GetUniqueId() const;
-
SkTypeface* GetSkTypeface() const;
// Access to underlying raw font bytes
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 890d4a1..ab66b2a 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -113,11 +113,18 @@
mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
mHaveNewSurface = true;
mSwapHistory.clear();
+ makeCurrent();
} else {
mRenderThread.removeFrameCallback(this);
}
}
+void CanvasContext::requireSurface() {
+ LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
+ "requireSurface() called but no surface set!");
+ makeCurrent();
+}
+
void CanvasContext::setSwapBehavior(SwapBehavior swapBehavior) {
mSwapBehavior = swapBehavior;
}
@@ -139,18 +146,6 @@
return mRenderThread.removeFrameCallback(this);
}
-void CanvasContext::setStopped(bool stopped) {
- if (mStopped != stopped) {
- mStopped = stopped;
- if (mStopped) {
- mRenderThread.removeFrameCallback(this);
- if (mEglManager.isCurrent(mEglSurface)) {
- mEglManager.makeCurrent(EGL_NO_SURFACE);
- }
- }
- }
-}
-
// TODO: don't pass viewport size, it's automatic via EGL
void CanvasContext::setup(int width, int height, float lightRadius,
uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
@@ -177,9 +172,7 @@
mOpaque = opaque;
}
-bool CanvasContext::makeCurrent() {
- if (mStopped) return false;
-
+void CanvasContext::makeCurrent() {
// TODO: Figure out why this workaround is needed, see b/13913604
// In the meantime this matches the behavior of GLRenderer, so it is not a regression
EGLint error = 0;
@@ -187,7 +180,6 @@
if (error) {
setSurface(nullptr);
}
- return !error;
}
static bool wasSkipped(FrameInfo* info) {
@@ -679,7 +671,7 @@
}
Layer* CanvasContext::createTextureLayer() {
- mEglManager.initialize();
+ requireSurface();
return LayerRenderer::createTextureLayer(mRenderThread.renderState());
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 52df3abe..9350114 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -82,14 +82,13 @@
void initialize(Surface* surface);
void updateSurface(Surface* surface);
bool pauseSurface(Surface* surface);
- void setStopped(bool stopped);
bool hasSurface() { return mNativeSurface.get(); }
void setup(int width, int height, float lightRadius,
uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
void setLightCenter(const Vector3& lightCenter);
void setOpaque(bool opaque);
- bool makeCurrent();
+ void makeCurrent();
void prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
int64_t syncQueued, RenderNode* target);
void draw();
@@ -173,6 +172,7 @@
friend class android::uirenderer::RenderState;
void setSurface(Surface* window);
+ void requireSurface();
void freePrefetchedLayers(TreeObserver* observer);
@@ -185,7 +185,6 @@
EglManager& mEglManager;
sp<Surface> mNativeSurface;
EGLSurface mEglSurface = EGL_NO_SURFACE;
- bool mStopped = false;
bool mBufferPreserved = false;
SwapBehavior mSwapBehavior = kSwap_default;
struct SwapHistory {
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index ed472ac..651aaa2 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -115,7 +115,7 @@
ATRACE_CALL();
int64_t vsync = mFrameInfo[static_cast<int>(FrameInfoIndex::Vsync)];
mRenderThread->timeLord().vsyncReceived(vsync);
- bool canDraw = mContext->makeCurrent();
+ mContext->makeCurrent();
Caches::getInstance().textureCache.resetMarkInUse(mContext);
for (size_t i = 0; i < mLayers.size(); i++) {
@@ -126,9 +126,8 @@
// This is after the prepareTree so that any pending operations
// (RenderNode tree state, prefetched layers, etc...) will be flushed.
- if (CC_UNLIKELY(!mContext->hasSurface() || !canDraw)) {
+ if (CC_UNLIKELY(!mContext->hasSurface())) {
mSyncResult |= kSync_LostSurfaceRewardIfFound;
- info.out.canDrawThisFrame = false;
}
if (info.out.hasAnimations) {
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index ac6a28f..8def7ad 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -270,6 +270,12 @@
// Ensure we always have a valid surface & context
surface = mPBufferSurface;
}
+ // TODO: Temporary to help diagnose b/27286867
+ if (mCurrentSurface == mPBufferSurface || surface == mPBufferSurface) {
+ ALOGD("Switching from surface %p%s to %p%s", mCurrentSurface,
+ mCurrentSurface == mPBufferSurface ? " (pbuffer)" : "",
+ surface, surface == mPBufferSurface ? " (pbuffer)" : "");
+ }
if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) {
if (errOut) {
*errOut = eglGetError();
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index c5a2dc7..1116383 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -167,18 +167,6 @@
return (bool) postAndWait(task);
}
-CREATE_BRIDGE2(setStopped, CanvasContext* context, bool stopped) {
- args->context->setStopped(args->stopped);
- return nullptr;
-}
-
-void RenderProxy::setStopped(bool stopped) {
- SETUP_TASK(setStopped);
- args->context = mContext;
- args->stopped = stopped;
- postAndWait(task);
-}
-
CREATE_BRIDGE6(setup, CanvasContext* context, int width, int height,
float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
args->context->setup(args->width, args->height, args->lightRadius,
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 32d3283b..ecc296b 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -79,7 +79,6 @@
ANDROID_API void initialize(const sp<Surface>& surface);
ANDROID_API void updateSurface(const sp<Surface>& surface);
ANDROID_API bool pauseSurface(const sp<Surface>& surface);
- ANDROID_API void setStopped(bool stopped);
ANDROID_API void setup(int width, int height, float lightRadius,
uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
ANDROID_API void setLightCenter(const Vector3& lightCenter);
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index 9877439..209a104 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -1722,6 +1722,35 @@
EXPECT_EQ(4, renderer.getIndex());
}
+RENDERTHREAD_TEST(FrameBuilder, shadowClipping) {
+ class ShadowClippingTestRenderer : public TestRendererBase {
+ public:
+ void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(0, mIndex++);
+ EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipState->rect)
+ << "Shadow must respect pre-barrier canvas clip value.";
+ }
+ void onRectOp(const RectOp& op, const BakedOpState& state) override {
+ EXPECT_EQ(1, mIndex++);
+ }
+ };
+ auto parent = TestUtils::createNode(0, 0, 100, 100,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ // Apply a clip before the reorder barrier/shadow casting child is drawn.
+ // This clip must be applied to the shadow cast by the child.
+ canvas.clipRect(25, 25, 75, 75, SkRegion::kIntersect_Op);
+ canvas.insertReorderBarrier(true);
+ canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
+ });
+
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
+ TestUtils::createSyncedNodeList(parent),
+ (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
+ ShadowClippingTestRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(2, renderer.getIndex());
+}
+
static void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
class PropertyTestRenderer : public TestRendererBase {
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index c49ff71..18171de 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -603,6 +603,36 @@
EXPECT_TRUE(chunks[1].reorderChildren);
}
+TEST(RecordingCanvas, insertReorderBarrier_clip) {
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+ // first chunk: no recorded clip
+ canvas.insertReorderBarrier(true);
+ canvas.drawRect(0, 0, 400, 400, SkPaint());
+
+ // second chunk: no recorded clip, since inorder region
+ canvas.clipRect(0, 0, 200, 200, SkRegion::kIntersect_Op);
+ canvas.insertReorderBarrier(false);
+ canvas.drawRect(0, 0, 400, 400, SkPaint());
+
+ // third chunk: recorded clip
+ canvas.insertReorderBarrier(true);
+ canvas.drawRect(0, 0, 400, 400, SkPaint());
+ });
+
+ auto chunks = dl->getChunks();
+ ASSERT_EQ(3u, chunks.size());
+
+ EXPECT_TRUE(chunks[0].reorderChildren);
+ EXPECT_EQ(nullptr, chunks[0].reorderClip);
+
+ EXPECT_FALSE(chunks[1].reorderChildren);
+ EXPECT_EQ(nullptr, chunks[1].reorderClip);
+
+ EXPECT_TRUE(chunks[2].reorderChildren);
+ ASSERT_NE(nullptr, chunks[2].reorderClip);
+ EXPECT_EQ(Rect(200, 200), chunks[2].reorderClip->rect);
+}
+
TEST(RecordingCanvas, refPaint) {
SkPaint paint;
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index ca306cc..a5550ec 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -37,6 +37,8 @@
import android.util.ArrayMap;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
/**
* The AudioRecord class manages the audio resources for Java applications
* to record audio from the audio input hardware of the platform. This is
@@ -1320,6 +1322,7 @@
* Note: The query is only valid if the AudioRecord is currently recording. If it is not,
* <code>getRoutedDevice()</code> will return null.
*/
+ @Override
public AudioDeviceInfo getRoutedDevice() {
int deviceId = native_getRoutedDeviceId();
if (deviceId == 0) {
@@ -1338,8 +1341,8 @@
/*
* Call BEFORE adding a routing callback handler.
*/
- private void testEnableNativeRoutingCallbacks() {
- if (mRoutingChangeListeners.size() == 0 && mNewRoutingChangeListeners.size() == 0) {
+ private void testEnableNativeRoutingCallbacksLocked() {
+ if (mRoutingChangeListeners.size() == 0) {
native_enableDeviceCallback();
}
}
@@ -1347,24 +1350,23 @@
/*
* Call AFTER removing a routing callback handler.
*/
- private void testDisableNativeRoutingCallbacks() {
- if (mRoutingChangeListeners.size() == 0 && mNewRoutingChangeListeners.size() == 0) {
+ private void testDisableNativeRoutingCallbacksLocked() {
+ if (mRoutingChangeListeners.size() == 0) {
native_disableDeviceCallback();
}
}
//--------------------------------------------------------------------------
- // >= "N" (Re)Routing Info
+ // (Re)Routing Info
//--------------------
/**
* The list of AudioRouting.OnRoutingChangedListener interfaces added (with
- * {@link AudioRecord#addOnRoutingListener(AudioRouting.OnRoutingChangedListener,
- * android.os.Handler)}
- * by an app to receive (re)routing notifications.
+ * {@link AudioRecord#addOnRoutingChangedListener} by an app to receive
+ * (re)routing notifications.
*/
- private ArrayMap<AudioRouting.OnRoutingChangedListener, NativeNewRoutingEventHandlerDelegate>
- mNewRoutingChangeListeners =
- new ArrayMap<AudioRouting.OnRoutingChangedListener, NativeNewRoutingEventHandlerDelegate>();
+ @GuardedBy("mRoutingChangeListeners")
+ private ArrayMap<AudioRouting.OnRoutingChangedListener,
+ NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
/**
* Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of
@@ -1375,14 +1377,15 @@
* the callback. If <code>null</code>, the {@link Handler} associated with the main
* {@link Looper} will be used.
*/
- public void addOnRoutingListener(AudioRouting.OnRoutingChangedListener listener,
+ @Override
+ public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener,
android.os.Handler handler) {
- if (listener != null && !mNewRoutingChangeListeners.containsKey(listener)) {
- synchronized (mNewRoutingChangeListeners) {
- testEnableNativeRoutingCallbacks();
- mNewRoutingChangeListeners.put(
- listener, new NativeNewRoutingEventHandlerDelegate(this, listener,
- handler != null ? handler : new Handler(mInitializationLooper)));
+ synchronized (mRoutingChangeListeners) {
+ if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
+ testEnableNativeRoutingCallbacksLocked();
+ mRoutingChangeListeners.put(
+ listener, new NativeRoutingEventHandlerDelegate(this, listener,
+ handler != null ? handler : new Handler(mInitializationLooper)));
}
}
}
@@ -1393,39 +1396,42 @@
* @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
* to remove.
*/
- public void removeOnRoutingListener(AudioRouting.OnRoutingChangedListener listener) {
- synchronized (mNewRoutingChangeListeners) {
- if (mNewRoutingChangeListeners.containsKey(listener)) {
- mNewRoutingChangeListeners.remove(listener);
- testDisableNativeRoutingCallbacks();
+ @Override
+ public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) {
+ synchronized (mRoutingChangeListeners) {
+ if (mRoutingChangeListeners.containsKey(listener)) {
+ mRoutingChangeListeners.remove(listener);
+ testDisableNativeRoutingCallbacksLocked();
}
}
}
//--------------------------------------------------------------------------
- // Marshmallow (Re)Routing Info
+ // (Re)Routing Info
//--------------------
/**
- * Defines the interface by which applications can receive notifications of routing
- * changes for the associated {@link AudioRecord}.
+ * Defines the interface by which applications can receive notifications of
+ * routing changes for the associated {@link AudioRecord}.
+ *
+ * @deprecated users should switch to the general purpose
+ * {@link AudioRouting.OnRoutingChangedListener} class instead.
*/
- public interface OnRoutingChangedListener {
+ @Deprecated
+ public interface OnRoutingChangedListener extends AudioRouting.OnRoutingChangedListener {
/**
- * Called when the routing of an AudioRecord changes from either and explicit or
- * policy rerouting. Use {@link #getRoutedDevice()} to retrieve the newly routed-from
- * device.
+ * Called when the routing of an AudioRecord changes from either and
+ * explicit or policy rerouting. Use {@link #getRoutedDevice()} to
+ * retrieve the newly routed-from device.
*/
public void onRoutingChanged(AudioRecord audioRecord);
- }
- /**
- * The list of AudioRecord.OnRoutingChangedListener interface added (with
- * {@link AudioRecord#addOnRoutingChangedListener(OnRoutingChangedListener,android.os.Handler)}
- * by an app to receive (re)routing notifications.
- */
- private ArrayMap<OnRoutingChangedListener, NativeRoutingEventHandlerDelegate>
- mRoutingChangeListeners =
- new ArrayMap<OnRoutingChangedListener, NativeRoutingEventHandlerDelegate>();
+ @Override
+ default public void onRoutingChanged(AudioRouting router) {
+ if (router instanceof AudioRecord) {
+ onRoutingChanged((AudioRecord) router);
+ }
+ }
+ }
/**
* Adds an {@link OnRoutingChangedListener} to receive notifications of routing changes
@@ -1435,88 +1441,28 @@
* @param handler Specifies the {@link Handler} object for the thread on which to execute
* the callback. If <code>null</code>, the {@link Handler} associated with the main
* {@link Looper} will be used.
+ * @deprecated users should switch to the general purpose
+ * {@link AudioRouting.OnRoutingChangedListener} class instead.
*/
@Deprecated
public void addOnRoutingChangedListener(OnRoutingChangedListener listener,
android.os.Handler handler) {
- if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
- synchronized (mRoutingChangeListeners) {
- testEnableNativeRoutingCallbacks();
- mRoutingChangeListeners.put(
- listener, new NativeRoutingEventHandlerDelegate(this, listener,
- handler != null ? handler : new Handler(mInitializationLooper)));
- }
- }
+ addOnRoutingChangedListener((AudioRouting.OnRoutingChangedListener) listener, handler);
}
/**
* Removes an {@link OnRoutingChangedListener} which has been previously added
* to receive rerouting notifications.
* @param listener The previously added {@link OnRoutingChangedListener} interface to remove.
+ * @deprecated users should switch to the general purpose
+ * {@link AudioRouting.OnRoutingChangedListener} class instead.
*/
@Deprecated
public void removeOnRoutingChangedListener(OnRoutingChangedListener listener) {
- synchronized (mRoutingChangeListeners) {
- if (mRoutingChangeListeners.containsKey(listener)) {
- mRoutingChangeListeners.remove(listener);
- testDisableNativeRoutingCallbacks();
- }
- }
+ removeOnRoutingChangedListener((AudioRouting.OnRoutingChangedListener) listener);
}
/**
- * >= "N" Routing
- * Helper class to handle the forwarding of native events to the appropriate listener
- * (potentially) handled in a different thread
- */
- private class NativeNewRoutingEventHandlerDelegate {
- private final Handler mHandler;
-
- NativeNewRoutingEventHandlerDelegate(final AudioRecord record,
- final AudioRouting.OnRoutingChangedListener listener,
- Handler handler) {
- // find the looper for our new event handler
- Looper looper;
- if (handler != null) {
- looper = handler.getLooper();
- } else {
- // no given handler, use the looper the AudioRecord was created in
- looper = mInitializationLooper;
- }
-
- // construct the event handler with this looper
- if (looper != null) {
- // implement the event handler delegate
- mHandler = new Handler(looper) {
- @Override
- public void handleMessage(Message msg) {
- if (record == null) {
- return;
- }
- switch(msg.what) {
- case AudioSystem.NATIVE_EVENT_ROUTING_CHANGE:
- if (listener != null) {
- listener.onRoutingChanged(record);
- }
- break;
- default:
- loge("Unknown native event type: " + msg.what);
- break;
- }
- }
- };
- } else {
- mHandler = null;
- }
- }
-
- Handler getHandler() {
- return mHandler;
- }
- }
-
- /**
- * Marshmallow Routing
* Helper class to handle the forwarding of native events to the appropriate listener
* (potentially) handled in a different thread
*/
@@ -1524,7 +1470,7 @@
private final Handler mHandler;
NativeRoutingEventHandlerDelegate(final AudioRecord record,
- final OnRoutingChangedListener listener,
+ final AudioRouting.OnRoutingChangedListener listener,
Handler handler) {
// find the looper for our new event handler
Looper looper;
@@ -1571,26 +1517,12 @@
*/
private void broadcastRoutingChange() {
AudioManager.resetAudioPortGeneration();
- // Marshmallow Routing
- Collection<NativeRoutingEventHandlerDelegate> values;
synchronized (mRoutingChangeListeners) {
- values = mRoutingChangeListeners.values();
- }
- for(NativeRoutingEventHandlerDelegate delegate : values) {
- Handler handler = delegate.getHandler();
- if (handler != null) {
- handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE);
- }
- }
- // >= "N" Routing
- Collection<NativeNewRoutingEventHandlerDelegate> newValues;
- synchronized (mNewRoutingChangeListeners) {
- newValues = mNewRoutingChangeListeners.values();
- }
- for(NativeNewRoutingEventHandlerDelegate delegate : newValues) {
- Handler handler = delegate.getHandler();
- if (handler != null) {
- handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE);
+ for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) {
+ Handler handler = delegate.getHandler();
+ if (handler != null) {
+ handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE);
+ }
}
}
}
@@ -1623,6 +1555,7 @@
* @return true if successful, false if the specified {@link AudioDeviceInfo} is non-null and
* does not correspond to a valid audio input device.
*/
+ @Override
public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) {
// Do some validation....
if (deviceInfo != null && !deviceInfo.isSource()) {
@@ -1643,6 +1576,7 @@
* Returns the selected input specified by {@link #setPreferredDevice}. Note that this
* is not guarenteed to correspond to the actual device being used for recording.
*/
+ @Override
public AudioDeviceInfo getPreferredDevice() {
synchronized (this) {
return mPreferredDevice;
@@ -1683,7 +1617,6 @@
* (potentially) handled in a different thread
*/
private class NativeEventHandler extends Handler {
-
private final AudioRecord mAudioRecord;
NativeEventHandler(AudioRecord recorder, Looper looper) {
@@ -1714,8 +1647,7 @@
break;
}
}
- };
-
+ }
//---------------------------------------------------------
// Java methods called from the native side
diff --git a/media/java/android/media/AudioRouting.java b/media/java/android/media/AudioRouting.java
index 41f92d4..26fa631 100644
--- a/media/java/android/media/AudioRouting.java
+++ b/media/java/android/media/AudioRouting.java
@@ -57,7 +57,7 @@
* the callback. If <code>null</code>, the {@link Handler} associated with the main
* {@link Looper} will be used.
*/
- public void addOnRoutingListener(OnRoutingChangedListener listener,
+ public void addOnRoutingChangedListener(OnRoutingChangedListener listener,
Handler handler);
/**
@@ -66,7 +66,7 @@
* @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
* to remove.
*/
- public void removeOnRoutingListener(OnRoutingChangedListener listener);
+ public void removeOnRoutingChangedListener(OnRoutingChangedListener listener);
/**
* Defines the interface by which applications can receive notifications of routing
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 621129d..9d360db 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -40,6 +40,7 @@
import android.util.ArrayMap;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsService;
/**
@@ -1489,6 +1490,7 @@
* @deprecated Applications should use {@link #setVolume} instead, as it
* more gracefully scales down to mono, and up to multi-channel content beyond stereo.
*/
+ @Deprecated
public int setStereoVolume(float leftGain, float rightGain) {
if (isRestricted()) {
return SUCCESS;
@@ -2397,6 +2399,7 @@
* @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and
* does not correspond to a valid audio output device.
*/
+ @Override
public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) {
// Do some validation....
if (deviceInfo != null && !deviceInfo.isSink()) {
@@ -2416,6 +2419,7 @@
* Returns the selected output specified by {@link #setPreferredDevice}. Note that this
* is not guaranteed to correspond to the actual device being used for playback.
*/
+ @Override
public AudioDeviceInfo getPreferredDevice() {
synchronized (this) {
return mPreferredDevice;
@@ -2427,6 +2431,7 @@
* Note: The query is only valid if the AudioTrack is currently playing. If it is not,
* <code>getRoutedDevice()</code> will return null.
*/
+ @Override
public AudioDeviceInfo getRoutedDevice() {
int deviceId = native_getRoutedDeviceId();
if (deviceId == 0) {
@@ -2445,8 +2450,8 @@
/*
* Call BEFORE adding a routing callback handler.
*/
- private void testEnableNativeRoutingCallbacks() {
- if (mRoutingChangeListeners.size() == 0 && mNewRoutingChangeListeners.size() == 0) {
+ private void testEnableNativeRoutingCallbacksLocked() {
+ if (mRoutingChangeListeners.size() == 0) {
native_enableDeviceCallback();
}
}
@@ -2454,24 +2459,23 @@
/*
* Call AFTER removing a routing callback handler.
*/
- private void testDisableNativeRoutingCallbacks() {
- if (mRoutingChangeListeners.size() == 0 && mNewRoutingChangeListeners.size() == 0) {
+ private void testDisableNativeRoutingCallbacksLocked() {
+ if (mRoutingChangeListeners.size() == 0) {
native_disableDeviceCallback();
}
}
//--------------------------------------------------------------------------
- // >= "N" (Re)Routing Info
+ // (Re)Routing Info
//--------------------
/**
* The list of AudioRouting.OnRoutingChangedListener interfaces added (with
- * {@link AudioTrack#addOnRoutingListener(AudioRouting.OnRoutingChangedListener,
- * android.os.Handler)}
- * by an app to receive (re)routing notifications.
+ * {@link AudioRecord#addOnRoutingChangedListener} by an app to receive
+ * (re)routing notifications.
*/
- private ArrayMap<AudioRouting.OnRoutingChangedListener, NativeNewRoutingEventHandlerDelegate>
- mNewRoutingChangeListeners =
- new ArrayMap<AudioRouting.OnRoutingChangedListener, NativeNewRoutingEventHandlerDelegate>();
+ @GuardedBy("mRoutingChangeListeners")
+ private ArrayMap<AudioRouting.OnRoutingChangedListener,
+ NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
/**
* Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
@@ -2482,14 +2486,15 @@
* the callback. If <code>null</code>, the {@link Handler} associated with the main
* {@link Looper} will be used.
*/
- public void addOnRoutingListener(AudioRouting.OnRoutingChangedListener listener,
+ @Override
+ public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener,
Handler handler) {
- if (listener != null && !mNewRoutingChangeListeners.containsKey(listener)) {
- synchronized (mNewRoutingChangeListeners) {
- testEnableNativeRoutingCallbacks();
- mNewRoutingChangeListeners.put(
- listener, new NativeNewRoutingEventHandlerDelegate(this, listener,
- handler != null ? handler : new Handler(mInitializationLooper)));
+ synchronized (mRoutingChangeListeners) {
+ if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
+ testEnableNativeRoutingCallbacksLocked();
+ mRoutingChangeListeners.put(
+ listener, new NativeRoutingEventHandlerDelegate(this, listener,
+ handler != null ? handler : new Handler(mInitializationLooper)));
}
}
}
@@ -2500,39 +2505,42 @@
* @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
* to remove.
*/
- public void removeOnRoutingListener(AudioRouting.OnRoutingChangedListener listener) {
- if (mNewRoutingChangeListeners.containsKey(listener)) {
- mNewRoutingChangeListeners.remove(listener);
+ @Override
+ public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) {
+ synchronized (mRoutingChangeListeners) {
+ if (mRoutingChangeListeners.containsKey(listener)) {
+ mRoutingChangeListeners.remove(listener);
+ }
+ testDisableNativeRoutingCallbacksLocked();
}
- testDisableNativeRoutingCallbacks();
}
//--------------------------------------------------------------------------
- // Marshmallow (Re)Routing Info
+ // (Re)Routing Info
//--------------------
/**
- * Defines the interface by which applications can receive notifications of routing
- * changes for the associated {@link AudioTrack}.
+ * Defines the interface by which applications can receive notifications of
+ * routing changes for the associated {@link AudioTrack}.
+ *
+ * @deprecated users should switch to the general purpose
+ * {@link AudioRouting.OnRoutingChangedListener} class instead.
*/
@Deprecated
- public interface OnRoutingChangedListener {
+ public interface OnRoutingChangedListener extends AudioRouting.OnRoutingChangedListener {
/**
- * Called when the routing of an AudioTrack changes from either and explicit or
- * policy rerouting. Use {@link #getRoutedDevice()} to retrieve the newly routed-to
- * device.
+ * Called when the routing of an AudioTrack changes from either and
+ * explicit or policy rerouting. Use {@link #getRoutedDevice()} to
+ * retrieve the newly routed-to device.
*/
- @Deprecated
public void onRoutingChanged(AudioTrack audioTrack);
- }
- /**
- * The list of AudioTrack.OnRoutingChangedListener interfaces added (with
- * {@link AudioTrack#addOnRoutingChangedListener(OnRoutingChangedListener, android.os.Handler)}
- * by an app to receive (re)routing notifications.
- */
- private ArrayMap<OnRoutingChangedListener, NativeRoutingEventHandlerDelegate>
- mRoutingChangeListeners =
- new ArrayMap<OnRoutingChangedListener, NativeRoutingEventHandlerDelegate>();
+ @Override
+ default public void onRoutingChanged(AudioRouting router) {
+ if (router instanceof AudioTrack) {
+ onRoutingChanged((AudioTrack) router);
+ }
+ }
+ }
/**
* Adds an {@link OnRoutingChangedListener} to receive notifications of routing changes
@@ -2542,33 +2550,25 @@
* @param handler Specifies the {@link Handler} object for the thread on which to execute
* the callback. If <code>null</code>, the {@link Handler} associated with the main
* {@link Looper} will be used.
+ * @deprecated users should switch to the general purpose
+ * {@link AudioRouting.OnRoutingChangedListener} class instead.
*/
@Deprecated
public void addOnRoutingChangedListener(OnRoutingChangedListener listener,
android.os.Handler handler) {
- if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
- synchronized (mRoutingChangeListeners) {
- testEnableNativeRoutingCallbacks();
- mRoutingChangeListeners.put(
- listener, new NativeRoutingEventHandlerDelegate(this, listener,
- handler != null ? handler : new Handler(mInitializationLooper)));
- }
- }
+ addOnRoutingChangedListener((AudioRouting.OnRoutingChangedListener) listener, handler);
}
/**
* Removes an {@link OnRoutingChangedListener} which has been previously added
* to receive rerouting notifications.
* @param listener The previously added {@link OnRoutingChangedListener} interface to remove.
+ * @deprecated users should switch to the general purpose
+ * {@link AudioRouting.OnRoutingChangedListener} class instead.
*/
@Deprecated
public void removeOnRoutingChangedListener(OnRoutingChangedListener listener) {
- synchronized (mRoutingChangeListeners) {
- if (mRoutingChangeListeners.containsKey(listener)) {
- mRoutingChangeListeners.remove(listener);
- }
- testDisableNativeRoutingCallbacks();
- }
+ removeOnRoutingChangedListener((AudioRouting.OnRoutingChangedListener) listener);
}
/**
@@ -2576,27 +2576,12 @@
*/
private void broadcastRoutingChange() {
AudioManager.resetAudioPortGeneration();
-
- // Marshmallow Routing
- Collection<NativeRoutingEventHandlerDelegate> values;
synchronized (mRoutingChangeListeners) {
- values = mRoutingChangeListeners.values();
- }
- for(NativeRoutingEventHandlerDelegate delegate : values) {
- Handler handler = delegate.getHandler();
- if (handler != null) {
- handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE);
- }
- }
- // >= "N" Routing
- Collection<NativeNewRoutingEventHandlerDelegate> newValues;
- synchronized (mNewRoutingChangeListeners) {
- newValues = mNewRoutingChangeListeners.values();
- }
- for(NativeNewRoutingEventHandlerDelegate delegate : newValues) {
- Handler handler = delegate.getHandler();
- if (handler != null) {
- handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE);
+ for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) {
+ Handler handler = delegate.getHandler();
+ if (handler != null) {
+ handler.sendEmptyMessage(AudioSystem.NATIVE_EVENT_ROUTING_CHANGE);
+ }
}
}
}
@@ -2681,7 +2666,6 @@
}
/**
- * Marshmallow Routing API.
* Helper class to handle the forwarding of native events to the appropriate listener
* (potentially) handled in a different thread
*/
@@ -2689,57 +2673,6 @@
private final Handler mHandler;
NativeRoutingEventHandlerDelegate(final AudioTrack track,
- final OnRoutingChangedListener listener,
- Handler handler) {
- // find the looper for our new event handler
- Looper looper;
- if (handler != null) {
- looper = handler.getLooper();
- } else {
- // no given handler, use the looper the AudioTrack was created in
- looper = mInitializationLooper;
- }
-
- // construct the event handler with this looper
- if (looper != null) {
- // implement the event handler delegate
- mHandler = new Handler(looper) {
- @Override
- public void handleMessage(Message msg) {
- if (track == null) {
- return;
- }
- switch(msg.what) {
- case AudioSystem.NATIVE_EVENT_ROUTING_CHANGE:
- if (listener != null) {
- listener.onRoutingChanged(track);
- }
- break;
- default:
- loge("Unknown native event type: " + msg.what);
- break;
- }
- }
- };
- } else {
- mHandler = null;
- }
- }
-
- Handler getHandler() {
- return mHandler;
- }
- }
-
- /**
- * Marshmallow Routing API.
- * Helper class to handle the forwarding of native events to the appropriate listener
- * (potentially) handled in a different thread
- */
- private class NativeNewRoutingEventHandlerDelegate {
- private final Handler mHandler;
-
- NativeNewRoutingEventHandlerDelegate(final AudioTrack track,
final AudioRouting.OnRoutingChangedListener listener,
Handler handler) {
// find the looper for our new event handler
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 2bd9781..7af9c24 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -2611,10 +2611,13 @@
public static final int VP8ProfileMain = 0x01;
// from OMX_VIDEO_VP9PROFILETYPE
- public static final int VP9Profile0 = 0x00;
- public static final int VP9Profile1 = 0x01;
- public static final int VP9Profile2 = 0x02;
- public static final int VP9Profile3 = 0x03;
+ public static final int VP9Profile0 = 0x01;
+ public static final int VP9Profile1 = 0x02;
+ public static final int VP9Profile2 = 0x04;
+ public static final int VP9Profile3 = 0x08;
+ // HDR profiles also support passing HDR metadata
+ public static final int VP9Profile2HDR = 0x1000;
+ public static final int VP9Profile3HDR = 0x2000;
// from OMX_VIDEO_VP9LEVELTYPE
public static final int VP9Level1 = 0x0;
diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java
index e623353..d718a7e 100644
--- a/media/java/android/media/tv/TvTrackInfo.java
+++ b/media/java/android/media/tv/TvTrackInfo.java
@@ -20,9 +20,12 @@
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import com.android.internal.util.Preconditions;
+import java.util.Objects;
+
/**
* Encapsulates the format of tracks played in {@link TvInputService}.
*/
@@ -245,6 +248,37 @@
dest.writeBundle(mExtra);
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof TvTrackInfo)) {
+ return false;
+ }
+
+ TvTrackInfo obj = (TvTrackInfo) o;
+ return TextUtils.equals(mId, obj.mId)
+ && mType == obj.mType
+ && TextUtils.equals(mLanguage, obj.mLanguage)
+ && TextUtils.equals(mDescription, obj.mDescription)
+ && Objects.equals(mExtra, obj.mExtra)
+ && (mType == TYPE_AUDIO
+ ? mAudioChannelCount == obj.mAudioChannelCount
+ && mAudioSampleRate == obj.mAudioSampleRate
+ : (mType == TYPE_VIDEO
+ ? mVideoWidth == obj.mVideoWidth
+ && mVideoHeight == obj.mVideoHeight
+ && mVideoFrameRate == obj.mVideoFrameRate
+ && mVideoPixelAspectRatio == obj.mVideoPixelAspectRatio : true));
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(mId);
+ }
+
public static final Parcelable.Creator<TvTrackInfo> CREATOR =
new Parcelable.Creator<TvTrackInfo>() {
@Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 40b54d3..7a7d3a1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -232,12 +232,13 @@
final MenuItem list = menu.findItem(R.id.menu_list);
final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
- boolean recents = cwd == null;
- createDir.setVisible(picking && !recents && cwd.isCreateSupported());
+ createDir.setVisible(picking);
+ createDir.setEnabled(canCreateDirectory());
// No display options in recent directories
- if (picking && recents) {
+ boolean inRecents = cwd == null;
+ if (picking && inRecents) {
grid.setVisible(false);
list.setVisible(false);
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index bc2133e..aa9f356 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -833,6 +833,15 @@
getActivity(),
DocumentsActivity.class);
+
+ // Relay any config overrides bits present in the original intent.
+ Intent original = getActivity().getIntent();
+ if (original != null && original.hasExtra(Shared.EXTRA_PRODUCTIVITY_MODE)) {
+ intent.putExtra(
+ Shared.EXTRA_PRODUCTIVITY_MODE,
+ original.getBooleanExtra(Shared.EXTRA_PRODUCTIVITY_MODE, false));
+ }
+
// Set an appropriate title on the drawer when it is shown in the picker.
// Coupled with the fact that we auto-open the drawer for copy/move operations
// it should basically be the thing people see first.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
index ab21532..f34df75 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -16,13 +16,18 @@
package com.android.systemui.qs.external;
import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
import android.os.Handler;
import android.os.UserHandle;
import android.service.quicksettings.IQSTileService;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
+import libcore.util.Objects;
/**
* Manages the priority which lets {@link TileServices} make decisions about which tiles
@@ -68,6 +73,12 @@
mHandler = handler;
mStateManager = tileLifecycleManager;
mStateManager.setQSService(tileServices);
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addDataScheme("package");
+ mServices.getContext().registerReceiverAsUser(mUninstallReceiver,
+ new UserHandle(ActivityManager.getCurrentUser()), filter, null, mHandler);
}
public boolean isActiveTile() {
@@ -106,6 +117,7 @@
}
public void handleDestroy() {
+ mServices.getContext().unregisterReceiver(mUninstallReceiver);
mStateManager.handleDestroy();
}
@@ -198,4 +210,23 @@
mServices.recalculateBindAllowance();
}
};
+
+ private final BroadcastReceiver mUninstallReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (!Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+ return;
+ }
+ if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ return;
+ }
+ Uri data = intent.getData();
+ String pkgName = data.getEncodedSchemeSpecificPart();
+ final ComponentName component = mStateManager.getComponent();
+ if (!Objects.equal(pkgName, component.getPackageName())) {
+ return;
+ }
+ mServices.getHost().removeTile(component);
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index f36d013..2ab6b5f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -72,6 +72,10 @@
return mContext;
}
+ public QSTileHost getHost() {
+ return mHost;
+ }
+
public TileServiceManager getTileWrapper(CustomTile tile) {
ComponentName component = tile.getComponent();
TileServiceManager service = onCreateTileService(component);
@@ -89,6 +93,7 @@
public void freeService(CustomTile tile, TileServiceManager service) {
synchronized (mServices) {
service.setBindAllowed(false);
+ service.handleDestroy();
mServices.remove(tile);
mTiles.remove(tile.getComponent());
final String slot = tile.getComponent().getClassName();
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 3005535..98e0dd9 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -31,12 +31,13 @@
import android.graphics.Region.Op;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
+import android.os.Vibrator;
import android.util.AttributeSet;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.GestureDetector;
-import android.view.GestureDetector.OnDoubleTapListener;
import android.view.GestureDetector.SimpleOnGestureListener;
+import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.VelocityTracker;
@@ -45,7 +46,6 @@
import android.view.ViewConfiguration;
import android.view.ViewTreeObserver.InternalInsetsInfo;
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
-import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -866,6 +866,9 @@
mEntranceAnimationRunning = true;
resizeStack(position, mSnapAlgorithm.getMiddleTarget().position,
mSnapAlgorithm.getMiddleTarget());
+
+ // Vibrate after docking
+ performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
}
public final void onBusEvent(RecentsDrawnEvent drawnEvent) {
@@ -894,6 +897,9 @@
// Don't start immediately - give a little bit time to settle the drag resize change.
stopDragging(getCurrentPosition(), target, 336 /* duration */, 100 /* startDelay */,
Interpolators.TOUCH_RESPONSE);
+
+ // Vibrate after undocking
+ performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0f48d21..3ec51e3 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13164,6 +13164,9 @@
}
}
+ private volatile long mWtfClusterStart;
+ private volatile int mWtfClusterCount;
+
/**
* Write a description of an error (crash, WTF, ANR) to the drop box.
* @param eventType to include in the drop box tag ("crash", "wtf", etc.)
@@ -13190,6 +13193,16 @@
// Exit early if the dropbox isn't configured to accept this report type.
if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return;
+ // Rate-limit how often we're willing to do the heavy lifting below to
+ // collect and record logs; currently 5 logs per 10 second period.
+ final long now = SystemClock.elapsedRealtime();
+ if (now - mWtfClusterStart > 10 * DateUtils.SECOND_IN_MILLIS) {
+ mWtfClusterStart = now;
+ mWtfClusterCount = 1;
+ } else {
+ if (mWtfClusterCount++ >= 5) return;
+ }
+
final StringBuilder sb = new StringBuilder(1024);
appendDropBoxProcessHeaders(process, processName, sb);
if (process != null) {
@@ -17131,7 +17144,7 @@
// but historically it has not been protected and apps may be using it
// to poke their own app widget. So, instead of making it protected,
// just limit it to the caller.
- if (callerApp == null) {
+ if (callerPackage == null) {
String msg = "Permission Denial: not allowed to send broadcast "
+ action + " from unknown caller.";
Slog.w(TAG, msg);
@@ -17140,17 +17153,17 @@
// They are good enough to send to an explicit component... verify
// it is being sent to the calling app.
if (!intent.getComponent().getPackageName().equals(
- callerApp.info.packageName)) {
+ callerPackage)) {
String msg = "Permission Denial: not allowed to send broadcast "
+ action + " to "
+ intent.getComponent().getPackageName() + " from "
- + callerApp.info.packageName;
+ + callerPackage;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
} else {
// Limit broadcast to their own package.
- intent.setPackage(callerApp.info.packageName);
+ intent.setPackage(callerPackage);
}
}
}
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
index 1825c88..0e192ea 100644
--- a/services/core/java/com/android/server/am/PreBootBroadcaster.java
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -69,6 +69,12 @@
return;
}
+ if (!mService.isUserRunning(mUserId, 0)) {
+ Slog.i(TAG, "User " + mUserId + " is no longer running; skipping remaining receivers");
+ onFinished();
+ return;
+ }
+
final ResolveInfo ri = mTargets.get(mIndex++);
final ComponentName componentName = ri.activityInfo.getComponentName();
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index fb3c6ec..fe32104 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -49,6 +49,7 @@
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
+import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
@@ -265,70 +266,134 @@
*/
private void generateCrop(WallpaperData wallpaper) {
boolean success = false;
- boolean needCrop = false;
- boolean needScale = false;
+
+ Rect cropHint = new Rect(wallpaper.cropHint);
if (DEBUG) {
Slog.v(TAG, "Generating crop for new wallpaper(s): 0x"
+ Integer.toHexString(wallpaper.whichPending)
- + " to " + wallpaper.cropFile.getName());
+ + " to " + wallpaper.cropFile.getName()
+ + " crop=(" + cropHint.width() + 'x' + cropHint.height()
+ + ") dim=(" + wallpaper.width + 'x' + wallpaper.height + ')');
}
// Analyse the source; needed in multiple cases
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(wallpaper.wallpaperFile.getAbsolutePath(), options);
-
- // We'll need to scale if the crop is sufficiently bigger than the display
-
- // Legacy case uses an empty crop rect here, so we just preserve the
- // source image verbatim
- if (!wallpaper.cropHint.isEmpty()) {
- // ...clamp the crop rect to the measured bounds...
- wallpaper.cropHint.right = Math.min(wallpaper.cropHint.right, options.outWidth);
- wallpaper.cropHint.bottom = Math.min(wallpaper.cropHint.bottom, options.outHeight);
- // ...and don't bother cropping if what we're left with is identity
- needCrop = (options.outHeight >= wallpaper.cropHint.height()
- && options.outWidth >= wallpaper.cropHint.width());
- }
-
- if (!needCrop && !needScale) {
- // Simple case: the nominal crop is at least as big as the source image,
- // so we take the whole thing and just copy the image file directly.
- if (DEBUG) {
- Slog.v(TAG, "Null crop of new wallpaper; copying");
- }
- success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile);
- if (!success) {
- wallpaper.cropFile.delete();
- // TODO: fall back to default wallpaper in this case
- }
+ if (options.outWidth <= 0 || options.outHeight <= 0) {
+ Slog.e(TAG, "Invalid wallpaper data");
+ success = false;
} else {
- // Fancy case: crop and/or scale
- FileOutputStream f = null;
- BufferedOutputStream bos = null;
- try {
- BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(
- wallpaper.wallpaperFile.getAbsolutePath(), false);
- Bitmap cropped = decoder.decodeRegion(wallpaper.cropHint, null);
- decoder.recycle();
+ boolean needCrop = false;
+ boolean needScale = false;
- if (cropped == null) {
- Slog.e(TAG, "Could not decode new wallpaper");
- } else {
- f = new FileOutputStream(wallpaper.cropFile);
- bos = new BufferedOutputStream(f, 32*1024);
- cropped.compress(Bitmap.CompressFormat.PNG, 90, bos);
- bos.flush(); // don't rely on the implicit flush-at-close when noting success
- success = true;
- }
- } catch (IOException e) {
+ // Empty crop means use the full image
+ if (cropHint.isEmpty()) {
+ cropHint.left = cropHint.top = 0;
+ cropHint.right = options.outWidth;
+ cropHint.bottom = options.outHeight;
+ } else {
+ // force the crop rect to lie within the measured bounds
+ cropHint.offset(
+ (cropHint.right > options.outWidth ? options.outWidth - cropHint.right : 0),
+ (cropHint.bottom > options.outHeight ? options.outHeight - cropHint.bottom : 0));
+
+ // Don't bother cropping if what we're left with is identity
+ needCrop = (options.outHeight >= cropHint.height()
+ && options.outWidth >= cropHint.width());
+ }
+
+ // scale if the crop height winds up not matching the recommended metrics
+ needScale = (wallpaper.height != cropHint.height());
+
+ if (DEBUG) {
+ Slog.v(TAG, "crop: w=" + cropHint.width() + " h=" + cropHint.height());
+ Slog.v(TAG, "dims: w=" + wallpaper.width + " h=" + wallpaper.height);
+ Slog.v(TAG, "meas: w=" + options.outWidth + " h=" + options.outHeight);
+ Slog.v(TAG, "crop?=" + needCrop + " scale?=" + needScale);
+ }
+
+ if (!needCrop && !needScale) {
+ // Simple case: the nominal crop fits what we want, so we take
+ // the whole thing and just copy the image file directly.
if (DEBUG) {
- Slog.e(TAG, "I/O error decoding crop: " + e.getMessage());
+ Slog.v(TAG, "Null crop of new wallpaper; copying");
}
- } finally {
- IoUtils.closeQuietly(bos);
- IoUtils.closeQuietly(f);
+ success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile);
+ if (!success) {
+ wallpaper.cropFile.delete();
+ // TODO: fall back to default wallpaper in this case
+ }
+ } else {
+ // Fancy case: crop and scale. First, we decode and scale down if appropriate.
+ FileOutputStream f = null;
+ BufferedOutputStream bos = null;
+ try {
+ BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(
+ wallpaper.wallpaperFile.getAbsolutePath(), false);
+
+ // This actually downsamples only by powers of two, but that's okay; we do
+ // a proper scaling blit later. This is to minimize transient RAM use.
+ // We calculate the largest power-of-two under the actual ratio rather than
+ // just let the decode take care of it because we also want to remap where the
+ // cropHint rectangle lies in the decoded [super]rect.
+ final BitmapFactory.Options scaler;
+ final int actualScale = cropHint.height() / wallpaper.height;
+ int scale = 1;
+ while (2*scale < actualScale) {
+ scale *= 2;
+ }
+ if (scale > 1) {
+ scaler = new BitmapFactory.Options();
+ scaler.inSampleSize = scale;
+ if (DEBUG) {
+ Slog.v(TAG, "Downsampling cropped rect with scale " + scale);
+ }
+ } else {
+ scaler = null;
+ }
+ Bitmap cropped = decoder.decodeRegion(cropHint, scaler);
+ decoder.recycle();
+
+ if (cropped == null) {
+ Slog.e(TAG, "Could not decode new wallpaper");
+ } else {
+ // We've got the extracted crop; now we want to scale it properly to
+ // the desired rectangle. That's a height-biased operation: make it
+ // fit the hinted height, and accept whatever width we end up with.
+ cropHint.offsetTo(0, 0);
+ cropHint.right /= scale; // adjust by downsampling factor
+ cropHint.bottom /= scale;
+ final float heightR = ((float)wallpaper.height) / ((float)cropHint.height());
+ if (DEBUG) {
+ Slog.v(TAG, "scale " + heightR + ", extracting " + cropHint);
+ }
+ final int destWidth = (int)(cropHint.width() * heightR);
+ final Bitmap finalCrop = Bitmap.createScaledBitmap(cropped,
+ destWidth, wallpaper.height, true);
+ if (DEBUG) {
+ Slog.v(TAG, "Final extract:");
+ Slog.v(TAG, " dims: w=" + wallpaper.width
+ + " h=" + wallpaper.height);
+ Slog.v(TAG, " out: w=" + finalCrop.getWidth()
+ + " h=" + finalCrop.getHeight());
+ }
+
+ f = new FileOutputStream(wallpaper.cropFile);
+ bos = new BufferedOutputStream(f, 32*1024);
+ finalCrop.compress(Bitmap.CompressFormat.PNG, 90, bos);
+ bos.flush(); // don't rely on the implicit flush-at-close when noting success
+ success = true;
+ }
+ } catch (Exception e) {
+ if (DEBUG) {
+ Slog.e(TAG, "Error decoding crop", e);
+ }
+ } finally {
+ IoUtils.closeQuietly(bos);
+ IoUtils.closeQuietly(f);
+ }
}
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 0aeb96f..ecfeff9 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -152,6 +152,7 @@
private ArrayList<UsageStatsManagerInternal.AppIdleStateChangeListener>
mPackageAccessListeners = new ArrayList<>();
+ private boolean mHaveCarrierPrivilegedApps;
private List<String> mCarrierPrivilegedApps;
public UsageStatsService(Context context) {
@@ -931,11 +932,14 @@
private boolean isCarrierApp(String packageName) {
synchronized (mLock) {
- if (mCarrierPrivilegedApps == null) {
+ if (!mHaveCarrierPrivilegedApps) {
fetchCarrierPrivilegedAppsLocked();
}
+ if (mCarrierPrivilegedApps != null) {
+ return mCarrierPrivilegedApps.contains(packageName);
+ }
+ return false;
}
- return mCarrierPrivilegedApps.contains(packageName);
}
void clearCarrierPrivilegedApps() {
@@ -943,6 +947,7 @@
Slog.i(TAG, "Clearing carrier privileged apps list");
}
synchronized (mLock) {
+ mHaveCarrierPrivilegedApps = false;
mCarrierPrivilegedApps = null; // Need to be refetched.
}
}
@@ -951,6 +956,7 @@
TelephonyManager telephonyManager =
getContext().getSystemService(TelephonyManager.class);
mCarrierPrivilegedApps = telephonyManager.getPackagesWithCarrierPrivileges();
+ mHaveCarrierPrivilegedApps = true;
if (DEBUG) {
Slog.d(TAG, "apps with carrier privilege " + mCarrierPrivilegedApps);
}
@@ -1024,7 +1030,8 @@
}
pw.println();
- pw.println("Carrier privileged apps: " + mCarrierPrivilegedApps);
+ pw.println("Carrier privileged apps (have=" + mHaveCarrierPrivilegedApps
+ + "): " + mCarrierPrivilegedApps);
pw.println();
pw.println("Settings:");
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index fcb967f..ccabace 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -102,6 +102,7 @@
public static final int CMD_NET_STAT_POLL = BASE + 40;
public static final int EVENT_DATA_RAT_CHANGED = BASE + 41;
public static final int CMD_CLEAR_PROVISIONING_SPINNER = BASE + 42;
+ public static final int EVENT_DEVICE_PROVISIONED_CHANGE = BASE + 43;
/***** Constants *****/
diff --git a/tests/SoundTriggerTestApp/res/layout/main.xml b/tests/SoundTriggerTestApp/res/layout/main.xml
index 702be49..06949a0 100644
--- a/tests/SoundTriggerTestApp/res/layout/main.xml
+++ b/tests/SoundTriggerTestApp/res/layout/main.xml
@@ -60,29 +60,22 @@
android:onClick="onUnEnrollButtonClicked"
android:padding="20dp" />
+ <Button
+ android:id="@+id/play_trigger_id"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/play_trigger"
+ android:onClick="onPlayTriggerButtonClicked"
+ android:padding="20dp" />
+
</LinearLayout>
<RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/model_group_id"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="20dp"
- android:checkedButton="@+id/model_one"
android:orientation="vertical">
- <RadioButton android:id="@+id/model_one"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/model_one"
- android:onClick="onRadioButtonClicked"/>
- <RadioButton android:id="@+id/model_two"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/model_two"
- android:onClick="onRadioButtonClicked"/>
- <RadioButton android:id="@+id/model_three"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/model_three"
- android:onClick="onRadioButtonClicked"/>
</RadioGroup>
<ScrollView
@@ -93,7 +86,7 @@
android:fillViewport="true">
<TextView
- android:id="@+id/console"
+ android:id="@+id/console"
android:paddingTop="20pt"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
diff --git a/tests/SoundTriggerTestApp/res/values/strings.xml b/tests/SoundTriggerTestApp/res/values/strings.xml
index b4ca71b..7c1f649 100644
--- a/tests/SoundTriggerTestApp/res/values/strings.xml
+++ b/tests/SoundTriggerTestApp/res/values/strings.xml
@@ -21,8 +21,6 @@
<string name="unenroll">Un-load</string>
<string name="start_recog">Start</string>
<string name="stop_recog">Stop</string>
- <string name="model_one">Model One</string>
- <string name="model_two">Model Two</string>
- <string name="model_three">Model Three</string>
+ <string name="play_trigger">Play Trigger Audio</string>
<string name="none">Debug messages appear here:\n</string>
</resources>
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java
index 3ca96d2..5fd38e9 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java
@@ -16,24 +16,36 @@
package com.android.test.soundtrigger;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
import java.util.Random;
import java.util.UUID;
import android.app.Activity;
-import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
+import android.hardware.soundtrigger.SoundTrigger;
import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
import android.media.soundtrigger.SoundTriggerDetector;
import android.media.soundtrigger.SoundTriggerManager;
-import android.text.Editable;
-import android.text.method.ScrollingMovementMethod;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
import android.os.UserManager;
+import android.text.Editable;
+import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.View;
+import android.widget.Button;
import android.widget.RadioButton;
+import android.widget.RadioButton;
+import android.widget.RadioGroup;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
@@ -44,20 +56,17 @@
private SoundTriggerUtil mSoundTriggerUtil;
private Random mRandom;
- private UUID mModelUuid1 = UUID.randomUUID();
- private UUID mModelUuid2 = UUID.randomUUID();
- private UUID mModelUuid3 = UUID.randomUUID();
- private UUID mVendorUuid = UUID.randomUUID();
- private SoundTriggerDetector mDetector1 = null;
- private SoundTriggerDetector mDetector2 = null;
- private SoundTriggerDetector mDetector3 = null;
+ private Map<Integer, ModelInfo> mModelInfoMap;
+ private Map<View, Integer> mModelIdMap;
private TextView mDebugView = null;
- private int mSelectedModelId = 1;
+ private int mSelectedModelId = -1;
private ScrollView mScrollView = null;
+ private Button mPlayTriggerButton = null;
private PowerManager.WakeLock mScreenWakelock;
private Handler mHandler;
+ private RadioGroup mRadioGroup;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -66,11 +75,108 @@
setContentView(R.layout.main);
mDebugView = (TextView) findViewById(R.id.console);
mScrollView = (ScrollView) findViewById(R.id.scroller_id);
+ mRadioGroup = (RadioGroup) findViewById(R.id.model_group_id);
+ mPlayTriggerButton = (Button) findViewById(R.id.play_trigger_id);
mDebugView.setText(mDebugView.getText(), TextView.BufferType.EDITABLE);
mDebugView.setMovementMethod(new ScrollingMovementMethod());
mSoundTriggerUtil = new SoundTriggerUtil(this);
mRandom = new Random();
mHandler = new Handler();
+
+ mModelInfoMap = new HashMap();
+ mModelIdMap = new HashMap();
+
+ setVolumeControlStream(AudioManager.STREAM_MUSIC);
+
+ // Load all the models in the data dir.
+ for (File file : getFilesDir().listFiles()) {
+ // Find meta-data in .properties files, ignore everything else.
+ if (!file.getName().endsWith(".properties")) {
+ continue;
+ }
+ try {
+ Properties properties = new Properties();
+ properties.load(new FileInputStream(file));
+ createModelInfoAndWidget(properties);
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to load properties file " + file.getName());
+ }
+ }
+
+ // Create a few dummy models if we didn't load anything.
+ if (mModelIdMap.isEmpty()) {
+ Properties dummyModelProperties = new Properties();
+ for (String name : new String[]{"One", "Two", "Three"}) {
+ dummyModelProperties.setProperty("name", "Model " + name);
+ createModelInfoAndWidget(dummyModelProperties);
+ }
+ }
+ }
+
+ private void createModelInfoAndWidget(Properties properties) {
+ try {
+ ModelInfo modelInfo = new ModelInfo();
+
+ if (!properties.containsKey("name")) {
+ throw new RuntimeException("must have a 'name' property");
+ }
+ modelInfo.name = properties.getProperty("name");
+
+ if (properties.containsKey("modelUuid")) {
+ modelInfo.modelUuid = UUID.fromString(properties.getProperty("modelUuid"));
+ } else {
+ modelInfo.modelUuid = UUID.randomUUID();
+ }
+
+ if (properties.containsKey("vendorUuid")) {
+ modelInfo.vendorUuid = UUID.fromString(properties.getProperty("vendorUuid"));
+ } else {
+ modelInfo.vendorUuid = UUID.randomUUID();
+ }
+
+ if (properties.containsKey("triggerAudio")) {
+ modelInfo.triggerAudioPlayer = MediaPlayer.create(this, Uri.parse(
+ getFilesDir().getPath() + "/" + properties.getProperty("triggerAudio")));
+ }
+
+ if (properties.containsKey("dataFile")) {
+ File modelDataFile = new File(
+ getFilesDir().getPath() + "/" + properties.getProperty("dataFile"));
+ modelInfo.modelData = new byte[(int) modelDataFile.length()];
+ FileInputStream input = new FileInputStream(modelDataFile);
+ input.read(modelInfo.modelData, 0, modelInfo.modelData.length);
+ } else {
+ modelInfo.modelData = new byte[1024];
+ mRandom.nextBytes(modelInfo.modelData);
+ }
+
+ // TODO: Add property support for keyphrase models when they're exposed by the
+ // service. Also things like how much audio they should record with the capture session
+ // provided in the callback.
+
+ // Add a widget into the radio group.
+ RadioButton button = new RadioButton(this);
+ mRadioGroup.addView(button);
+ button.setText(modelInfo.name);
+ button.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ onRadioButtonClicked(v);
+ }
+ });
+
+ // Update our maps containing the button -> id and id -> modelInfo.
+ int newModelId = mModelIdMap.size() + 1;
+ mModelIdMap.put(button, newModelId);
+ mModelInfoMap.put(newModelId, modelInfo);
+
+ // If we don't have something selected, select this first thing.
+ if (mSelectedModelId < 0) {
+ button.setChecked(true);
+ onRadioButtonClicked(button);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Error parsing properties for " + properties.getProperty("name"), e);
+ }
}
private void postMessage(String msg) {
@@ -91,27 +197,15 @@
}
private synchronized UUID getSelectedUuid() {
- if (mSelectedModelId == 2) return mModelUuid2;
- if (mSelectedModelId == 3) return mModelUuid3;
- return mModelUuid1; // Default.
+ return mModelInfoMap.get(mSelectedModelId).modelUuid;
}
private synchronized void setDetector(SoundTriggerDetector detector) {
- if (mSelectedModelId == 2) {
- mDetector2 = detector;
- return;
- }
- if (mSelectedModelId == 3) {
- mDetector3 = detector;
- return;
- }
- mDetector1 = detector;
+ mModelInfoMap.get(mSelectedModelId).detector = detector;
}
private synchronized SoundTriggerDetector getDetector() {
- if (mSelectedModelId == 2) return mDetector2;
- if (mSelectedModelId == 3) return mDetector3;
- return mDetector1;
+ return mModelInfoMap.get(mSelectedModelId).detector;
}
private void screenWakeup() {
@@ -127,25 +221,29 @@
mScreenWakelock.release();
}
+ /** TODO: Should return the abstract sound model that can be then sent to the service. */
+ private GenericSoundModel createNewSoundModel() {
+ ModelInfo modelInfo = mModelInfoMap.get(mSelectedModelId);
+ return new GenericSoundModel(modelInfo.modelUuid, modelInfo.vendorUuid,
+ modelInfo.modelData);
+ }
+
/**
* Called when the user clicks the enroll button.
* Performs a fresh enrollment.
*/
public void onEnrollButtonClicked(View v) {
postMessage("Loading model: " + mSelectedModelId);
- // Generate a fake model to push.
- byte[] data = new byte[1024];
- mRandom.nextBytes(data);
- UUID modelUuid = getSelectedUuid();
- GenericSoundModel model = new GenericSoundModel(modelUuid, mVendorUuid, data);
+
+ GenericSoundModel model = createNewSoundModel();
boolean status = mSoundTriggerUtil.addOrUpdateSoundModel(model);
if (status) {
Toast.makeText(
- this, "Successfully created sound trigger model UUID=" + modelUuid,
+ this, "Successfully created sound trigger model UUID=" + model.uuid,
Toast.LENGTH_SHORT).show();
} else {
- Toast.makeText(this, "Failed to enroll!!!" + modelUuid, Toast.LENGTH_SHORT).show();
+ Toast.makeText(this, "Failed to enroll!!!" + model.uuid, Toast.LENGTH_SHORT).show();
}
// Test the SoundManager API.
@@ -185,11 +283,7 @@
Toast.makeText(this, "Sound model not found!!!", Toast.LENGTH_SHORT).show();
return;
}
- // Generate a fake model to push.
- byte[] data = new byte[2048];
- mRandom.nextBytes(data);
- GenericSoundModel updated = new GenericSoundModel(soundModel.uuid,
- soundModel.vendorUuid, data);
+ GenericSoundModel updated = createNewSoundModel();
boolean status = mSoundTriggerUtil.addOrUpdateSoundModel(updated);
if (status) {
Toast.makeText(this, "Successfully re-enrolled, model UUID=" + updated.uuid,
@@ -237,29 +331,32 @@
public synchronized void onRadioButtonClicked(View view) {
// Is the button now checked?
boolean checked = ((RadioButton) view).isChecked();
- // Check which radio button was clicked
- switch(view.getId()) {
- case R.id.model_one:
- if (checked) {
- mSelectedModelId = 1;
- postMessage("Selected model one.");
- }
- break;
- case R.id.model_two:
- if (checked) {
- mSelectedModelId = 2;
- postMessage("Selected model two.");
- }
- break;
- case R.id.model_three:
- if (checked) {
- mSelectedModelId = 3;
- postMessage("Selected model three.");
- }
- break;
+ if (checked) {
+ mSelectedModelId = mModelIdMap.get(view);
+ ModelInfo modelInfo = mModelInfoMap.get(mSelectedModelId);
+ postMessage("Selected " + modelInfo.name);
+
+ // Set the play trigger button to be enabled only if we actually have some audio.
+ mPlayTriggerButton.setEnabled(modelInfo.triggerAudioPlayer != null);
}
}
+ public synchronized void onPlayTriggerButtonClicked(View v) {
+ ModelInfo modelInfo = mModelInfoMap.get(mSelectedModelId);
+ modelInfo.triggerAudioPlayer.start();
+ postMessage("Playing trigger audio for " + modelInfo.name);
+ }
+
+ // Helper struct for holding information about a model.
+ private static class ModelInfo {
+ public String name;
+ public UUID modelUuid;
+ public UUID vendorUuid;
+ public MediaPlayer triggerAudioPlayer;
+ public SoundTriggerDetector detector;
+ public byte modelData[];
+ };
+
// Implementation of SoundTriggerDetector.Callback.
public class DetectorCallback extends SoundTriggerDetector.Callback {
public void onAvailabilityChanged(int status) {
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 0f84506..be5b8fc 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -149,7 +149,7 @@
void setAllowScansWithTraffic(int enabled);
int getAllowScansWithTraffic();
- boolean enableAutoJoinWhenAssociated(boolean enabled);
+ boolean setEnableAutoJoinWhenAssociated(boolean enabled);
boolean getEnableAutoJoinWhenAssociated();
void enableWifiConnectivityManager(boolean enabled);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 6984fe2..1cd32b6 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2700,9 +2700,9 @@
* @return true -- if set successful false -- if set failed
* @hide
*/
- public boolean enableAutoJoinWhenAssociated(boolean enabled) {
+ public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
try {
- return mService.enableAutoJoinWhenAssociated(enabled);
+ return mService.setEnableAutoJoinWhenAssociated(enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}