Merge "Wake screen from external HID peripherals."
diff --git a/api/current.xml b/api/current.xml
index f98edab..c1d2f66 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -220707,6 +220707,17 @@
<parameter name="autoScale" type="boolean">
</parameter>
</method>
+<method name="buildLayer"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="cancelLongPress"
return="void"
abstract="false"
@@ -233470,6 +233481,17 @@
visibility="protected"
>
</method>
+<method name="getBackgroundColor"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getDetachWallpaper"
return="boolean"
abstract="false"
@@ -233755,6 +233777,19 @@
<parameter name="listener" type="android.view.animation.Animation.AnimationListener">
</parameter>
</method>
+<method name="setBackgroundColor"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="bg" type="int">
+</parameter>
+</method>
<method name="setDetachWallpaper"
return="void"
abstract="false"
@@ -266669,7 +266704,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="t" type="T">
+<parameter name="arg0" type="T">
</parameter>
</method>
</interface>
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index 8b59554..22dd3c7 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -168,7 +168,9 @@
*/
private final HashMap<View, Animator> pendingAnimations = new HashMap<View, Animator>();
private final HashMap<View, Animator> currentChangingAnimations = new HashMap<View, Animator>();
- private final HashMap<View, Animator> currentVisibilityAnimations =
+ private final HashMap<View, Animator> currentAppearingAnimations =
+ new HashMap<View, Animator>();
+ private final HashMap<View, Animator> currentDisappearingAnimations =
new HashMap<View, Animator>();
/**
@@ -709,7 +711,8 @@
* @return true if any animations in the transition are running.
*/
public boolean isRunning() {
- return (currentChangingAnimations.size() > 0 || currentVisibilityAnimations.size() > 0);
+ return (currentChangingAnimations.size() > 0 || currentAppearingAnimations.size() > 0 ||
+ currentDisappearingAnimations.size() > 0);
}
/**
@@ -721,17 +724,74 @@
* @hide
*/
public void cancel() {
- HashMap<View, Animator> currentAnimCopy =
- (HashMap<View, Animator>) currentChangingAnimations.clone();
- for (Animator anim : currentAnimCopy.values()) {
- anim.cancel();
+ if (currentChangingAnimations.size() > 0) {
+ HashMap<View, Animator> currentAnimCopy =
+ (HashMap<View, Animator>) currentChangingAnimations.clone();
+ for (Animator anim : currentAnimCopy.values()) {
+ anim.cancel();
+ }
+ currentChangingAnimations.clear();
}
- currentChangingAnimations.clear();
- currentAnimCopy = (HashMap<View, Animator>) currentVisibilityAnimations.clone();
- for (Animator anim : currentAnimCopy.values()) {
- anim.end();
+ if (currentAppearingAnimations.size() > 0) {
+ HashMap<View, Animator> currentAnimCopy =
+ (HashMap<View, Animator>) currentAppearingAnimations.clone();
+ for (Animator anim : currentAnimCopy.values()) {
+ anim.end();
+ }
+ currentAppearingAnimations.clear();
}
- currentVisibilityAnimations.clear();
+ if (currentDisappearingAnimations.size() > 0) {
+ HashMap<View, Animator> currentAnimCopy =
+ (HashMap<View, Animator>) currentDisappearingAnimations.clone();
+ for (Animator anim : currentAnimCopy.values()) {
+ anim.end();
+ }
+ currentDisappearingAnimations.clear();
+ }
+ }
+
+ /**
+ * Cancels the specified type of transition. Note that we cancel() the changing animations
+ * but end() the visibility animations. This is because this method is currently called
+ * in the context of starting a new transition, so we want to move things from their mid-
+ * transition positions, but we want them to have their end-transition visibility.
+ *
+ * @hide
+ */
+ public void cancel(int transitionType) {
+ switch (transitionType) {
+ case CHANGE_APPEARING:
+ case CHANGE_DISAPPEARING:
+ if (currentChangingAnimations.size() > 0) {
+ HashMap<View, Animator> currentAnimCopy =
+ (HashMap<View, Animator>) currentChangingAnimations.clone();
+ for (Animator anim : currentAnimCopy.values()) {
+ anim.cancel();
+ }
+ currentChangingAnimations.clear();
+ }
+ break;
+ case APPEARING:
+ if (currentAppearingAnimations.size() > 0) {
+ HashMap<View, Animator> currentAnimCopy =
+ (HashMap<View, Animator>) currentAppearingAnimations.clone();
+ for (Animator anim : currentAnimCopy.values()) {
+ anim.end();
+ }
+ currentAppearingAnimations.clear();
+ }
+ break;
+ case DISAPPEARING:
+ if (currentDisappearingAnimations.size() > 0) {
+ HashMap<View, Animator> currentAnimCopy =
+ (HashMap<View, Animator>) currentDisappearingAnimations.clone();
+ for (Animator anim : currentAnimCopy.values()) {
+ anim.end();
+ }
+ currentDisappearingAnimations.clear();
+ }
+ break;
+ }
}
/**
@@ -741,7 +801,7 @@
* @param child The View being added to the ViewGroup.
*/
private void runAppearingTransition(final ViewGroup parent, final View child) {
- Animator currentAnimation = currentVisibilityAnimations.get(child);
+ Animator currentAnimation = currentDisappearingAnimations.get(child);
if (currentAnimation != null) {
currentAnimation.cancel();
}
@@ -764,14 +824,14 @@
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator anim) {
- currentVisibilityAnimations.remove(child);
+ currentAppearingAnimations.remove(child);
for (TransitionListener listener : mListeners) {
listener.endTransition(LayoutTransition.this, parent, child, APPEARING);
}
}
});
}
- currentVisibilityAnimations.put(child, anim);
+ currentAppearingAnimations.put(child, anim);
anim.start();
}
@@ -782,7 +842,7 @@
* @param child The View being removed from the ViewGroup.
*/
private void runDisappearingTransition(final ViewGroup parent, final View child) {
- Animator currentAnimation = currentVisibilityAnimations.get(child);
+ Animator currentAnimation = currentAppearingAnimations.get(child);
if (currentAnimation != null) {
currentAnimation.cancel();
}
@@ -802,7 +862,7 @@
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator anim) {
- currentVisibilityAnimations.remove(child);
+ currentDisappearingAnimations.remove(child);
for (TransitionListener listener : mListeners) {
listener.endTransition(LayoutTransition.this, parent, child, DISAPPEARING);
}
@@ -812,7 +872,7 @@
if (anim instanceof ObjectAnimator) {
((ObjectAnimator) anim).setCurrentPlayTime(0);
}
- currentVisibilityAnimations.put(child, anim);
+ currentDisappearingAnimations.put(child, anim);
anim.start();
}
@@ -826,9 +886,10 @@
* @param child The View being added to the ViewGroup.
*/
public void addChild(ViewGroup parent, View child) {
- if (isRunning()) {
- cancel();
- }
+ // Want disappearing animations to finish up before proceeding
+ cancel(DISAPPEARING);
+ // Also, cancel changing animations so that we start fresh ones from current locations
+ cancel(CHANGE_APPEARING);
if (mListeners != null) {
for (TransitionListener listener : mListeners) {
listener.startTransition(this, parent, child, APPEARING);
@@ -861,9 +922,10 @@
* @param child The View being removed from the ViewGroup.
*/
public void removeChild(ViewGroup parent, View child) {
- if (isRunning()) {
- cancel();
- }
+ // Want appearing animations to finish up before proceeding
+ cancel(APPEARING);
+ // Also, cancel changing animations so that we start fresh ones from current locations
+ cancel(CHANGE_DISAPPEARING);
if (mListeners != null) {
for (TransitionListener listener : mListeners) {
listener.startTransition(this, parent, child, DISAPPEARING);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8f9a76b..b409f2f 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -98,7 +98,6 @@
import java.util.regex.Pattern;
import dalvik.system.CloseGuard;
-import dalvik.system.SamplingProfiler;
final class SuperNotCalledException extends AndroidRuntimeException {
public SuperNotCalledException(String msg) {
@@ -355,6 +354,7 @@
boolean restrictedBackupMode;
Configuration config;
boolean handlingProfiling;
+ Bundle coreSettings;
public String toString() {
return "AppBindData{appInfo=" + appInfo + "}";
}
@@ -552,7 +552,7 @@
ComponentName instrumentationName, String profileFile,
Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
int debugMode, boolean isRestrictedBackupMode, Configuration config,
- Map<String, IBinder> services) {
+ Map<String, IBinder> services, Bundle coreSettings) {
if (services != null) {
// Setup the service cache in the ServiceManager
@@ -570,6 +570,7 @@
data.debugMode = debugMode;
data.restrictedBackupMode = isRestrictedBackupMode;
data.config = config;
+ data.coreSettings = coreSettings;
queueOrSendMessage(H.BIND_APPLICATION, data);
}
@@ -896,6 +897,10 @@
private void printRow(PrintWriter pw, String format, Object...objs) {
pw.println(String.format(format, objs));
}
+
+ public void setCoreSettings(Bundle settings) {
+ queueOrSendMessage(H.SET_CORE_SETTINGS, settings);
+ }
}
private final class H extends Handler {
@@ -937,6 +942,7 @@
public static final int DUMP_HEAP = 135;
public static final int DUMP_ACTIVITY = 136;
public static final int SLEEPING = 137;
+ public static final int SET_CORE_SETTINGS = 138;
String codeToString(int code) {
if (DEBUG_MESSAGES) {
switch (code) {
@@ -978,6 +984,7 @@
case DUMP_HEAP: return "DUMP_HEAP";
case DUMP_ACTIVITY: return "DUMP_ACTIVITY";
case SLEEPING: return "SLEEPING";
+ case SET_CORE_SETTINGS: return "SET_CORE_SETTINGS";
}
}
return "(unknown)";
@@ -1113,6 +1120,9 @@
case SLEEPING:
handleSleeping((IBinder)msg.obj, msg.arg1 != 0);
break;
+ case SET_CORE_SETTINGS:
+ handleSetCoreSettings((Bundle) msg.obj);
+ break;
}
if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + msg.what);
}
@@ -2709,6 +2719,14 @@
}
}
+ private void handleSetCoreSettings(Bundle coreSettings) {
+ if (mBoundApplication != null) {
+ synchronized (mBoundApplication) {
+ mBoundApplication.coreSettings = coreSettings;
+ }
+ }
+ }
+
private final void deliverResults(ActivityClientRecord r, List<ResultInfo> results) {
final int N = results.size();
for (int i=0; i<N; i++) {
@@ -3971,6 +3989,20 @@
}
}
+ public int getIntCoreSetting(String key, int defaultValue) {
+ if (mBoundApplication == null) {
+ return defaultValue;
+ }
+ synchronized (mBoundApplication) {
+ Bundle coreSettings = mBoundApplication.coreSettings;
+ if (coreSettings != null) {
+ return coreSettings.getInt(key, defaultValue);
+ } else {
+ return defaultValue;
+ }
+ }
+ }
+
public static final void main(String[] args) {
SamplingProfilerIntegration.start();
diff --git a/core/java/android/app/AppGlobals.java b/core/java/android/app/AppGlobals.java
index 9a39129..55515b8 100644
--- a/core/java/android/app/AppGlobals.java
+++ b/core/java/android/app/AppGlobals.java
@@ -38,12 +38,23 @@
public static String getInitialPackage() {
return ActivityThread.currentPackageName();
}
-
+
/**
* Return the raw interface to the package manager.
- * @return
+ * @return The package manager.
*/
public static IPackageManager getPackageManager() {
return ActivityThread.getPackageManager();
}
+
+ /**
+ * Gets the value of an integer core setting.
+ *
+ * @param key The setting key.
+ * @param defaultValue The setting default value.
+ * @return The core settings.
+ */
+ public static int getIntCoreSetting(String key, int defaultValue) {
+ return ActivityThread.currentActivityThread().getIntCoreSetting(key, defaultValue);
+ }
}
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index ef92933..aa26b04 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -257,10 +257,11 @@
boolean restrictedBackupMode = (data.readInt() != 0);
Configuration config = Configuration.CREATOR.createFromParcel(data);
HashMap<String, IBinder> services = data.readHashMap(null);
+ Bundle coreSettings = data.readBundle();
bindApplication(packageName, info,
providers, testName, profileName,
testArgs, testWatcher, testMode, restrictedBackupMode,
- config, services);
+ config, services, coreSettings);
return true;
}
@@ -454,6 +455,13 @@
}
return true;
}
+
+ case SET_CORE_SETTINGS: {
+ data.enforceInterface(IApplicationThread.descriptor);
+ Bundle settings = data.readBundle();
+ setCoreSettings(settings);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -712,7 +720,7 @@
List<ProviderInfo> providers, ComponentName testName,
String profileName, Bundle testArgs, IInstrumentationWatcher testWatcher, int debugMode,
boolean restrictedBackupMode, Configuration config,
- Map<String, IBinder> services) throws RemoteException {
+ Map<String, IBinder> services, Bundle coreSettings) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeString(packageName);
@@ -731,6 +739,7 @@
data.writeInt(restrictedBackupMode ? 1 : 0);
config.writeToParcel(data, 0);
data.writeMap(services);
+ data.writeBundle(coreSettings);
mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
@@ -938,4 +947,11 @@
mRemote.transact(DUMP_ACTIVITY_TRANSACTION, data, null, 0);
data.recycle();
}
+
+ public void setCoreSettings(Bundle coreSettings) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeBundle(coreSettings);
+ mRemote.transact(SET_CORE_SETTINGS, data, null, IBinder.FLAG_ONEWAY);
+ }
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 16c3c5c..55177a9 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -82,7 +82,8 @@
void bindApplication(String packageName, ApplicationInfo info, List<ProviderInfo> providers,
ComponentName testName, String profileName, Bundle testArguments,
IInstrumentationWatcher testWatcher, int debugMode, boolean restrictedBackupMode,
- Configuration config, Map<String, IBinder> services) throws RemoteException;
+ Configuration config, Map<String, IBinder> services,
+ Bundle coreSettings) throws RemoteException;
void scheduleExit() throws RemoteException;
void scheduleSuicide() throws RemoteException;
void requestThumbnail(IBinder token) throws RemoteException;
@@ -110,6 +111,7 @@
void scheduleCrash(String msg) throws RemoteException;
void dumpActivity(FileDescriptor fd, IBinder servicetoken, String prefix, String[] args)
throws RemoteException;
+ void setCoreSettings(Bundle coreSettings) throws RemoteException;
String descriptor = "android.app.IApplicationThread";
@@ -151,4 +153,5 @@
int DUMP_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+36;
int CLEAR_DNS_CACHE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+37;
int SET_HTTP_PROXY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+38;
+ int SET_CORE_SETTINGS = IBinder.FIRST_CALL_TRANSACTION+39;
}
diff --git a/core/java/android/preference/PreferenceFragment.java b/core/java/android/preference/PreferenceFragment.java
index b96defe..4e22ba0 100644
--- a/core/java/android/preference/PreferenceFragment.java
+++ b/core/java/android/preference/PreferenceFragment.java
@@ -187,6 +187,7 @@
public void onDestroyView() {
mList = null;
mHandler.removeCallbacks(mRequestFocus);
+ mHandler.removeMessages(MSG_BIND_PREFERENCES);
super.onDestroyView();
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1718189..6deb5a0 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2698,6 +2698,12 @@
"accessibility_web_content_key_bindings";
/**
+ * The timout for considering a press to be a long press in milliseconds.
+ * @hide
+ */
+ public static final String LONG_PRESS_TIMEOUT = "long_press_timeout";
+
+ /**
* Setting to always use the default text-to-speech settings regardless
* of the application settings.
* 1 = override application settings,
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index fc01ef2..53fa7c2 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -1169,6 +1169,30 @@
return ret;
}
+ /**
+ * Returns the next cursor position in the run. This avoids placing the cursor between
+ * surrogates, between characters that form conjuncts, between base characters and combining
+ * marks, or within a reordering cluster.
+ *
+ * <p>The context is the shaping context for cursor movement, generally the bounds of the metric
+ * span enclosing the cursor in the direction of movement.
+ * <code>contextStart</code>, <code>contextEnd</code> and <code>offset</code> are relative to
+ * the start of the string.</p>
+ *
+ * <p>If cursorOpt is CURSOR_AT and the offset is not a valid cursor position,
+ * this returns -1. Otherwise this will never return a value before contextStart or after
+ * contextEnd.</p>
+ *
+ * @param contextStart the start index of the context
+ * @param contextEnd the (non-inclusive) end index of the context
+ * @param flags either DIRECTION_RTL or DIRECTION_LTR
+ * @param offset the cursor position to move from
+ * @param cursorOpt how to move the cursor, one of CURSOR_AFTER,
+ * CURSOR_AT_OR_AFTER, CURSOR_BEFORE,
+ * CURSOR_AT_OR_BEFORE, or CURSOR_AT
+ * @param p the Paint object that is requesting this information
+ * @return the offset of the next position, or -1
+ */
public int getTextRunCursor(int contextStart, int contextEnd, int flags, int offset,
int cursorOpt, Paint p) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2170d72..32c9e27 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8488,6 +8488,7 @@
* {@link #LAYER_TYPE_HARDWARE}
*
* @see #setLayerType(int, android.graphics.Paint)
+ * @see #buildLayer()
* @see #LAYER_TYPE_NONE
* @see #LAYER_TYPE_SOFTWARE
* @see #LAYER_TYPE_HARDWARE
@@ -8497,6 +8498,36 @@
}
/**
+ * Forces this view's layer to be created and this view to be rendered
+ * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE},
+ * invoking this method will have no effect.
+ *
+ * This method can for instance be used to render a view into its layer before
+ * starting an animation. If this view is complex, rendering into the layer
+ * before starting the animation will avoid skipping frames.
+ *
+ * @throws IllegalStateException If this view is not attached to a window
+ *
+ * @see #setLayerType(int, android.graphics.Paint)
+ */
+ public void buildLayer() {
+ if (mLayerType == LAYER_TYPE_NONE) return;
+
+ if (mAttachInfo == null) {
+ throw new IllegalStateException("This view must be attached to a window first");
+ }
+
+ switch (mLayerType) {
+ case LAYER_TYPE_HARDWARE:
+ getHardwareLayer();
+ break;
+ case LAYER_TYPE_SOFTWARE:
+ buildDrawingCache(true);
+ break;
+ }
+ }
+
+ /**
* <p>Returns a hardware layer that can be used to draw this view again
* without executing its draw method.</p>
*
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index cc4e89c..d95c5b0 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -16,8 +16,11 @@
package android.view;
+import android.app.AppGlobals;
import android.content.Context;
import android.content.res.Configuration;
+import android.os.Bundle;
+import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.SparseArray;
@@ -74,7 +77,7 @@
* Defines the duration in milliseconds before a press turns into
* a long press
*/
- private static final int LONG_PRESS_TIMEOUT = 500;
+ private static final int DEFAULTLONG_PRESS_TIMEOUT = 500;
/**
* Defines the duration in milliseconds a user needs to hold down the
@@ -320,15 +323,16 @@
public static int getPressedStateDuration() {
return PRESSED_STATE_DURATION;
}
-
+
/**
* @return the duration in milliseconds before a press turns into
* a long press
*/
public static int getLongPressTimeout() {
- return LONG_PRESS_TIMEOUT;
+ return AppGlobals.getIntCoreSetting(Settings.Secure.LONG_PRESS_TIMEOUT,
+ DEFAULTLONG_PRESS_TIMEOUT);
}
-
+
/**
* @return the duration in milliseconds we will wait to see if a touch event
* is a tap or a scroll. If the user does not move within this interval, it is
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index af4c221..3153ac5 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3001,8 +3001,10 @@
private void addViewInner(View child, int index, LayoutParams params,
boolean preventRequestLayout) {
- if (mTransition != null && mTransition.isRunning()) {
- mTransition.cancel();
+ if (mTransition != null) {
+ // Don't prevent other add transitions from completing, but cancel remove
+ // transitions to let them complete the process before we add to the container
+ mTransition.cancel(LayoutTransition.DISAPPEARING);
}
if (child.getParent() != null) {
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index 13d0ec1..87c759c 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -181,6 +181,11 @@
private int mZAdjustment;
/**
+ * Desired background color behind animation.
+ */
+ private int mBackgroundColor;
+
+ /**
* scalefactor to apply to pivot points, etc. during animation. Subclasses retrieve the
* value via getScaleFactor().
*/
@@ -236,6 +241,8 @@
setZAdjustment(a.getInt(com.android.internal.R.styleable.Animation_zAdjustment, ZORDER_NORMAL));
+ setBackgroundColor(a.getInt(com.android.internal.R.styleable.Animation_background, 0));
+
setDetachWallpaper(a.getBoolean(com.android.internal.R.styleable.Animation_detachWallpaper, false));
ensureInterpolator();
@@ -568,6 +575,16 @@
}
/**
+ * Set background behind animation.
+ *
+ * @param bg The background color. If 0, no background. Currently must
+ * be black, with any desired alpha level.
+ */
+ public void setBackgroundColor(int bg) {
+ mBackgroundColor = bg;
+ }
+
+ /**
* The scale factor is set by the call to <code>getTransformation</code>. Overrides of
* {@link #getTransformation(long, Transformation, float)} will get this value
* directly. Overrides of {@link #applyTransformation(float, Transformation)} can
@@ -690,6 +707,13 @@
}
/**
+ * Returns the background color behind the animation.
+ */
+ public int getBackgroundColor() {
+ return mBackgroundColor;
+ }
+
+ /**
* Return value of {@link #setDetachWallpaper(boolean)}.
* @attr ref android.R.styleable#Animation_detachWallpaper
*/
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 43f8790..af20ddb 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3666,9 +3666,11 @@
* @param interfaceName The name of the interface to remove.
*/
public void removeJavascriptInterface(String interfaceName) {
- WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
- arg.mInterfaceName = interfaceName;
- mWebViewCore.sendMessage(EventHub.REMOVE_JS_INTERFACE, arg);
+ if (mWebViewCore != null) {
+ WebViewCore.JSInterfaceData arg = new WebViewCore.JSInterfaceData();
+ arg.mInterfaceName = interfaceName;
+ mWebViewCore.sendMessage(EventHub.REMOVE_JS_INTERFACE, arg);
+ }
}
/**
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 88c8b2a..28f64a9 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -227,10 +227,13 @@
assert density > 0;
if (Math.abs(density - mDefaultScale) > MINIMUM_SCALE_INCREMENT) {
+ // Remember the current zoom density before it gets changed.
+ final float originalDefault = mDefaultScale;
// set the new default density
setDefaultZoomScale(density);
+ float scaleChange = (originalDefault > 0.0) ? density / originalDefault: 1.0f;
// adjust the scale if it falls outside the new zoom bounds
- setZoomScale(mActualScale, true);
+ setZoomScale(mActualScale * scaleChange, true);
}
}
@@ -629,7 +632,7 @@
}
/* package */ float getZoomOverviewScale() {
- return computeScaleWithLimits(mWebView.getViewWidth() * mInvZoomOverviewWidth);
+ return mWebView.getViewWidth() * mInvZoomOverviewWidth;
}
public boolean isInZoomOverview() {
@@ -882,6 +885,7 @@
if (!mMinZoomScaleFixed) {
mMinZoomScale = newZoomOverviewScale;
+ mMaxZoomScale = Math.max(mMaxZoomScale, mMinZoomScale);
}
// fit the content width to the current view for the first new picture
// after first layout.
@@ -956,6 +960,10 @@
final Point viewSize = drawData.mViewSize;
updateZoomRange(viewState, viewSize.x, drawData.mMinPrefWidth);
setupZoomOverviewWidth(drawData, mWebView.getViewWidth());
+ if (!mMinZoomScaleFixed) {
+ mMinZoomScale = getZoomOverviewScale();
+ mMaxZoomScale = Math.max(mMaxZoomScale, mMinZoomScale);
+ }
if (!mWebView.drawHistory()) {
float scale;
@@ -971,7 +979,7 @@
scale = overviewScale;
if (!settings.getUseWideViewPort()
|| !settings.getLoadWithOverviewMode()) {
- scale = Math.max(viewState.mTextWrapScale, scale);
+ scale = Math.max(mDefaultScale, scale);
}
if (settings.isNarrowColumnLayout() &&
settings.getUseFixedViewport()) {
diff --git a/core/res/res/anim/task_close_enter.xml b/core/res/res/anim/task_close_enter.xml
index b479543..66d982f 100644
--- a/core/res/res/anim/task_close_enter.xml
+++ b/core/res/res/anim/task_close_enter.xml
@@ -18,7 +18,7 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:detachWallpaper="true" android:shareInterpolator="false">
+ android:background="#ff000000" android:shareInterpolator="false">
<scale android:fromXScale="1.0" android:toXScale="1.0"
android:fromYScale="0.95" android:toYScale="1.0"
android:pivotX="50%p" android:pivotY="50%p"
diff --git a/core/res/res/anim/task_close_exit.xml b/core/res/res/anim/task_close_exit.xml
index e561e97..312946b 100644
--- a/core/res/res/anim/task_close_exit.xml
+++ b/core/res/res/anim/task_close_exit.xml
@@ -18,7 +18,7 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:detachWallpaper="true" android:shareInterpolator="false">
+ android:background="#ff000000" android:shareInterpolator="false">
<scale android:fromXScale="1.0" android:toXScale="1.0"
android:fromYScale="1.0" android:toYScale="0.0"
android:pivotX="50%p" android:pivotY="50%p"
diff --git a/core/res/res/anim/task_open_enter.xml b/core/res/res/anim/task_open_enter.xml
index b3b3fd1..3dda797 100644
--- a/core/res/res/anim/task_open_enter.xml
+++ b/core/res/res/anim/task_open_enter.xml
@@ -18,7 +18,7 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:detachWallpaper="true" android:shareInterpolator="false">
+ android:background="#ff000000" android:shareInterpolator="false">
<scale android:fromXScale="1.0" android:toXScale="1.0"
android:fromYScale=".9" android:toYScale="1.0"
android:pivotX="50%p" android:pivotY="50%p"
diff --git a/core/res/res/anim/task_open_exit.xml b/core/res/res/anim/task_open_exit.xml
index 763b581..e377c2a 100644
--- a/core/res/res/anim/task_open_exit.xml
+++ b/core/res/res/anim/task_open_exit.xml
@@ -18,7 +18,7 @@
-->
<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:detachWallpaper="true" android:shareInterpolator="false">
+ android:background="#ff000000" android:shareInterpolator="false">
<scale android:fromXScale="1.0" android:toXScale="1.0"
android:fromYScale="1.0" android:toYScale="0.0"
android:pivotX="50%p" android:pivotY="50%p"
diff --git a/core/res/res/drawable-hdpi/ic_paste_bubble_holo.png b/core/res/res/drawable-hdpi/ic_paste_bubble_holo.png
new file mode 100644
index 0000000..15bd8b2
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_paste_bubble_holo.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_section_divider_holo_dark.9.png b/core/res/res/drawable-hdpi/list_section_divider_holo_dark.9.png
index 2dabb5f..21e2fb9 100644
--- a/core/res/res/drawable-hdpi/list_section_divider_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/list_section_divider_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_section_divider_holo_light.9.png b/core/res/res/drawable-hdpi/list_section_divider_holo_light.9.png
index 8069452..8e9c02c 100644
--- a/core/res/res/drawable-hdpi/list_section_divider_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/list_section_divider_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_edit_paste_window.9.png b/core/res/res/drawable-hdpi/text_edit_paste_window.9.png
index 7cd000b..6654e4d 100644
--- a/core/res/res/drawable-hdpi/text_edit_paste_window.9.png
+++ b/core/res/res/drawable-hdpi/text_edit_paste_window.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_edit_side_paste_window.9.png b/core/res/res/drawable-hdpi/text_edit_side_paste_window.9.png
index 7cd000b..c564495 100644
--- a/core/res/res/drawable-hdpi/text_edit_side_paste_window.9.png
+++ b/core/res/res/drawable-hdpi/text_edit_side_paste_window.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_left.png b/core/res/res/drawable-hdpi/text_select_handle_left.png
old mode 100755
new mode 100644
index 3743d91..e42a62e
--- a/core/res/res/drawable-hdpi/text_select_handle_left.png
+++ b/core/res/res/drawable-hdpi/text_select_handle_left.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_middle.png b/core/res/res/drawable-hdpi/text_select_handle_middle.png
old mode 100755
new mode 100644
index 5a83c6c..00d47f2
--- a/core/res/res/drawable-hdpi/text_select_handle_middle.png
+++ b/core/res/res/drawable-hdpi/text_select_handle_middle.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/text_select_handle_right.png b/core/res/res/drawable-hdpi/text_select_handle_right.png
old mode 100755
new mode 100644
index 12a3dff..7426543
--- a/core/res/res/drawable-hdpi/text_select_handle_right.png
+++ b/core/res/res/drawable-hdpi/text_select_handle_right.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_paste_bubble_holo.png b/core/res/res/drawable-mdpi/ic_paste_bubble_holo.png
new file mode 100644
index 0000000..e483e84
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_paste_bubble_holo.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_section_divider_holo_dark.9.png b/core/res/res/drawable-mdpi/list_section_divider_holo_dark.9.png
index f873edb..b888135 100644
--- a/core/res/res/drawable-mdpi/list_section_divider_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/list_section_divider_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_section_divider_holo_light.9.png b/core/res/res/drawable-mdpi/list_section_divider_holo_light.9.png
index ba11cfb..1cc1f7f 100644
--- a/core/res/res/drawable-mdpi/list_section_divider_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/list_section_divider_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_edit_paste_window.9.png b/core/res/res/drawable-mdpi/text_edit_paste_window.9.png
index 6b98c13..41886eb 100644
--- a/core/res/res/drawable-mdpi/text_edit_paste_window.9.png
+++ b/core/res/res/drawable-mdpi/text_edit_paste_window.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_edit_side_paste_window.9.png b/core/res/res/drawable-mdpi/text_edit_side_paste_window.9.png
index d87c35b..d8ae54c 100644
--- a/core/res/res/drawable-mdpi/text_edit_side_paste_window.9.png
+++ b/core/res/res/drawable-mdpi/text_edit_side_paste_window.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_select_handle_left.png b/core/res/res/drawable-mdpi/text_select_handle_left.png
index 4ee2f42..959887f 100644
--- a/core/res/res/drawable-mdpi/text_select_handle_left.png
+++ b/core/res/res/drawable-mdpi/text_select_handle_left.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_select_handle_middle.png b/core/res/res/drawable-mdpi/text_select_handle_middle.png
index 3d16052..42d4e1a 100644
--- a/core/res/res/drawable-mdpi/text_select_handle_middle.png
+++ b/core/res/res/drawable-mdpi/text_select_handle_middle.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_select_handle_right.png b/core/res/res/drawable-mdpi/text_select_handle_right.png
index 3d38928..61f9c12 100644
--- a/core/res/res/drawable-mdpi/text_select_handle_right.png
+++ b/core/res/res/drawable-mdpi/text_select_handle_right.png
Binary files differ
diff --git a/core/res/res/layout/text_edit_paste_window.xml b/core/res/res/layout/text_edit_paste_window.xml
index 575b98e..01e5530 100644
--- a/core/res/res/layout/text_edit_paste_window.xml
+++ b/core/res/res/layout/text_edit_paste_window.xml
@@ -24,8 +24,8 @@
android:paddingLeft="16dip"
android:paddingRight="16dip"
android:paddingTop="8dip"
- android:paddingBottom="8dip"
- android:drawableLeft="@android:drawable/ic_menu_paste_light"
+ android:paddingBottom="12dip"
+ android:drawableLeft="@android:drawable/ic_paste_bubble_holo"
android:drawablePadding="8dip"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceMediumInverse"
diff --git a/core/res/res/layout/text_edit_side_paste_window.xml b/core/res/res/layout/text_edit_side_paste_window.xml
index 689a039..6651786 100644
--- a/core/res/res/layout/text_edit_side_paste_window.xml
+++ b/core/res/res/layout/text_edit_side_paste_window.xml
@@ -25,7 +25,7 @@
android:paddingRight="16dip"
android:paddingTop="8dip"
android:paddingBottom="8dip"
- android:drawableLeft="@android:drawable/ic_menu_paste_light"
+ android:drawableLeft="@android:drawable/ic_paste_bubble_holo"
android:drawablePadding="8dip"
android:gravity="center"
android:textAppearance="?android:attr/textAppearanceMediumInverse"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 3b225a4..d3b1062 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3596,6 +3596,10 @@
content for the duration of the animation. -->
<enum name="bottom" value="-1" />
</attr>
+ <!-- Special background behind animation. Only for use with window
+ animations. Can only be a color, and only black. If 0, the
+ default, there is no background. -->
+ <attr name="background" />
<!-- Special option for window animations: if this window is on top
of a wallpaper, don't animate the wallpaper with it. -->
<attr name="detachWallpaper" format="boolean" />
diff --git a/data/sounds/effects/ogg/Lock.ogg b/data/sounds/effects/ogg/Lock.ogg
index 2e57d9e..a25513f 100644
--- a/data/sounds/effects/ogg/Lock.ogg
+++ b/data/sounds/effects/ogg/Lock.ogg
Binary files differ
diff --git a/drm/common/DrmSupportInfo.cpp b/drm/common/DrmSupportInfo.cpp
index ffc8953..3e02093 100644
--- a/drm/common/DrmSupportInfo.cpp
+++ b/drm/common/DrmSupportInfo.cpp
@@ -56,7 +56,7 @@
for (unsigned int i = 0; i < mFileSuffixVector.size(); i++) {
const String8 item = mFileSuffixVector.itemAt(i);
- if (String8("") != fileType && item.find(fileType) != -1) {
+ if (item.find(fileType) != -1) {
return true;
}
}
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index ef7d274..ec400b7 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -184,7 +184,10 @@
IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
result = rDrmEngine.canHandle(uniqueId, path);
} else {
- result = canHandle(uniqueId, path);
+ String8 extension = path.getPathExtension();
+ if (String8("") != extension) {
+ result = canHandle(uniqueId, path);
+ }
}
}
return result;
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
index 6caf678..c541456 100644
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -479,6 +479,9 @@
*/
public int acquireRights(DrmInfoRequest drmInfoRequest) {
DrmInfo drmInfo = acquireDrmInfo(drmInfoRequest);
+ if (null == drmInfo) {
+ return ERROR_UNKNOWN;
+ }
return processDrmInfo(drmInfo);
}
diff --git a/graphics/java/android/renderscript/Type.java b/graphics/java/android/renderscript/Type.java
index 9979e2a..b39d2e4 100644
--- a/graphics/java/android/renderscript/Type.java
+++ b/graphics/java/android/renderscript/Type.java
@@ -142,7 +142,8 @@
}
int count = x * y * z * faces;
- if (hasLod && (x > 1) && (y > 1) && (z > 1)) {
+
+ while (hasLod && ((x > 1) || (y > 1) || (z > 1))) {
if(x > 1) {
x >>= 1;
}
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index cce9129..7956788 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -55,17 +55,25 @@
virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
virtual sp<IOMX> getOMX() = 0;
- // codecs usage tracking for the battery app
+ // codecs and audio devices usage tracking for the battery app
enum BatteryDataBits {
// tracking audio codec
- kBatteryDataTrackAudio = 1,
+ kBatteryDataTrackAudio = 0x1,
// tracking video codec
- kBatteryDataTrackVideo = 2,
+ kBatteryDataTrackVideo = 0x2,
// codec is started, otherwise codec is paused
- kBatteryDataCodecStarted = 4,
+ kBatteryDataCodecStarted = 0x4,
// tracking decoder (for media player),
// otherwise tracking encoder (for media recorder)
- kBatteryDataTrackDecoder = 8,
+ kBatteryDataTrackDecoder = 0x8,
+ // start to play an audio on an audio device
+ kBatteryDataAudioFlingerStart = 0x10,
+ // stop/pause the audio playback
+ kBatteryDataAudioFlingerStop = 0x20,
+ // audio is rounted to speaker
+ kBatteryDataSpeakerOn = 0x40,
+ // audio is rounted to devices other than speaker
+ kBatteryDataOtherAudioDeviceOn = 0x80,
};
virtual void addBatteryData(uint32_t params) = 0;
diff --git a/include/media/IStreamSource.h b/include/media/IStreamSource.h
index 4b698e6..d310cee 100644
--- a/include/media/IStreamSource.h
+++ b/include/media/IStreamSource.h
@@ -45,6 +45,12 @@
virtual void queueBuffer(size_t index, size_t size) = 0;
+ // When signalling a discontinuity you can optionally
+ // specify an int64_t PTS timestamp in "msg".
+ // If present, rendering of data following the discontinuity
+ // will be suppressed until media time reaches this timestamp.
+ static const char *const kKeyResumeAtPTS;
+
virtual void issueCommand(
Command cmd, bool synchronous, const sp<AMessage> &msg = NULL) = 0;
};
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 24f9739..b1eb164 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -214,6 +214,11 @@
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
layer->texture, 0);
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glEnable(GL_SCISSOR_TEST);
+
glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
return layer;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 361815a..dfca7eb 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -144,6 +144,8 @@
mSnapshot = new Snapshot(mFirstSnapshot,
SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+ mSnapshot->fbo = getTargetFbo();
+
mSaveCount = 1;
glViewport(0, 0, mWidth, mHeight);
diff --git a/media/java/android/mtp/MtpClient.java b/media/java/android/mtp/MtpClient.java
index 6c8b228..c4ee19e 100644
--- a/media/java/android/mtp/MtpClient.java
+++ b/media/java/android/mtp/MtpClient.java
@@ -163,15 +163,6 @@
mContext.unregisterReceiver(mUsbReceiver);
}
- @Override
- protected void finalize() throws Throwable {
- try {
- close();
- } finally {
- super.finalize();
- }
- }
-
/**
* Registers a {@link android.mtp.MtpClient.Listener} interface to receive
* notifications when MTP or PTP devices are added or removed.
diff --git a/media/libmedia/IStreamSource.cpp b/media/libmedia/IStreamSource.cpp
index 5069002..c14ee82 100644
--- a/media/libmedia/IStreamSource.cpp
+++ b/media/libmedia/IStreamSource.cpp
@@ -26,6 +26,9 @@
namespace android {
+// static
+const char *const IStreamListener::kKeyResumeAtPTS = "resume-at-PTS";
+
enum {
// IStreamSource
SET_LISTENER = IBinder::FIRST_CALL_TRANSACTION,
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index ec6188f..a42cca5 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -214,6 +214,15 @@
{
LOGV("MediaPlayerService created");
mNextConnId = 1;
+
+ mBatteryAudio.refCount = 0;
+ for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
+ mBatteryAudio.deviceOn[i] = 0;
+ mBatteryAudio.lastTime[i] = 0;
+ mBatteryAudio.totalTime[i] = 0;
+ }
+ // speaker is on by default
+ mBatteryAudio.deviceOn[SPEAKER] = 1;
}
MediaPlayerService::~MediaPlayerService()
@@ -1777,12 +1786,88 @@
void MediaPlayerService::addBatteryData(uint32_t params)
{
Mutex::Autolock lock(mLock);
+
+ int32_t time = systemTime() / 1000000L;
+
+ // change audio output devices. This notification comes from AudioFlinger
+ if ((params & kBatteryDataSpeakerOn)
+ || (params & kBatteryDataOtherAudioDeviceOn)) {
+
+ int deviceOn[NUM_AUDIO_DEVICES];
+ for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
+ deviceOn[i] = 0;
+ }
+
+ if ((params & kBatteryDataSpeakerOn)
+ && (params & kBatteryDataOtherAudioDeviceOn)) {
+ deviceOn[SPEAKER_AND_OTHER] = 1;
+ } else if (params & kBatteryDataSpeakerOn) {
+ deviceOn[SPEAKER] = 1;
+ } else {
+ deviceOn[OTHER_AUDIO_DEVICE] = 1;
+ }
+
+ for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
+ if (mBatteryAudio.deviceOn[i] != deviceOn[i]){
+
+ if (mBatteryAudio.refCount > 0) { // if playing audio
+ if (!deviceOn[i]) {
+ mBatteryAudio.lastTime[i] += time;
+ mBatteryAudio.totalTime[i] += mBatteryAudio.lastTime[i];
+ mBatteryAudio.lastTime[i] = 0;
+ } else {
+ mBatteryAudio.lastTime[i] = 0 - time;
+ }
+ }
+
+ mBatteryAudio.deviceOn[i] = deviceOn[i];
+ }
+ }
+ return;
+ }
+
+ // an sudio stream is started
+ if (params & kBatteryDataAudioFlingerStart) {
+ // record the start time only if currently no other audio
+ // is being played
+ if (mBatteryAudio.refCount == 0) {
+ for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
+ if (mBatteryAudio.deviceOn[i]) {
+ mBatteryAudio.lastTime[i] -= time;
+ }
+ }
+ }
+
+ mBatteryAudio.refCount ++;
+ return;
+
+ } else if (params & kBatteryDataAudioFlingerStop) {
+ if (mBatteryAudio.refCount <= 0) {
+ LOGW("Battery track warning: refCount is <= 0");
+ return;
+ }
+
+ // record the stop time only if currently this is the only
+ // audio being played
+ if (mBatteryAudio.refCount == 1) {
+ for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
+ if (mBatteryAudio.deviceOn[i]) {
+ mBatteryAudio.lastTime[i] += time;
+ mBatteryAudio.totalTime[i] += mBatteryAudio.lastTime[i];
+ mBatteryAudio.lastTime[i] = 0;
+ }
+ }
+ }
+
+ mBatteryAudio.refCount --;
+ return;
+ }
+
int uid = IPCThreadState::self()->getCallingUid();
if (uid == AID_MEDIA) {
return;
}
int index = mBatteryData.indexOfKey(uid);
- int32_t time = systemTime() / 1000000L;
if (index < 0) { // create a new entry for this UID
BatteryUsageInfo info;
@@ -1792,7 +1877,10 @@
info.videoLastTime = 0;
info.refCount = 0;
- mBatteryData.add(uid, info);
+ if (mBatteryData.add(uid, info) == NO_MEMORY) {
+ LOGE("Battery track error: no memory for new app");
+ return;
+ }
}
BatteryUsageInfo &info = mBatteryData.editValueFor(uid);
@@ -1837,6 +1925,26 @@
status_t MediaPlayerService::pullBatteryData(Parcel* reply) {
Mutex::Autolock lock(mLock);
+
+ // audio output devices usage
+ int32_t time = systemTime() / 1000000L; //in ms
+ int32_t totalTime;
+
+ for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
+ totalTime = mBatteryAudio.totalTime[i];
+
+ if (mBatteryAudio.deviceOn[i]
+ && (mBatteryAudio.lastTime[i] != 0)) {
+ int32_t tmpTime = mBatteryAudio.lastTime[i] + time;
+ totalTime += tmpTime;
+ }
+
+ reply->writeInt32(totalTime);
+ // reset the total time
+ mBatteryAudio.totalTime[i] = 0;
+ }
+
+ // codec usage
BatteryUsageInfo info;
int size = mBatteryData.size();
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 1175ed0..ff6ccf54 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -225,6 +225,25 @@
};
KeyedVector<int, BatteryUsageInfo> mBatteryData;
+ enum {
+ SPEAKER,
+ OTHER_AUDIO_DEVICE,
+ SPEAKER_AND_OTHER,
+ NUM_AUDIO_DEVICES
+ };
+
+ struct BatteryAudioFlingerUsageInfo {
+ int refCount; // how many audio streams are being played
+ int deviceOn[NUM_AUDIO_DEVICES]; // whether the device is currently used
+ int32_t lastTime[NUM_AUDIO_DEVICES]; // in ms
+ // totalTime[]: total time of audio output devices usage
+ int32_t totalTime[NUM_AUDIO_DEVICES]; // in ms
+ };
+
+ // This varialble is used to record the usage of audio output device
+ // for battery app
+ BatteryAudioFlingerUsageInfo mBatteryAudio;
+
// Collect info of the codec usage from media player and media recorder
virtual void addBatteryData(uint32_t params);
// API for the Battery app to pull the data of codecs usage
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index b3314be..d07ea1b 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -96,10 +96,12 @@
} else {
if (buffer[0] == 0x00) {
// XXX legacy
+ sp<AMessage> extra;
mTSParser->signalDiscontinuity(
buffer[1] == 0x00
? ATSParser::DISCONTINUITY_SEEK
- : ATSParser::DISCONTINUITY_FORMATCHANGE);
+ : ATSParser::DISCONTINUITY_FORMATCHANGE,
+ extra);
} else {
mTSParser->feedTSPacket(buffer, sizeof(buffer));
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 474c056..d439f6e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -191,6 +191,8 @@
mAudioEOS = false;
mVideoEOS = false;
+ mSkipRenderingAudioUntilMediaTimeUs = -1;
+ mSkipRenderingVideoUntilMediaTimeUs = -1;
mSource->start();
@@ -592,6 +594,31 @@
LOGV("%s discontinuity (formatChange=%d)",
audio ? "audio" : "video", formatChange);
+ if (audio) {
+ mSkipRenderingAudioUntilMediaTimeUs = -1;
+ } else {
+ mSkipRenderingVideoUntilMediaTimeUs = -1;
+ }
+
+ sp<AMessage> extra;
+ if (accessUnit->meta()->findMessage("extra", &extra)
+ && extra != NULL) {
+ int64_t resumeAtMediaTimeUs;
+ if (extra->findInt64(
+ "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) {
+ LOGI("suppressing rendering of %s until %lld us",
+ audio ? "audio" : "video", resumeAtMediaTimeUs);
+
+ if (audio) {
+ mSkipRenderingAudioUntilMediaTimeUs =
+ resumeAtMediaTimeUs;
+ } else {
+ mSkipRenderingVideoUntilMediaTimeUs =
+ resumeAtMediaTimeUs;
+ }
+ }
+ }
+
flushDecoder(audio, formatChange);
}
@@ -627,6 +654,27 @@
sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get());
+ int64_t &skipUntilMediaTimeUs =
+ audio
+ ? mSkipRenderingAudioUntilMediaTimeUs
+ : mSkipRenderingVideoUntilMediaTimeUs;
+
+ if (skipUntilMediaTimeUs >= 0) {
+ int64_t mediaTimeUs;
+ CHECK(buffer->meta()->findInt64("timeUs", &mediaTimeUs));
+
+ if (mediaTimeUs < skipUntilMediaTimeUs) {
+ LOGV("dropping %s buffer at time %lld as requested.",
+ audio ? "audio" : "video",
+ mediaTimeUs);
+
+ reply->post();
+ return;
+ }
+
+ skipUntilMediaTimeUs = -1;
+ }
+
mRenderer->queueBuffer(audio, buffer, reply);
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index e7c6a42..fb5b001 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -112,6 +112,9 @@
bool mResetInProgress;
bool mResetPostponed;
+ int64_t mSkipRenderingAudioUntilMediaTimeUs;
+ int64_t mSkipRenderingVideoUntilMediaTimeUs;
+
status_t instantiateDecoder(bool audio, sp<Decoder> *decoder);
status_t feedDecoderInputData(bool audio, const sp<AMessage> &msg);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp
index a23beb7..885ebe4 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.cpp
@@ -92,9 +92,12 @@
}
}
-ssize_t NuPlayer::NuPlayerStreamListener::read(void *data, size_t size) {
+ssize_t NuPlayer::NuPlayerStreamListener::read(
+ void *data, size_t size, sp<AMessage> *extra) {
CHECK_GT(size, 0u);
+ extra->clear();
+
Mutex::Autolock autoLock(mLock);
if (mEOS) {
@@ -122,6 +125,8 @@
case DISCONTINUITY:
{
+ *extra = entry->mExtra;
+
mQueue.erase(mQueue.begin());
entry = NULL;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h
index f88e945..df0935d 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h
@@ -37,7 +37,7 @@
Command cmd, bool synchronous, const sp<AMessage> &extra);
void start();
- ssize_t read(void *data, size_t size);
+ ssize_t read(void *data, size_t size, sp<AMessage> *extra);
private:
enum {
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index b85ac9f..2016282 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -54,7 +54,8 @@
for (int32_t i = 0; i < 10; ++i) {
char buffer[188];
- ssize_t n = mStreamListener->read(buffer, sizeof(buffer));
+ sp<AMessage> extra;
+ ssize_t n = mStreamListener->read(buffer, sizeof(buffer), &extra);
if (n == 0) {
LOGI("input data EOS reached.");
@@ -62,7 +63,8 @@
mEOS = true;
break;
} else if (n == INFO_DISCONTINUITY) {
- mTSParser->signalDiscontinuity(ATSParser::DISCONTINUITY_SEEK);
+ mTSParser->signalDiscontinuity(
+ ATSParser::DISCONTINUITY_SEEK, extra);
} else if (n < 0) {
CHECK_EQ(n, -EWOULDBLOCK);
break;
@@ -72,7 +74,8 @@
mTSParser->signalDiscontinuity(
buffer[1] == 0x00
? ATSParser::DISCONTINUITY_SEEK
- : ATSParser::DISCONTINUITY_FORMATCHANGE);
+ : ATSParser::DISCONTINUITY_FORMATCHANGE,
+ extra);
} else {
mTSParser->feedTSPacket(buffer, sizeof(buffer));
}
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index e43cdaa..d590ab9 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -429,16 +429,6 @@
return err;
}
- // Increase the buffer count by one to allow for the ANativeWindow to hold
- // on to one of the buffers.
- def.nBufferCountActual++;
- err = mOMX->setParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
-
- if (err != OK) {
- return err;
- }
-
// Set up the native window.
OMX_U32 usage = 0;
err = mOMX->getGraphicBufferUsage(mNode, kPortIndexOutput, &usage);
@@ -457,6 +447,33 @@
return err;
}
+ int minUndequeuedBufs = 0;
+ err = mNativeWindow->query(
+ mNativeWindow.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+ &minUndequeuedBufs);
+
+ if (err != 0) {
+ LOGE("NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d)",
+ strerror(-err), -err);
+ return err;
+ }
+
+ // XXX: Is this the right logic to use? It's not clear to me what the OMX
+ // buffer counts refer to - how do they account for the renderer holding on
+ // to buffers?
+ if (def.nBufferCountActual < def.nBufferCountMin + minUndequeuedBufs) {
+ OMX_U32 newBufferCount = def.nBufferCountMin + minUndequeuedBufs;
+ def.nBufferCountActual = newBufferCount;
+ err = mOMX->setParameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+
+ if (err != OK) {
+ LOGE("[%s] setting nBufferCountActual to %lu failed: %d",
+ mComponentName.c_str(), newBufferCount, err);
+ return err;
+ }
+ }
+
err = native_window_set_buffer_count(
mNativeWindow.get(), def.nBufferCountActual);
@@ -512,11 +529,7 @@
cancelEnd = mBuffers[kPortIndexOutput].size();
} else {
// Return the last two buffers to the native window.
- // XXX TODO: The number of buffers the native window owns should
- // probably be queried from it when we put the native window in
- // fixed buffer pool mode (which needs to be implemented).
- // Currently it's hard-coded to 2.
- cancelStart = def.nBufferCountActual - 2;
+ cancelStart = def.nBufferCountActual - minUndequeuedBufs;
cancelEnd = def.nBufferCountActual;
}
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 5f40893..4a94e0d 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1738,15 +1738,6 @@
return err;
}
- // Increase the buffer count by one to allow for the ANativeWindow to hold
- // on to one of the buffers.
- def.nBufferCountActual++;
- err = mOMX->setParameter(
- mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
- if (err != OK) {
- return err;
- }
-
err = applyRotation();
if (err != OK) {
return err;
@@ -1768,6 +1759,30 @@
return err;
}
+ int minUndequeuedBufs = 0;
+ err = mNativeWindow->query(mNativeWindow.get(),
+ NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);
+ if (err != 0) {
+ LOGE("NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d)",
+ strerror(-err), -err);
+ return err;
+ }
+
+ // XXX: Is this the right logic to use? It's not clear to me what the OMX
+ // buffer counts refer to - how do they account for the renderer holding on
+ // to buffers?
+ if (def.nBufferCountActual < def.nBufferCountMin + minUndequeuedBufs) {
+ OMX_U32 newBufferCount = def.nBufferCountMin + minUndequeuedBufs;
+ def.nBufferCountActual = newBufferCount;
+ err = mOMX->setParameter(
+ mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+ if (err != OK) {
+ CODEC_LOGE("setting nBufferCountActual to %lu failed: %d",
+ newBufferCount, err);
+ return err;
+ }
+ }
+
err = native_window_set_buffer_count(
mNativeWindow.get(), def.nBufferCountActual);
if (err != 0) {
@@ -1822,10 +1837,7 @@
cancelEnd = mPortBuffers[kPortIndexOutput].size();
} else {
// Return the last two buffers to the native window.
- // XXX TODO: The number of buffers the native window owns should probably be
- // queried from it when we put the native window in fixed buffer pool mode
- // (which needs to be implemented). Currently it's hard-coded to 2.
- cancelStart = def.nBufferCountActual - 2;
+ cancelStart = def.nBufferCountActual - minUndequeuedBufs;
cancelEnd = def.nBufferCountActual;
}
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 6056739..7d4bc6e 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -32,6 +32,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
+#include <media/IStreamSource.h>
#include <utils/KeyedVector.h>
namespace android {
@@ -49,7 +50,9 @@
unsigned pid, unsigned payload_unit_start_indicator,
ABitReader *br);
- void signalDiscontinuity(DiscontinuityType type);
+ void signalDiscontinuity(
+ DiscontinuityType type, const sp<AMessage> &extra);
+
void signalEOS(status_t finalResult);
sp<MediaSource> getSource(SourceType type);
@@ -83,7 +86,9 @@
unsigned payload_unit_start_indicator,
ABitReader *br);
- void signalDiscontinuity(DiscontinuityType type);
+ void signalDiscontinuity(
+ DiscontinuityType type, const sp<AMessage> &extra);
+
void signalEOS(status_t finalResult);
sp<MediaSource> getSource(SourceType type);
@@ -100,6 +105,7 @@
sp<AnotherPacketSource> mSource;
bool mPayloadStarted;
DiscontinuityType mPendingDiscontinuity;
+ sp<AMessage> mPendingDiscontinuityExtra;
ElementaryStreamQueue mQueue;
@@ -112,7 +118,8 @@
void extractAACFrames(const sp<ABuffer> &buffer);
- void deferDiscontinuity(DiscontinuityType type);
+ void deferDiscontinuity(
+ DiscontinuityType type, const sp<AMessage> &extra);
DISALLOW_EVIL_CONSTRUCTORS(Stream);
};
@@ -150,9 +157,10 @@
return true;
}
-void ATSParser::Program::signalDiscontinuity(DiscontinuityType type) {
+void ATSParser::Program::signalDiscontinuity(
+ DiscontinuityType type, const sp<AMessage> &extra) {
for (size_t i = 0; i < mStreams.size(); ++i) {
- mStreams.editValueAt(i)->signalDiscontinuity(type);
+ mStreams.editValueAt(i)->signalDiscontinuity(type, extra);
}
}
@@ -283,7 +291,8 @@
mStreams.add(info.mPID, stream);
if (PIDsChanged) {
- stream->signalDiscontinuity(DISCONTINUITY_FORMATCHANGE);
+ sp<AMessage> extra;
+ stream->signalDiscontinuity(DISCONTINUITY_FORMATCHANGE, extra);
}
}
}
@@ -360,13 +369,25 @@
size_t payloadSizeBits = br->numBitsLeft();
CHECK_EQ(payloadSizeBits % 8, 0u);
- CHECK_LE(mBuffer->size() + payloadSizeBits / 8, mBuffer->capacity());
+ size_t neededSize = mBuffer->size() + payloadSizeBits / 8;
+ if (mBuffer->capacity() < neededSize) {
+ // Increment in multiples of 64K.
+ neededSize = (neededSize + 65535) & ~65535;
+
+ LOGI("resizing buffer to %d bytes", neededSize);
+
+ sp<ABuffer> newBuffer = new ABuffer(neededSize);
+ memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size());
+ newBuffer->setRange(0, mBuffer->size());
+ mBuffer = newBuffer;
+ }
memcpy(mBuffer->data() + mBuffer->size(), br->data(), payloadSizeBits / 8);
mBuffer->setRange(0, mBuffer->size() + payloadSizeBits / 8);
}
-void ATSParser::Stream::signalDiscontinuity(DiscontinuityType type) {
+void ATSParser::Stream::signalDiscontinuity(
+ DiscontinuityType type, const sp<AMessage> &extra) {
mPayloadStarted = false;
mBuffer->setRange(0, 0);
@@ -378,10 +399,21 @@
mQueue.clear(!isASeek);
+ uint64_t resumeAtPTS;
+ if (extra != NULL
+ && extra->findInt64(
+ IStreamListener::kKeyResumeAtPTS,
+ (int64_t *)&resumeAtPTS)) {
+ int64_t resumeAtMediaTimeUs =
+ mProgram->convertPTSToTimestamp(resumeAtPTS);
+
+ extra->setInt64("resume-at-mediatimeUs", resumeAtMediaTimeUs);
+ }
+
if (mSource != NULL) {
- mSource->queueDiscontinuity(type);
+ mSource->queueDiscontinuity(type, extra);
} else {
- deferDiscontinuity(type);
+ deferDiscontinuity(type, extra);
}
break;
}
@@ -392,10 +424,12 @@
}
}
-void ATSParser::Stream::deferDiscontinuity(DiscontinuityType type) {
+void ATSParser::Stream::deferDiscontinuity(
+ DiscontinuityType type, const sp<AMessage> &extra) {
if (type > mPendingDiscontinuity) {
// Only upgrade discontinuities.
mPendingDiscontinuity = type;
+ mPendingDiscontinuityExtra = extra;
}
}
@@ -596,8 +630,10 @@
mSource = new AnotherPacketSource(meta);
if (mPendingDiscontinuity != DISCONTINUITY_NONE) {
- mSource->queueDiscontinuity(mPendingDiscontinuity);
+ mSource->queueDiscontinuity(
+ mPendingDiscontinuity, mPendingDiscontinuityExtra);
mPendingDiscontinuity = DISCONTINUITY_NONE;
+ mPendingDiscontinuityExtra.clear();
}
mSource->queueAccessUnit(accessUnit);
@@ -639,9 +675,10 @@
parseTS(&br);
}
-void ATSParser::signalDiscontinuity(DiscontinuityType type) {
+void ATSParser::signalDiscontinuity(
+ DiscontinuityType type, const sp<AMessage> &extra) {
for (size_t i = 0; i < mPrograms.size(); ++i) {
- mPrograms.editItemAt(i)->signalDiscontinuity(type);
+ mPrograms.editItemAt(i)->signalDiscontinuity(type, extra);
}
}
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 455f9d5..3936f05 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -41,7 +41,10 @@
ATSParser();
void feedTSPacket(const void *data, size_t size);
- void signalDiscontinuity(DiscontinuityType type);
+
+ void signalDiscontinuity(
+ DiscontinuityType type, const sp<AMessage> &extra);
+
void signalEOS(status_t finalResult);
enum SourceType {
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 0ad883b..59de17e 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -136,9 +136,11 @@
}
void AnotherPacketSource::queueDiscontinuity(
- ATSParser::DiscontinuityType type) {
+ ATSParser::DiscontinuityType type,
+ const sp<AMessage> &extra) {
sp<ABuffer> buffer = new ABuffer(0);
buffer->meta()->setInt32("discontinuity", static_cast<int32_t>(type));
+ buffer->meta()->setMessage("extra", extra);
Mutex::Autolock autoLock(mLock);
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
index 6fe93f8..439c7853 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
@@ -46,7 +46,10 @@
status_t nextBufferTime(int64_t *timeUs);
void queueAccessUnit(const sp<ABuffer> &buffer);
- void queueDiscontinuity(ATSParser::DiscontinuityType type);
+
+ void queueDiscontinuity(
+ ATSParser::DiscontinuityType type, const sp<AMessage> &extra);
+
void signalEOS(status_t result);
status_t dequeueAccessUnit(sp<ABuffer> *buffer);
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 2df6d68..bf06f947 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -121,4 +121,8 @@
<integer name="def_download_manager_max_bytes_over_mobile">-1</integer>
<!-- Default for Settings.Secure.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE. <=0 if no limit -->
<integer name="def_download_manager_recommended_max_bytes_over_mobile">-1</integer>
+
+ <!-- Default for Settings.Secure.LONG_PRESS_TIMEOUT_MILLIS -->
+ <integer name="def_long_press_timeout_millis">500</integer>
+
</resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index f336f06..d901c2c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -819,6 +819,24 @@
upgradeVersion = 64;
}
+ if (upgradeVersion == 64) {
+ // New setting to configure the long press timeout.
+ db.beginTransaction();
+ SQLiteStatement stmt = null;
+ try {
+ stmt = db.compileStatement("INSERT INTO secure(name,value)"
+ + " VALUES(?,?);");
+ loadIntegerSetting(stmt, Settings.Secure.LONG_PRESS_TIMEOUT,
+ R.integer.def_long_press_timeout_millis);
+ stmt.close();
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ if (stmt != null) stmt.close();
+ }
+ upgradeVersion = 65;
+ }
+
// *** Remember to update DATABASE_VERSION above!
if (upgradeVersion != currentVersion) {
@@ -1332,6 +1350,9 @@
loadSetting(stmt, Settings.Secure.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE,
Integer.toString(recommendedMaxBytes));
}
+
+ loadIntegerSetting(stmt, Settings.Secure.LONG_PRESS_TIMEOUT,
+ R.integer.def_long_press_timeout_millis);
} finally {
if (stmt != null) stmt.close();
}
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index a07ebfc..2b08ab5 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -24,6 +24,7 @@
#include <sys/time.h>
#include <sys/resource.h>
+#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <binder/Parcel.h>
@@ -35,6 +36,7 @@
#include <media/AudioTrack.h>
#include <media/AudioRecord.h>
+#include <media/IMediaPlayerService.h>
#include <private/media/AudioTrackShared.h>
#include <private/media/AudioEffectShared.h>
@@ -121,6 +123,19 @@
#endif
}
+// To collect the amplifier usage
+static void addBatteryData(uint32_t params) {
+ sp<IBinder> binder =
+ defaultServiceManager()->getService(String16("media.player"));
+ sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+ if (service.get() == NULL) {
+ LOGW("Cannot connect to the MediaPlayerService for battery tracking");
+ return;
+ }
+
+ service->addBatteryData(params);
+}
+
// ----------------------------------------------------------------------------
AudioFlinger::AudioFlinger()
@@ -1833,6 +1848,27 @@
}
}
if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
+ // when changing the audio output device, call addBatteryData to notify
+ // the change
+ if (mDevice != value) {
+ uint32_t params = 0;
+ // check whether speaker is on
+ if (value & AudioSystem::DEVICE_OUT_SPEAKER) {
+ params |= IMediaPlayerService::kBatteryDataSpeakerOn;
+ }
+
+ int deviceWithoutSpeaker
+ = AudioSystem::DEVICE_OUT_ALL & ~AudioSystem::DEVICE_OUT_SPEAKER;
+ // check if any other device (except speaker) is on
+ if (value & deviceWithoutSpeaker ) {
+ params |= IMediaPlayerService::kBatteryDataOtherAudioDeviceOn;
+ }
+
+ if (params != 0) {
+ addBatteryData(params);
+ }
+ }
+
// forward device change to effects that have requested to be
// aware of attached audio device.
mDevice = (uint32_t)value;
@@ -2831,6 +2867,9 @@
AudioSystem::stopOutput(thread->id(),
(AudioSystem::stream_type)mStreamType,
mSessionId);
+
+ // to track the speaker usage
+ addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStop);
}
AudioSystem::releaseOutput(thread->id());
}
@@ -2941,6 +2980,11 @@
(AudioSystem::stream_type)mStreamType,
mSessionId);
thread->mLock.lock();
+
+ // to track the speaker usage
+ if (status == NO_ERROR) {
+ addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStart);
+ }
}
if (status == NO_ERROR) {
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
@@ -2976,6 +3020,9 @@
(AudioSystem::stream_type)mStreamType,
mSessionId);
thread->mLock.lock();
+
+ // to track the speaker usage
+ addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStop);
}
}
}
@@ -2995,6 +3042,9 @@
(AudioSystem::stream_type)mStreamType,
mSessionId);
thread->mLock.lock();
+
+ // to track the speaker usage
+ addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStop);
}
}
}
diff --git a/services/audioflinger/AudioPolicyManagerBase.cpp b/services/audioflinger/AudioPolicyManagerBase.cpp
index bfc80db..74be4e0 100644
--- a/services/audioflinger/AudioPolicyManagerBase.cpp
+++ b/services/audioflinger/AudioPolicyManagerBase.cpp
@@ -122,12 +122,12 @@
// request routing change if necessary
uint32_t newDevice = getNewDevice(mHardwareOutput, false);
#ifdef WITH_A2DP
+ checkA2dpSuspend();
checkOutputForAllStrategies();
// A2DP outputs must be closed after checkOutputForAllStrategies() is executed
if (state == AudioSystem::DEVICE_STATE_UNAVAILABLE && AudioSystem::isA2dpDevice(device)) {
closeA2dpOutputs();
}
- checkA2dpSuspend();
#endif
updateDeviceForStrategy();
setOutputDevice(mHardwareOutput, newDevice);
@@ -269,8 +269,8 @@
// check for device and output changes triggered by new phone state
newDevice = getNewDevice(mHardwareOutput, false);
#ifdef WITH_A2DP
- checkOutputForAllStrategies();
checkA2dpSuspend();
+ checkOutputForAllStrategies();
#endif
updateDeviceForStrategy();
@@ -378,8 +378,8 @@
// check for device and output changes triggered by new phone state
uint32_t newDevice = getNewDevice(mHardwareOutput, false);
#ifdef WITH_A2DP
- checkOutputForAllStrategies();
checkA2dpSuspend();
+ checkOutputForAllStrategies();
#endif
updateDeviceForStrategy();
setOutputDevice(mHardwareOutput, newDevice);
@@ -1624,7 +1624,7 @@
if (device) break;
#ifdef WITH_A2DP
// when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
- if (!isInCall()) {
+ if (!isInCall() && !mA2dpSuspended) {
device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP;
if (device) break;
device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
@@ -1647,7 +1647,7 @@
#ifdef WITH_A2DP
// when not in a phone call, phone strategy should route STREAM_VOICE_CALL to
// A2DP speaker when forcing to speaker output
- if (!isInCall()) {
+ if (!isInCall() && !mA2dpSuspended) {
device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
if (device) break;
}
@@ -1687,7 +1687,7 @@
device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
}
#ifdef WITH_A2DP
- if ((mA2dpOutput != 0) &&
+ if ((mA2dpOutput != 0) && !mA2dpSuspended &&
(strategy != STRATEGY_SONIFICATION || a2dpUsedForSonification())) {
if (device2 == 0) {
device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index e6dfb7f..40417b1 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -717,6 +717,8 @@
final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
= new SparseArray<HashMap<Uri, UriPermission>>();
+ CoreSettingsObserver mCoreSettingsObserver;
+
/**
* Thread-local storage used to carry caller permissions over through
* indirect content-provider access.
@@ -3589,7 +3591,8 @@
app.instrumentationClass, app.instrumentationProfileFile,
app.instrumentationArguments, app.instrumentationWatcher, testMode,
isRestrictedBackupMode || !normalMode,
- mConfiguration, getCommonServicesLocked());
+ mConfiguration, getCommonServicesLocked(),
+ mCoreSettingsObserver.getCoreSettingsLocked());
updateLruProcessLocked(app, false, true);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
} catch (Exception e) {
@@ -5772,6 +5775,8 @@
if (providers != null) {
mSystemThread.installSystemProviders(providers);
}
+
+ mSelf.mCoreSettingsObserver = new CoreSettingsObserver(mSelf);
}
/**
@@ -13030,4 +13035,17 @@
public void monitor() {
synchronized (this) { }
}
+
+ public void onCoreSettingsChange(Bundle settings) {
+ for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
+ ProcessRecord processRecord = mLruProcesses.get(i);
+ try {
+ if (processRecord.thread != null) {
+ processRecord.thread.setCoreSettings(settings);
+ }
+ } catch (RemoteException re) {
+ /* ignore */
+ }
+ }
+ }
}
diff --git a/services/java/com/android/server/am/CoreSettingsObserver.java b/services/java/com/android/server/am/CoreSettingsObserver.java
new file mode 100644
index 0000000..25db84a
--- /dev/null
+++ b/services/java/com/android/server/am/CoreSettingsObserver.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2006-2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Helper class for watching a set of core settings which the framework
+ * propagates to application processes to avoid multiple lookups and potentially
+ * disk I/O operations. Note: This class assumes that all core settings reside
+ * in {@link Settings.Secure}.
+ */
+class CoreSettingsObserver extends ContentObserver {
+ private static final String LOG_TAG = CoreSettingsObserver.class.getSimpleName();
+
+ // mapping form property name to its type
+ private static final Map<String, Class<?>> sCoreSettingToTypeMap = new HashMap<
+ String, Class<?>>();
+ static {
+ sCoreSettingToTypeMap.put(Settings.Secure.LONG_PRESS_TIMEOUT, int.class);
+ // add other core settings here...
+ }
+
+ private final Bundle mCoreSettings = new Bundle();
+
+ private final ActivityManagerService mActivityManagerService;
+
+ public CoreSettingsObserver(ActivityManagerService activityManagerService) {
+ super(activityManagerService.mHandler);
+ mActivityManagerService = activityManagerService;
+ beginObserveCoreSettings();
+ populateCoreSettings(mCoreSettings);
+ }
+
+ public Bundle getCoreSettingsLocked() {
+ return (Bundle) mCoreSettings.clone();
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ synchronized (mActivityManagerService) {
+ populateCoreSettings(mCoreSettings);
+ mActivityManagerService.onCoreSettingsChange(mCoreSettings);
+ }
+ }
+
+ private void beginObserveCoreSettings() {
+ for (String setting : sCoreSettingToTypeMap.keySet()) {
+ Uri uri = Settings.Secure.getUriFor(setting);
+ mActivityManagerService.mContext.getContentResolver().registerContentObserver(
+ uri, false, this);
+ }
+ }
+
+ private void populateCoreSettings(Bundle snapshot) {
+ Context context = mActivityManagerService.mContext;
+ for (Map.Entry<String, Class<?>> entry : sCoreSettingToTypeMap.entrySet()) {
+ String setting = entry.getKey();
+ Class<?> type = entry.getValue();
+ try {
+ if (type == String.class) {
+ String value = Settings.Secure.getString(context.getContentResolver(),
+ setting);
+ snapshot.putString(setting, value);
+ } else if (type == int.class) {
+ int value = Settings.Secure.getInt(context.getContentResolver(),
+ setting);
+ snapshot.putInt(setting, value);
+ } else if (type == float.class) {
+ float value = Settings.Secure.getFloat(context.getContentResolver(),
+ setting);
+ snapshot.putFloat(setting, value);
+ } else if (type == long.class) {
+ long value = Settings.Secure.getLong(context.getContentResolver(),
+ setting);
+ snapshot.putLong(setting, value);
+ }
+ } catch (SettingNotFoundException snfe) {
+ Log.w(LOG_TAG, "Cannot find setting \"" + setting + "\"", snfe);
+ }
+ }
+ }
+}
diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java
index 94c25e9..8170c61 100644
--- a/services/java/com/android/server/usb/UsbService.java
+++ b/services/java/com/android/server/usb/UsbService.java
@@ -102,8 +102,8 @@
private boolean mSystemReady;
private UsbAccessory mCurrentAccessory;
- // functions to restore after exiting accessory mode
- private final ArrayList<String> mAccessoryRestoreFunctions = new ArrayList<String>();
+ // USB functions that are enabled by default, to restore after exiting accessory mode
+ private final ArrayList<String> mDefaultFunctions = new ArrayList<String>();
private final Context mContext;
private final Object mLock = new Object();
@@ -118,20 +118,6 @@
boolean enteringAccessoryMode =
(mHasUsbAccessory && enabled && UsbManager.USB_FUNCTION_ACCESSORY.equals(function));
- if (enteringAccessoryMode) {
- // keep a list of functions to reenable after exiting accessory mode
- mAccessoryRestoreFunctions.clear();
- int count = mEnabledFunctions.size();
- for (int i = 0; i < count; i++) {
- String f = mEnabledFunctions.get(i);
- // RNDIS should not be restored and adb is handled automatically
- if (!UsbManager.USB_FUNCTION_RNDIS.equals(f) &&
- !UsbManager.USB_FUNCTION_ADB.equals(f) &&
- !UsbManager.USB_FUNCTION_ACCESSORY.equals(f)) {
- mAccessoryRestoreFunctions.add(f);
- }
- }
- }
if (enabled) {
if (!mEnabledFunctions.contains(function)) {
mEnabledFunctions.add(function);
@@ -261,6 +247,11 @@
String functionName = files[i].getName();
if (value == 1) {
mEnabledFunctions.add(functionName);
+ // adb is enabled/disabled automatically by the adbd daemon,
+ // so don't treat it as a default function
+ if (!UsbManager.USB_FUNCTION_ADB.equals(functionName)) {
+ mDefaultFunctions.add(functionName);
+ }
} else {
mDisabledFunctions.add(functionName);
}
@@ -503,29 +494,24 @@
switch (msg.what) {
case MSG_UPDATE_STATE:
if (mConnected != mLastConnected || mConfiguration != mLastConfiguration) {
- if (mConnected == 0 && mCurrentAccessory != null) {
- // turn off accessory mode when we are disconnected
+ if (mConnected == 0) {
+ // make sure accessory mode is off, and restore default functions
if (UsbManager.setFunctionEnabled(
UsbManager.USB_FUNCTION_ACCESSORY, false)) {
Log.d(TAG, "exited USB accessory mode");
- // restore previously enabled functions
- for (String function : mAccessoryRestoreFunctions) {
+ int count = mDefaultFunctions.size();
+ for (int i = 0; i < count; i++) {
+ String function = mDefaultFunctions.get(i);
if (UsbManager.setFunctionEnabled(function, true)) {
Log.e(TAG, "could not reenable function " + function);
}
}
- mAccessoryRestoreFunctions.clear();
+ }
+ if (mCurrentAccessory != null) {
mDeviceManager.accessoryDetached(mCurrentAccessory);
mCurrentAccessory = null;
-
- // this will cause an immediate reset of the USB bus,
- // so there is no point in sending the
- // function disabled broadcast.
- return;
- } else {
- Log.e(TAG, "could not disable USB_FUNCTION_ACCESSORY");
}
}
@@ -581,14 +567,18 @@
pw.print(mDisabledFunctions.get(i) + " ");
}
pw.println("");
+ pw.print(" Default Functions: ");
+ for (int i = 0; i < mDefaultFunctions.size(); i++) {
+ pw.print(mDefaultFunctions.get(i) + " ");
+ }
+ pw.println("");
pw.println(" mConnected: " + mConnected + ", mConfiguration: " + mConfiguration);
+ pw.println(" mCurrentAccessory: " + mCurrentAccessory);
pw.println(" USB Host State:");
for (String name : mDevices.keySet()) {
pw.println(" " + name + ": " + mDevices.get(name));
}
- pw.println(" mCurrentAccessory: " + mCurrentAccessory);
-
mDeviceManager.dump(fd, pw);
}
}
diff --git a/services/java/com/android/server/wm/DimAnimator.java b/services/java/com/android/server/wm/DimAnimator.java
index 1fcb869..a266d70 100644
--- a/services/java/com/android/server/wm/DimAnimator.java
+++ b/services/java/com/android/server/wm/DimAnimator.java
@@ -45,7 +45,7 @@
+ mDimSurface + ": CREATE");
try {
mDimSurface = new Surface(session, 0,
- "DimSurface",
+ "DimAnimator",
-1, 16, 16, PixelFormat.OPAQUE,
Surface.FX_SURFACE_DIM);
mDimSurface.setAlpha(0.0f);
@@ -84,7 +84,7 @@
* {@link updateSurface} after all windows are examined.
*/
void updateParameters(Resources res, WindowState w, long currentTime) {
- mDimSurface.setLayer(w.mAnimLayer-1);
+ mDimSurface.setLayer(w.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM);
final float target = w.mExiting ? 0 : w.mAttrs.dimAmount;
if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM " + mDimSurface
@@ -177,8 +177,11 @@
return animating;
}
- public void printTo(PrintWriter pw) {
- pw.print(" mDimShown="); pw.print(mDimShown);
+ public void printTo(String prefix, PrintWriter pw) {
+ pw.print(prefix);
+ pw.print("mDimSurface="); pw.println(mDimSurface);
+ pw.print(prefix);
+ pw.print("mDimShown="); pw.print(mDimShown);
pw.print(" current="); pw.print(mDimCurrentAlpha);
pw.print(" target="); pw.print(mDimTargetAlpha);
pw.print(" delta="); pw.print(mDimDeltaPerMs);
diff --git a/services/java/com/android/server/wm/DimSurface.java b/services/java/com/android/server/wm/DimSurface.java
new file mode 100644
index 0000000..084ac6f
--- /dev/null
+++ b/services/java/com/android/server/wm/DimSurface.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import android.graphics.PixelFormat;
+import android.util.Slog;
+import android.view.Surface;
+import android.view.SurfaceSession;
+
+import java.io.PrintWriter;
+
+class DimSurface {
+ Surface mDimSurface;
+ boolean mDimShown = false;
+ int mDimColor = 0;
+ int mLayer = -1;
+ int mLastDimWidth, mLastDimHeight;
+
+ DimSurface(SurfaceSession session) {
+ if (mDimSurface == null) {
+ if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM "
+ + mDimSurface + ": CREATE");
+ try {
+ mDimSurface = new Surface(session, 0,
+ "DimSurface",
+ -1, 16, 16, PixelFormat.OPAQUE,
+ Surface.FX_SURFACE_DIM);
+ mDimSurface.setAlpha(0.0f);
+ } catch (Exception e) {
+ Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e);
+ }
+ }
+ }
+
+ /**
+ * Show the dim surface.
+ */
+ void show(int dw, int dh, int layer, int color) {
+ if (!mDimShown) {
+ if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM " + mDimSurface + ": SHOW pos=(0,0) (" +
+ dw + "x" + dh + ")");
+ mDimShown = true;
+ try {
+ mLastDimWidth = dw;
+ mLastDimHeight = dh;
+ mDimSurface.setPosition(0, 0);
+ mDimSurface.setSize(dw, dh);
+ mDimSurface.show();
+ } catch (RuntimeException e) {
+ Slog.w(WindowManagerService.TAG, "Failure showing dim surface", e);
+ }
+ } else if (mLastDimWidth != dw || mLastDimHeight != dh || mDimColor != color
+ || mLayer != layer) {
+ mLastDimWidth = dw;
+ mLastDimHeight = dh;
+ mLayer = layer;
+ mDimColor = color;
+ mDimSurface.setSize(dw, dh);
+ mDimSurface.setLayer(layer);
+ mDimSurface.setAlpha(((color>>24)&0xff)/255.0f);
+ }
+ }
+
+ void hide() {
+ if (mDimShown) {
+ mDimShown = false;
+ try {
+ mDimSurface.hide();
+ } catch (RuntimeException e) {
+ Slog.w(WindowManagerService.TAG, "Illegal argument exception hiding dim surface");
+ }
+ }
+ }
+
+ public void printTo(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("mDimSurface="); pw.println(mDimSurface);
+ pw.print(prefix); pw.print("mDimShown="); pw.print(mDimShown);
+ pw.print(" mLayer="); pw.println(mLayer);
+ pw.print(" mDimColor=0x"); pw.println(Integer.toHexString(mDimColor));
+ pw.print(prefix); pw.print("mLastDimWidth="); pw.print(mLastDimWidth);
+ pw.print(" mLastDimWidth="); pw.println(mLastDimWidth);
+ }
+}
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 4356ce5..fbf1ec3 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -110,18 +110,16 @@
Bitmap screenshot = Surface.screenshot(0, 0);
- if (screenshot != null) {
- // Screenshot does NOT include rotation!
- mSnapshotRotation = 0;
- mWidth = screenshot.getWidth();
- mHeight = screenshot.getHeight();
- } else {
- // Just in case.
- mSnapshotRotation = display.getRotation();
- mWidth = mDisplayMetrics.widthPixels;
- mHeight = mDisplayMetrics.heightPixels;
+ if (screenshot == null) {
+ // Device is not capable of screenshots... we can't do an animation.
+ return;
}
+ // Screenshot does NOT include rotation!
+ mSnapshotRotation = 0;
+ mWidth = screenshot.getWidth();
+ mHeight = screenshot.getHeight();
+
mOriginalRotation = display.getRotation();
mOriginalWidth = mDisplayMetrics.widthPixels;
mOriginalHeight = mDisplayMetrics.heightPixels;
@@ -150,23 +148,19 @@
c = mSurface.lockCanvas(dirty);
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Unable to lock surface", e);
- return;
} catch (Surface.OutOfResourcesException e) {
Slog.w(TAG, "Unable to lock surface", e);
- return;
}
if (c == null) {
- Slog.w(TAG, "Null surface");
+ Slog.w(TAG, "Null surface canvas");
+ mSurface.destroy();
+ mSurface = null;
return;
}
- if (screenshot != null) {
- Paint paint = new Paint(0);
- paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
- c.drawBitmap(screenshot, 0, 0, paint);
- } else {
- c.drawColor(Color.BLACK, PorterDuff.Mode.SRC);
- }
+ Paint paint = new Paint(0);
+ paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+ c.drawBitmap(screenshot, 0, 0, paint);
mSurface.unlockCanvasAndPost(c);
}
@@ -177,12 +171,14 @@
"<<< CLOSE TRANSACTION ScreenRotationAnimation");
}
- if (screenshot != null) {
- screenshot.recycle();
- }
+ screenshot.recycle();
}
}
+ boolean hasScreenshot() {
+ return mSurface != null;
+ }
+
static int deltaRotation(int oldRotation, int newRotation) {
int delta = newRotation - oldRotation;
if (delta < 0) delta += 4;
@@ -250,17 +246,14 @@
*/
public boolean dismiss(SurfaceSession session, long maxAnimationDuration,
float animationScale) {
- // Figure out how the screen has moved from the original rotation.
- int delta = deltaRotation(mCurRotation, mOriginalRotation);
- if (false && delta == 0) {
- // Nothing changed, just remove the snapshot.
- if (mSurface != null) {
- mSurface.destroy();
- mSurface = null;
- }
+ if (mSurface == null) {
+ // Can't do animation.
return false;
}
+ // Figure out how the screen has moved from the original rotation.
+ int delta = deltaRotation(mCurRotation, mOriginalRotation);
+
switch (delta) {
case Surface.ROTATION_0:
mExitAnimation = AnimationUtils.loadAnimation(mContext,
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 15269dc..b5d84e8 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -180,6 +180,16 @@
*/
static final int WINDOW_LAYER_MULTIPLIER = 5;
+ /**
+ * Dim surface layer is immediately below target window.
+ */
+ static final int LAYER_OFFSET_DIM = 1;
+
+ /**
+ * Blur surface layer is immediately below dim layer.
+ */
+ static final int LAYER_OFFSET_BLUR = 2;
+
/** The maximum length we will accept for a loaded animation duration:
* this is 10 seconds.
*/
@@ -276,8 +286,6 @@
final IBatteryStats mBatteryStats;
- private static final boolean mInEmulator = SystemProperties.get("ro.kernel.qemu").equals("1");
-
/**
* All currently active sessions with clients.
*/
@@ -468,6 +476,7 @@
// visible behind it in case it animates in a way that would allow it to be
// seen.
WindowState mWindowDetachedWallpaper = null;
+ DimSurface mWindowAnimationBackgroundSurface = null;
int mWallpaperAnimLayerAdjustment;
float mLastWallpaperX = -1;
float mLastWallpaperY = -1;
@@ -4940,7 +4949,8 @@
if (mDisplayEnabled) {
// NOTE: We disable the rotation in the emulator because
// it doesn't support hardware OpenGL emulation yet.
- if (CUSTOM_SCREEN_ROTATION && !mInEmulator) {
+ if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null
+ && mScreenRotationAnimation.hasScreenshot()) {
Surface.freezeDisplay(0);
if (!inTransaction) {
if (SHOW_TRANSACTIONS) Slog.i(TAG,
@@ -6802,6 +6812,8 @@
boolean wallpaperMayChange = false;
boolean forceHiding = false;
WindowState windowDetachedWallpaper = null;
+ WindowState windowAnimationBackground = null;
+ int windowAnimationBackgroundColor = 0;
mPolicy.beginAnimationLw(dw, dh);
@@ -6851,8 +6863,15 @@
// an animating window and take care of a request to run
// a detached wallpaper animation.
if (nowAnimating) {
- if (w.mAnimation != null && w.mAnimation.getDetachWallpaper()) {
- windowDetachedWallpaper = w;
+ if (w.mAnimation != null) {
+ if (w.mAnimation.getDetachWallpaper()) {
+ windowDetachedWallpaper = w;
+ }
+ if (w.mAnimation.getBackgroundColor() != 0) {
+ windowAnimationBackground = w;
+ windowAnimationBackgroundColor =
+ w.mAnimation.getBackgroundColor();
+ }
}
animating = true;
}
@@ -6860,9 +6879,15 @@
// If this window's app token is running a detached wallpaper
// animation, make a note so we can ensure the wallpaper is
// displayed behind it.
- if (w.mAppToken != null && w.mAppToken.animation != null
- && w.mAppToken.animation.getDetachWallpaper()) {
- windowDetachedWallpaper = w;
+ if (w.mAppToken != null && w.mAppToken.animation != null) {
+ if (w.mAppToken.animation.getDetachWallpaper()) {
+ windowDetachedWallpaper = w;
+ }
+ if (w.mAppToken.animation.getBackgroundColor() != 0) {
+ windowAnimationBackground = w;
+ windowAnimationBackgroundColor =
+ w.mAppToken.animation.getBackgroundColor();
+ }
}
if (wasAnimating && !w.mAnimating && mWallpaperTarget == w) {
@@ -7301,6 +7326,17 @@
wallpaperMayChange = true;
}
+ if (windowAnimationBackgroundColor != 0) {
+ if (mWindowAnimationBackgroundSurface == null) {
+ mWindowAnimationBackgroundSurface = new DimSurface(mFxSession);
+ }
+ mWindowAnimationBackgroundSurface.show(dw, dh,
+ windowAnimationBackground.mAnimLayer - LAYER_OFFSET_DIM,
+ windowAnimationBackgroundColor);
+ } else if (mWindowAnimationBackgroundSurface != null) {
+ mWindowAnimationBackgroundSurface.hide();
+ }
+
if (wallpaperMayChange) {
if (DEBUG_WALLPAPER) Slog.v(TAG,
"Wallpaper may change! Adjusting");
@@ -7730,7 +7766,7 @@
dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
mBlurSurface.setPosition(0, 0);
mBlurSurface.setSize(dw, dh);
- mBlurSurface.setLayer(w.mAnimLayer-2);
+ mBlurSurface.setLayer(w.mAnimLayer-LAYER_OFFSET_BLUR);
if (!mBlurShown) {
try {
if (SHOW_TRANSACTIONS) Slog.i(TAG, " BLUR "
@@ -7779,7 +7815,8 @@
// Using the same layer as Dim because they will never be shown at the
// same time. NOTE: we do NOT use mAnimLayer, because we don't
// want this surface dragged up in front of stuff that is animating.
- mBackgroundFillerSurface.setLayer(mBackgroundFillerTarget.mLayer - 1);
+ mBackgroundFillerSurface.setLayer(mBackgroundFillerTarget.mLayer
+ - LAYER_OFFSET_DIM);
mBackgroundFillerSurface.show();
} catch (RuntimeException e) {
Slog.e(TAG, "Exception showing filler surface");
@@ -8294,6 +8331,9 @@
mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
mDisplay, mFxSession, inTransaction);
}
+ if (!mScreenRotationAnimation.hasScreenshot()) {
+ Surface.freezeDisplay(0);
+ }
} else {
Surface.freezeDisplay(0);
}
@@ -8316,17 +8356,21 @@
boolean updateRotation = false;
- if (CUSTOM_SCREEN_ROTATION) {
- if (mScreenRotationAnimation != null) {
- if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
- mTransitionAnimationScale)) {
- requestAnimationLocked(0);
- } else {
- mScreenRotationAnimation = null;
- updateRotation = true;
- }
+ if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null
+ && mScreenRotationAnimation.hasScreenshot()) {
+ if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
+ mTransitionAnimationScale)) {
+ requestAnimationLocked(0);
+ } else {
+ mScreenRotationAnimation = null;
+ updateRotation = true;
}
} else {
+ if (mScreenRotationAnimation != null) {
+ mScreenRotationAnimation.kill();
+ mScreenRotationAnimation = null;
+ }
+ updateRotation = true;
Surface.unfreezeDisplay(0);
}
@@ -8589,6 +8633,10 @@
if (mWindowDetachedWallpaper != null) {
pw.print(" mWindowDetachedWallpaper="); pw.println(mWindowDetachedWallpaper);
}
+ if (mWindowAnimationBackgroundSurface != null) {
+ pw.println(" mWindowAnimationBackgroundSurface:");
+ mWindowAnimationBackgroundSurface.printTo(" ", pw);
+ }
pw.print(" mCurConfiguration="); pw.println(this.mCurConfiguration);
pw.print(" mInTouchMode="); pw.print(mInTouchMode);
pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
@@ -8597,7 +8645,8 @@
pw.print(" mLayoutNeeded="); pw.print(mLayoutNeeded);
pw.print(" mBlurShown="); pw.println(mBlurShown);
if (mDimAnimator != null) {
- mDimAnimator.printTo(pw);
+ pw.println(" mDimAnimator:");
+ mDimAnimator.printTo(" ", pw);
} else {
pw.println( " no DimAnimator ");
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 40882d8..554fa43 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2150,8 +2150,8 @@
sh = (!sh) ? hw_h : sh;
const size_t size = sw * sh * 4;
- LOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d",
- sw, sh, minLayerZ, maxLayerZ);
+ //LOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d",
+ // sw, sh, minLayerZ, maxLayerZ);
// make sure to clear all GL error flags
while ( glGetError() != GL_NO_ERROR ) ;
@@ -2236,7 +2236,7 @@
hw.compositionComplete();
- LOGD("screenshot: result = %s", result<0 ? strerror(result) : "OK");
+ // LOGD("screenshot: result = %s", result<0 ? strerror(result) : "OK");
return result;
}
diff --git a/voip/java/android/net/rtp/AudioGroup.java b/voip/java/android/net/rtp/AudioGroup.java
index a6b54d8..20c8969 100644
--- a/voip/java/android/net/rtp/AudioGroup.java
+++ b/voip/java/android/net/rtp/AudioGroup.java
@@ -16,41 +16,47 @@
package android.net.rtp;
+import android.media.AudioManager;
+
import java.util.HashMap;
import java.util.Map;
/**
- * An AudioGroup acts as a router connected to the speaker, the microphone, and
- * {@link AudioStream}s. Its execution loop consists of four steps. First, for
- * each AudioStream not in {@link RtpStream#MODE_SEND_ONLY}, decodes its
- * incoming packets and stores in its buffer. Then, if the microphone is
- * enabled, processes the recorded audio and stores in its buffer. Third, if the
- * speaker is enabled, mixes and playbacks buffers of all AudioStreams. Finally,
- * for each AudioStream not in {@link RtpStream#MODE_RECEIVE_ONLY}, mixes all
- * other buffers and sends back the encoded packets. An AudioGroup does nothing
- * if there is no AudioStream in it.
+ * An AudioGroup is an audio hub for the speaker, the microphone, and
+ * {@link AudioStream}s. Each of these components can be logically turned on
+ * or off by calling {@link #setMode(int)} or {@link RtpStream#setMode(int)}.
+ * The AudioGroup will go through these components and process them one by one
+ * within its execution loop. The loop consists of four steps. First, for each
+ * AudioStream not in {@link RtpStream#MODE_SEND_ONLY}, decodes its incoming
+ * packets and stores in its buffer. Then, if the microphone is enabled,
+ * processes the recorded audio and stores in its buffer. Third, if the speaker
+ * is enabled, mixes all AudioStream buffers and plays back. Finally, for each
+ * AudioStream not in {@link RtpStream#MODE_RECEIVE_ONLY}, mixes all other
+ * buffers and sends back the encoded packets. An AudioGroup does nothing if
+ * there is no AudioStream in it.
*
* <p>Few things must be noticed before using these classes. The performance is
* highly related to the system load and the network bandwidth. Usually a
* simpler {@link AudioCodec} costs fewer CPU cycles but requires more network
- * bandwidth, and vise versa. Using two AudioStreams at the same time not only
- * doubles the load but also the bandwidth. The condition varies from one device
- * to another, and developers must choose the right combination in order to get
- * the best result.
+ * bandwidth, and vise versa. Using two AudioStreams at the same time doubles
+ * not only the load but also the bandwidth. The condition varies from one
+ * device to another, and developers should choose the right combination in
+ * order to get the best result.</p>
*
* <p>It is sometimes useful to keep multiple AudioGroups at the same time. For
* example, a Voice over IP (VoIP) application might want to put a conference
* call on hold in order to make a new call but still allow people in the
- * previous call to talk to each other. This can be done easily using two
+ * conference call talking to each other. This can be done easily using two
* AudioGroups, but there are some limitations. Since the speaker and the
- * microphone are shared globally, only one AudioGroup is allowed to run in
- * modes other than {@link #MODE_ON_HOLD}. In addition, before adding an
- * AudioStream into an AudioGroup, one should always put all other AudioGroups
- * into {@link #MODE_ON_HOLD}. That will make sure the audio driver correctly
- * initialized.</p>
+ * microphone are globally shared resources, only one AudioGroup at a time is
+ * allowed to run in a mode other than {@link #MODE_ON_HOLD}. The others will
+ * be unable to acquire these resources and fail silently.</p>
*
* <p class="note">Using this class requires
- * {@link android.Manifest.permission#RECORD_AUDIO} permission.</p>
+ * {@link android.Manifest.permission#RECORD_AUDIO} permission. Developers
+ * should set the audio mode to {@link AudioManager#MODE_IN_COMMUNICATION}
+ * using {@link AudioManager#setMode(int)} and change it back when none of
+ * the AudioGroups is in use.</p>
*
* @see AudioStream
* @hide
@@ -58,13 +64,13 @@
public class AudioGroup {
/**
* This mode is similar to {@link #MODE_NORMAL} except the speaker and
- * the microphone are disabled.
+ * the microphone are both disabled.
*/
public static final int MODE_ON_HOLD = 0;
/**
* This mode is similar to {@link #MODE_NORMAL} except the microphone is
- * muted.
+ * disabled.
*/
public static final int MODE_MUTED = 1;
@@ -137,20 +143,18 @@
private native void nativeSetMode(int mode);
// Package-private method used by AudioStream.join().
- void add(AudioStream stream, AudioCodec codec, int dtmfType) {
- synchronized (this) {
- if (!mStreams.containsKey(stream)) {
- try {
- int socket = stream.dup();
- String codecSpec = String.format("%d %s %s", codec.type,
- codec.rtpmap, codec.fmtp);
- nativeAdd(stream.getMode(), socket,
- stream.getRemoteAddress().getHostAddress(),
- stream.getRemotePort(), codecSpec, dtmfType);
- mStreams.put(stream, socket);
- } catch (NullPointerException e) {
- throw new IllegalStateException(e);
- }
+ synchronized void add(AudioStream stream, AudioCodec codec, int dtmfType) {
+ if (!mStreams.containsKey(stream)) {
+ try {
+ int socket = stream.dup();
+ String codecSpec = String.format("%d %s %s", codec.type,
+ codec.rtpmap, codec.fmtp);
+ nativeAdd(stream.getMode(), socket,
+ stream.getRemoteAddress().getHostAddress(),
+ stream.getRemotePort(), codecSpec, dtmfType);
+ mStreams.put(stream, socket);
+ } catch (NullPointerException e) {
+ throw new IllegalStateException(e);
}
}
}
@@ -159,12 +163,10 @@
int remotePort, String codecSpec, int dtmfType);
// Package-private method used by AudioStream.join().
- void remove(AudioStream stream) {
- synchronized (this) {
- Integer socket = mStreams.remove(stream);
- if (socket != null) {
- nativeRemove(socket);
- }
+ synchronized void remove(AudioStream stream) {
+ Integer socket = mStreams.remove(stream);
+ if (socket != null) {
+ nativeRemove(socket);
}
}
diff --git a/voip/java/android/net/rtp/AudioStream.java b/voip/java/android/net/rtp/AudioStream.java
index 0edae6b..b45cc5e 100644
--- a/voip/java/android/net/rtp/AudioStream.java
+++ b/voip/java/android/net/rtp/AudioStream.java
@@ -27,8 +27,8 @@
* configured {@link AudioCodec}. On the other side, An {@link AudioGroup}
* represents a local endpoint which mixes all the AudioStreams and optionally
* interacts with the speaker and the microphone at the same time. The simplest
- * usage includes one for each endpoints. For other combinations, users should
- * be aware of the limitations described in {@link AudioGroup}.
+ * usage includes one for each endpoints. For other combinations, developers
+ * should be aware of the limitations described in {@link AudioGroup}.
*
* <p>An AudioStream becomes busy when it joins an AudioGroup. In this case most
* of the setter methods are disabled. This is designed to ease the task of
diff --git a/wifi/java/android/net/wifi/SupplicantState.java b/wifi/java/android/net/wifi/SupplicantState.java
index 169b2d6..6b79210 100644
--- a/wifi/java/android/net/wifi/SupplicantState.java
+++ b/wifi/java/android/net/wifi/SupplicantState.java
@@ -152,6 +152,26 @@
return state != UNINITIALIZED && state != INVALID;
}
+ static boolean isConnecting(SupplicantState state) {
+ switch(state) {
+ case ASSOCIATING:
+ case ASSOCIATED:
+ case FOUR_WAY_HANDSHAKE:
+ case GROUP_HANDSHAKE:
+ case COMPLETED:
+ return true;
+ case DISCONNECTED:
+ case INACTIVE:
+ case SCANNING:
+ case DORMANT:
+ case UNINITIALIZED:
+ case INVALID:
+ return false;
+ default:
+ throw new IllegalArgumentException("Unknown supplicant state");
+ }
+ }
+
/** Implement the Parcelable interface {@hide} */
public int describeContents() {
return 0;
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index e89858c9..589d88c 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -344,6 +344,9 @@
*/
private static final long DEFAULT_SCAN_INTERVAL_MS = 60 * 1000; /* 1 minute */
+ private static final int MIN_RSSI = -200;
+ private static final int MAX_RSSI = 256;
+
/* Default parent state */
private HierarchicalState mDefaultState = new DefaultState();
/* Temporary initial state */
@@ -1239,7 +1242,7 @@
*/
private void fetchRssiAndLinkSpeedNative() {
int newRssi = WifiNative.getRssiCommand();
- if (newRssi != -1 && -200 < newRssi && newRssi < 256) { // screen out invalid values
+ if (newRssi != -1 && MIN_RSSI < newRssi && newRssi < MAX_RSSI) { // screen out invalid values
/* some implementations avoid negative values by adding 256
* so we need to adjust for that here.
*/
@@ -1264,7 +1267,7 @@
}
mLastSignalLevel = newSignalLevel;
} else {
- mWifiInfo.setRssi(-200);
+ mWifiInfo.setRssi(MIN_RSSI);
}
int newLinkSpeed = WifiNative.getLinkSpeedCommand();
if (newLinkSpeed != -1) {
@@ -1386,15 +1389,17 @@
/* Disable interface */
NetworkUtils.disableInterface(mInterfaceName);
- /* send event to CM & network change broadcast */
- setNetworkDetailedState(DetailedState.DISCONNECTED);
- sendNetworkStateChangeBroadcast(mLastBssid);
-
/* Reset data structures */
mWifiInfo.setInetAddress(null);
mWifiInfo.setBSSID(null);
mWifiInfo.setSSID(null);
mWifiInfo.setNetworkId(-1);
+ mWifiInfo.setRssi(MIN_RSSI);
+ mWifiInfo.setLinkSpeed(-1);
+
+ /* send event to CM & network change broadcast */
+ setNetworkDetailedState(DetailedState.DISCONNECTED);
+ sendNetworkStateChangeBroadcast(mLastBssid);
/* Clear network properties */
mLinkProperties.clear();
@@ -2363,7 +2368,10 @@
// 50023 supplicant_state_changed (custom|1|5)
EventLog.writeEvent(EVENTLOG_SUPPLICANT_STATE_CHANGED, state.ordinal());
mWifiInfo.setSupplicantState(state);
- mWifiInfo.setNetworkId(stateChangeResult.networkId);
+ // Network id is only valid when we start connecting
+ if (SupplicantState.isConnecting(state)) {
+ mWifiInfo.setNetworkId(stateChangeResult.networkId);
+ }
if (state == SupplicantState.ASSOCIATING) {
/* BSSID is valid only in ASSOCIATING state */
mWifiInfo.setBSSID(stateChangeResult.BSSID);
@@ -2741,6 +2749,15 @@
}
return HANDLED;
}
+ @Override
+ public void exit() {
+ /* If a scan result is pending in connected state, the supplicant
+ * is in SCAN_ONLY_MODE. Restore CONNECT_MODE on exit
+ */
+ if (mScanResultIsPending) {
+ WifiNative.setScanResultHandlingCommand(CONNECT_MODE);
+ }
+ }
}
class DisconnectingState extends HierarchicalState {