Merge "Fix back popping the back stack too much."
diff --git a/api/current.xml b/api/current.xml
index 64ac66f..2c88f11 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -1482,6 +1482,28 @@
visibility="public"
>
</field>
+<field name="animator_fade_in"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17432609"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="animator_fade_out"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17432610"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="anticipate_interpolator"
type="int"
transient="false"
@@ -4310,6 +4332,50 @@
visibility="public"
>
</field>
+<field name="fragmentCloseEnterAnimation"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843561"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="fragmentCloseExitAnimation"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843562"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="fragmentOpenEnterAnimation"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843559"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="fragmentOpenExitAnimation"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843560"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="freezesText"
type="int"
transient="false"
@@ -10580,6 +10646,17 @@
visibility="public"
>
</field>
+<field name="windowActionBarOverlay"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843558"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="windowActionBarStyle"
type="int"
transient="false"
@@ -20795,6 +20872,19 @@
<parameter name="sequenceItems" type="android.animation.Animatable...">
</parameter>
</method>
+<method name="setTarget"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="target" type="java.lang.Object">
+</parameter>
+</method>
</class>
<class name="Sequencer.Builder"
extends="java.lang.Object"
@@ -20936,6 +21026,17 @@
visibility="public"
>
</method>
+<method name="getHeight"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getNavigationMode"
return="int"
abstract="true"
@@ -20980,6 +21081,17 @@
visibility="public"
>
</method>
+<method name="hide"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="insertTab"
return="void"
abstract="true"
@@ -20995,6 +21107,17 @@
<parameter name="position" type="int">
</parameter>
</method>
+<method name="isShowing"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="newTab"
return="android.app.ActionBar.Tab"
abstract="true"
@@ -21287,6 +21410,17 @@
<parameter name="resId" type="int">
</parameter>
</method>
+<method name="show"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<field name="DISPLAY_HIDE_HOME"
type="int"
transient="false"
@@ -27850,8 +27984,8 @@
<parameter name="savedInstanceState" type="android.os.Bundle">
</parameter>
</method>
-<method name="onCreateAnimation"
- return="android.view.animation.Animation"
+<method name="onCreateAnimatable"
+ return="android.animation.Animatable"
abstract="false"
native="false"
synchronized="false"
@@ -28357,39 +28491,6 @@
<parameter name="fragment" type="android.app.Fragment">
</parameter>
</method>
-<field name="TRANSIT_ACTIVITY_CLOSE"
- type="int"
- transient="false"
- volatile="false"
- value="8199"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="TRANSIT_ACTIVITY_OPEN"
- type="int"
- transient="false"
- volatile="false"
- value="4102"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="TRANSIT_ENTER"
- type="int"
- transient="false"
- volatile="false"
- value="4097"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="TRANSIT_ENTER_MASK"
type="int"
transient="false"
@@ -28401,17 +28502,6 @@
visibility="public"
>
</field>
-<field name="TRANSIT_EXIT"
- type="int"
- transient="false"
- volatile="false"
- value="8194"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="TRANSIT_EXIT_MASK"
type="int"
transient="false"
@@ -28423,11 +28513,22 @@
visibility="public"
>
</field>
-<field name="TRANSIT_HIDE"
+<field name="TRANSIT_FRAGMENT_CLOSE"
type="int"
transient="false"
volatile="false"
- value="8196"
+ value="8194"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TRANSIT_FRAGMENT_OPEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4097"
static="true"
final="true"
deprecated="not deprecated"
@@ -28445,72 +28546,6 @@
visibility="public"
>
</field>
-<field name="TRANSIT_PREVIEW_DONE"
- type="int"
- transient="false"
- volatile="false"
- value="5"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="TRANSIT_SHOW"
- type="int"
- transient="false"
- volatile="false"
- value="4099"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="TRANSIT_TASK_CLOSE"
- type="int"
- transient="false"
- volatile="false"
- value="8201"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="TRANSIT_TASK_OPEN"
- type="int"
- transient="false"
- volatile="false"
- value="4104"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="TRANSIT_TASK_TO_BACK"
- type="int"
- transient="false"
- volatile="false"
- value="8203"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="TRANSIT_TASK_TO_FRONT"
- type="int"
- transient="false"
- volatile="false"
- value="4106"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="TRANSIT_UNSET"
type="int"
transient="false"
@@ -28522,50 +28557,6 @@
visibility="public"
>
</field>
-<field name="TRANSIT_WALLPAPER_CLOSE"
- type="int"
- transient="false"
- volatile="false"
- value="8204"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="TRANSIT_WALLPAPER_INTRA_CLOSE"
- type="int"
- transient="false"
- volatile="false"
- value="8207"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="TRANSIT_WALLPAPER_INTRA_OPEN"
- type="int"
- transient="false"
- volatile="false"
- value="4110"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="TRANSIT_WALLPAPER_OPEN"
- type="int"
- transient="false"
- volatile="false"
- value="4109"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
</interface>
<class name="Instrumentation"
extends="java.lang.Object"
@@ -201148,7 +201139,7 @@
visibility="public"
>
</field>
-<field name="FEATURE_ACTION_MODE_OVERLAY"
+<field name="FEATURE_ACTION_BAR_OVERLAY"
type="int"
transient="false"
volatile="false"
@@ -201159,6 +201150,17 @@
visibility="public"
>
</field>
+<field name="FEATURE_ACTION_MODE_OVERLAY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="10"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FEATURE_CONTEXT_MENU"
type="int"
transient="false"
@@ -201185,7 +201187,7 @@
type="int"
transient="false"
volatile="false"
- value="10"
+ value="11"
static="true"
final="true"
deprecated="not deprecated"
diff --git a/core/java/android/animation/Sequencer.java b/core/java/android/animation/Sequencer.java
index 3278a3e..2406d8a 100644
--- a/core/java/android/animation/Sequencer.java
+++ b/core/java/android/animation/Sequencer.java
@@ -140,6 +140,24 @@
}
/**
+ * Sets the target object for all current {@link #getChildAnimations() child animations}
+ * of this Sequencer that take targets ({@link android.animation.PropertyAnimator} and
+ * Sequencer).
+ *
+ * @param target The object being animated
+ */
+ public void setTarget(Object target) {
+ for (Node node : mNodes) {
+ Animatable animation = node.animation;
+ if (animation instanceof Sequencer) {
+ ((Sequencer)animation).setTarget(target);
+ } else if (animation instanceof PropertyAnimator) {
+ ((PropertyAnimator)animation).setTarget(target);
+ }
+ }
+ }
+
+ /**
* This method creates a <code>Builder</code> object, which is used to
* set up playing constraints. This initial <code>play()</code> method
* tells the <code>Builder</code> the animation that is the dependency for
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index d33494b..38086f0 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -18,6 +18,7 @@
import android.graphics.drawable.Drawable;
import android.view.View;
+import android.view.Window;
import android.widget.SpinnerAdapter;
/**
@@ -383,6 +384,34 @@
public abstract void selectTab(Tab tab);
/**
+ * Retrieve the current height of the ActionBar.
+ *
+ * @return The ActionBar's height
+ */
+ public abstract int getHeight();
+
+ /**
+ * Show the ActionBar if it is not currently showing.
+ * If the window hosting the ActionBar does not have the feature
+ * {@link Window#FEATURE_ACTION_BAR_OVERLAY} it will resize application
+ * content to fit the new space available.
+ */
+ public abstract void show();
+
+ /**
+ * Hide the ActionBar if it is not currently showing.
+ * If the window hosting the ActionBar does not have the feature
+ * {@link Window#FEATURE_ACTION_BAR_OVERLAY} it will resize application
+ * content to fit the new space available.
+ */
+ public abstract void hide();
+
+ /**
+ * @return <code>true</code> if the ActionBar is showing, <code>false</code> otherwise.
+ */
+ public abstract boolean isShowing();
+
+ /**
* Callback interface for ActionBar navigation events.
*/
public interface NavigationCallback {
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 0bb200c..2f61345 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -16,6 +16,7 @@
package android.app;
+import android.animation.Animatable;
import android.content.ComponentCallbacks;
import android.content.Context;
import android.content.Intent;
@@ -35,7 +36,6 @@
import android.view.ViewGroup;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnCreateContextMenuListener;
-import android.view.animation.Animation;
import android.widget.AdapterView;
import java.lang.reflect.InvocationTargetException;
@@ -495,7 +495,10 @@
mCalled = true;
}
- public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
+ /**
+ * Called when a fragment loads an animation.
+ */
+ public Animatable onCreateAnimatable(int transit, boolean enter, int nextAnim) {
return null;
}
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 35b4610..54e37b0 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -16,6 +16,9 @@
package android.app;
+import android.animation.Animatable;
+import android.animation.PropertyAnimator;
+import android.animation.Sequencer;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Handler;
@@ -28,7 +31,6 @@
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
-import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import java.util.ArrayList;
@@ -106,16 +108,16 @@
}
};
- Animation loadAnimation(Fragment fragment, int transit, boolean enter,
+ Animatable loadAnimatable(Fragment fragment, int transit, boolean enter,
int transitionStyle) {
- Animation animObj = fragment.onCreateAnimation(transitionStyle, enter,
+ Animatable animObj = fragment.onCreateAnimatable(transit, enter,
fragment.mNextAnim);
if (animObj != null) {
return animObj;
}
if (fragment.mNextAnim != 0) {
- Animation anim = AnimationUtils.loadAnimation(mActivity, fragment.mNextAnim);
+ Animatable anim = AnimationUtils.loadAnimator(mActivity, fragment.mNextAnim);
if (anim != null) {
return anim;
}
@@ -138,7 +140,7 @@
}
TypedArray attrs = mActivity.obtainStyledAttributes(transitionStyle,
- com.android.internal.R.styleable.WindowAnimation);
+ com.android.internal.R.styleable.FragmentAnimation);
int anim = attrs.getResourceId(styleIndex, 0);
attrs.recycle();
@@ -146,7 +148,7 @@
return null;
}
- return AnimationUtils.loadAnimation(mActivity, anim);
+ return AnimationUtils.loadAnimator(mActivity, anim);
}
void moveToState(Fragment f, int newState, int transit, int transitionStyle) {
@@ -208,10 +210,15 @@
if (f.mView != null) {
f.mView.setSaveFromParentEnabled(false);
if (container != null) {
- Animation anim = loadAnimation(f, transit, true,
+ Animatable anim = loadAnimatable(f, transit, true,
transitionStyle);
if (anim != null) {
- f.mView.setAnimation(anim);
+ if (anim instanceof Sequencer) {
+ ((Sequencer)anim).setTarget(f.mView);
+ } else if (anim instanceof PropertyAnimator) {
+ ((PropertyAnimator)anim).setTarget(f.mView);
+ }
+ anim.start();
}
container.addView(f.mView);
f.restoreViewState();
@@ -290,10 +297,15 @@
}
if (f.mContainer != null) {
if (mCurState > Fragment.INITIALIZING) {
- Animation anim = loadAnimation(f, transit, false,
+ Animatable anim = loadAnimatable(f, transit, true,
transitionStyle);
if (anim != null) {
- f.mView.setAnimation(anim);
+ if (anim instanceof Sequencer) {
+ ((Sequencer)anim).setTarget(f.mView);
+ } else if (anim instanceof PropertyAnimator) {
+ ((PropertyAnimator)anim).setTarget(f.mView);
+ }
+ anim.start();
}
}
f.mContainer.removeView(f.mView);
@@ -420,10 +432,15 @@
if (!fragment.mHidden) {
fragment.mHidden = true;
if (fragment.mView != null) {
- Animation anim = loadAnimation(fragment, transition, false,
+ Animatable anim = loadAnimatable(fragment, transition, true,
transitionStyle);
if (anim != null) {
- fragment.mView.setAnimation(anim);
+ if (anim instanceof Sequencer) {
+ ((Sequencer)anim).setTarget(fragment.mView);
+ } else if (anim instanceof PropertyAnimator) {
+ ((PropertyAnimator)anim).setTarget(fragment.mView);
+ }
+ anim.start();
}
fragment.mView.setVisibility(View.GONE);
}
@@ -439,10 +456,15 @@
if (fragment.mHidden) {
fragment.mHidden = false;
if (fragment.mView != null) {
- Animation anim = loadAnimation(fragment, transition, true,
+ Animatable anim = loadAnimatable(fragment, transition, true,
transitionStyle);
if (anim != null) {
- fragment.mView.setAnimation(anim);
+ if (anim instanceof Sequencer) {
+ ((Sequencer)anim).setTarget(fragment.mView);
+ } else if (anim instanceof PropertyAnimator) {
+ ((PropertyAnimator)anim).setTarget(fragment.mView);
+ }
+ anim.start();
}
fragment.mView.setVisibility(View.VISIBLE);
}
@@ -981,47 +1003,11 @@
public static int reverseTransit(int transit) {
int rev = 0;
switch (transit) {
- case FragmentTransaction.TRANSIT_ENTER:
- rev = FragmentTransaction.TRANSIT_EXIT;
+ case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
+ rev = FragmentTransaction.TRANSIT_FRAGMENT_CLOSE;
break;
- case FragmentTransaction.TRANSIT_EXIT:
- rev = FragmentTransaction.TRANSIT_ENTER;
- break;
- case FragmentTransaction.TRANSIT_SHOW:
- rev = FragmentTransaction.TRANSIT_HIDE;
- break;
- case FragmentTransaction.TRANSIT_HIDE:
- rev = FragmentTransaction.TRANSIT_SHOW;
- break;
- case FragmentTransaction.TRANSIT_ACTIVITY_OPEN:
- rev = FragmentTransaction.TRANSIT_ACTIVITY_CLOSE;
- break;
- case FragmentTransaction.TRANSIT_ACTIVITY_CLOSE:
- rev = FragmentTransaction.TRANSIT_ACTIVITY_OPEN;
- break;
- case FragmentTransaction.TRANSIT_TASK_OPEN:
- rev = FragmentTransaction.TRANSIT_TASK_CLOSE;
- break;
- case FragmentTransaction.TRANSIT_TASK_CLOSE:
- rev = FragmentTransaction.TRANSIT_TASK_OPEN;
- break;
- case FragmentTransaction.TRANSIT_TASK_TO_FRONT:
- rev = FragmentTransaction.TRANSIT_TASK_TO_BACK;
- break;
- case FragmentTransaction.TRANSIT_TASK_TO_BACK:
- rev = FragmentTransaction.TRANSIT_TASK_TO_FRONT;
- break;
- case FragmentTransaction.TRANSIT_WALLPAPER_OPEN:
- rev = FragmentTransaction.TRANSIT_WALLPAPER_CLOSE;
- break;
- case FragmentTransaction.TRANSIT_WALLPAPER_CLOSE:
- rev = FragmentTransaction.TRANSIT_WALLPAPER_OPEN;
- break;
- case FragmentTransaction.TRANSIT_WALLPAPER_INTRA_OPEN:
- rev = FragmentTransaction.TRANSIT_WALLPAPER_INTRA_CLOSE;
- break;
- case FragmentTransaction.TRANSIT_WALLPAPER_INTRA_CLOSE:
- rev = FragmentTransaction.TRANSIT_WALLPAPER_INTRA_OPEN;
+ case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
+ rev = FragmentTransaction.TRANSIT_FRAGMENT_OPEN;
break;
}
return rev;
@@ -1031,67 +1017,15 @@
public static int transitToStyleIndex(int transit, boolean enter) {
int animAttr = -1;
switch (transit) {
- case FragmentTransaction.TRANSIT_ENTER:
- animAttr = com.android.internal.R.styleable.WindowAnimation_windowEnterAnimation;
- break;
- case FragmentTransaction.TRANSIT_EXIT:
- animAttr = com.android.internal.R.styleable.WindowAnimation_windowExitAnimation;
- break;
- case FragmentTransaction.TRANSIT_SHOW:
- animAttr = com.android.internal.R.styleable.WindowAnimation_windowShowAnimation;
- break;
- case FragmentTransaction.TRANSIT_HIDE:
- animAttr = com.android.internal.R.styleable.WindowAnimation_windowHideAnimation;
- break;
- case FragmentTransaction.TRANSIT_ACTIVITY_OPEN:
+ case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
animAttr = enter
- ? com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation
- : com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
+ ? com.android.internal.R.styleable.FragmentAnimation_fragmentOpenEnterAnimation
+ : com.android.internal.R.styleable.FragmentAnimation_fragmentOpenExitAnimation;
break;
- case FragmentTransaction.TRANSIT_ACTIVITY_CLOSE:
+ case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
animAttr = enter
- ? com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation
- : com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
- break;
- case FragmentTransaction.TRANSIT_TASK_OPEN:
- animAttr = enter
- ? com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation
- : com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
- break;
- case FragmentTransaction.TRANSIT_TASK_CLOSE:
- animAttr = enter
- ? com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation
- : com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
- break;
- case FragmentTransaction.TRANSIT_TASK_TO_FRONT:
- animAttr = enter
- ? com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation
- : com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
- break;
- case FragmentTransaction.TRANSIT_TASK_TO_BACK:
- animAttr = enter
- ? com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation
- : com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
- break;
- case FragmentTransaction.TRANSIT_WALLPAPER_OPEN:
- animAttr = enter
- ? com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation
- : com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
- break;
- case FragmentTransaction.TRANSIT_WALLPAPER_CLOSE:
- animAttr = enter
- ? com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation
- : com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
- break;
- case FragmentTransaction.TRANSIT_WALLPAPER_INTRA_OPEN:
- animAttr = enter
- ? com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation
- : com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
- break;
- case FragmentTransaction.TRANSIT_WALLPAPER_INTRA_CLOSE:
- animAttr = enter
- ? com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation
- : com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
+ ? com.android.internal.R.styleable.FragmentAnimation_fragmentCloseEnterAnimation
+ : com.android.internal.R.styleable.FragmentAnimation_fragmentCloseExitAnimation;
break;
}
return animAttr;
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 65cf85c..04598a3 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -100,47 +100,11 @@
public final int TRANSIT_UNSET = -1;
/** No animation for transition. */
public final int TRANSIT_NONE = 0;
- /** Window has been added to the screen. */
- public final int TRANSIT_ENTER = 1 | TRANSIT_ENTER_MASK;
- /** Window has been removed from the screen. */
- public final int TRANSIT_EXIT = 2 | TRANSIT_EXIT_MASK;
- /** Window has been made visible. */
- public final int TRANSIT_SHOW = 3 | TRANSIT_ENTER_MASK;
- /** Window has been made invisible. */
- public final int TRANSIT_HIDE = 4 | TRANSIT_EXIT_MASK;
- /** The "application starting" preview window is no longer needed, and will
- * animate away to show the real window. */
- public final int TRANSIT_PREVIEW_DONE = 5;
- /** A window in a new activity is being opened on top of an existing one
- * in the same task. */
- public final int TRANSIT_ACTIVITY_OPEN = 6 | TRANSIT_ENTER_MASK;
- /** The window in the top-most activity is being closed to reveal the
- * previous activity in the same task. */
- public final int TRANSIT_ACTIVITY_CLOSE = 7 | TRANSIT_EXIT_MASK;
- /** A window in a new task is being opened on top of an existing one
- * in another activity's task. */
- public final int TRANSIT_TASK_OPEN = 8 | TRANSIT_ENTER_MASK;
- /** A window in the top-most activity is being closed to reveal the
- * previous activity in a different task. */
- public final int TRANSIT_TASK_CLOSE = 9 | TRANSIT_EXIT_MASK;
- /** A window in an existing task is being displayed on top of an existing one
- * in another activity's task. */
- public final int TRANSIT_TASK_TO_FRONT = 10 | TRANSIT_ENTER_MASK;
- /** A window in an existing task is being put below all other tasks. */
- public final int TRANSIT_TASK_TO_BACK = 11 | TRANSIT_EXIT_MASK;
- /** A window in a new activity that doesn't have a wallpaper is being
- * opened on top of one that does, effectively closing the wallpaper. */
- public final int TRANSIT_WALLPAPER_CLOSE = 12 | TRANSIT_EXIT_MASK;
- /** A window in a new activity that does have a wallpaper is being
- * opened on one that didn't, effectively opening the wallpaper. */
- public final int TRANSIT_WALLPAPER_OPEN = 13 | TRANSIT_ENTER_MASK;
- /** A window in a new activity is being opened on top of an existing one,
- * and both are on top of the wallpaper. */
- public final int TRANSIT_WALLPAPER_INTRA_OPEN = 14 | TRANSIT_ENTER_MASK;
- /** The window in the top-most activity is being closed to reveal the
- * previous activity, and both are on top of he wallpaper. */
- public final int TRANSIT_WALLPAPER_INTRA_CLOSE = 15 | TRANSIT_EXIT_MASK;
-
+ /** Fragment is being added */
+ public final int TRANSIT_FRAGMENT_OPEN = 1 | TRANSIT_ENTER_MASK;
+ /** Fragment is being removed */
+ public final int TRANSIT_FRAGMENT_CLOSE = 2 | TRANSIT_EXIT_MASK;
+
public FragmentTransaction setCustomAnimations(int enter, int exit);
public FragmentTransaction setTransition(int transit);
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index 69b3540..a9d7342 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -180,6 +180,11 @@
return mThread;
}
+ /** @hide */
+ public MessageQueue getQueue() {
+ return mQueue;
+ }
+
public void dump(Printer pw, String prefix) {
pw.println(prefix + this);
pw.println(prefix + "mRun=" + mRun);
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index e13c3e8..114f67d 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -125,6 +125,9 @@
// Back will then return RESULT_CANCELED and Next RESULT_OK
private static final String EXTRA_PREFS_SHOW_BUTTON_BAR = "extra_prefs_show_button_bar";
+ // add a Skip button?
+ private static final String EXTRA_PREFS_SHOW_SKIP = "extra_prefs_show_skip";
+
// specify custom text for the Back or Next buttons, or cause a button to not appear
// at all by setting it to null
private static final String EXTRA_PREFS_SET_NEXT_TEXT = "extra_prefs_set_next_text";
@@ -307,6 +310,13 @@
finish();
}
});
+ Button skipButton = (Button)findViewById(com.android.internal.R.id.skip_button);
+ skipButton.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ setResult(RESULT_OK);
+ finish();
+ }
+ });
mNextButton = (Button)findViewById(com.android.internal.R.id.next_button);
mNextButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
@@ -334,6 +344,9 @@
backButton.setText(buttonText);
}
}
+ if (intent.getBooleanExtra(EXTRA_PREFS_SHOW_SKIP, false)) {
+ skipButton.setVisibility(View.VISIBLE);
+ }
}
}
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index cd6b820..44bd6d4 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -300,7 +300,6 @@
*/
if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
throw new RuntimeException("eglMakeCurrent failed");
-
}
return mEglContext.getGL();
@@ -374,6 +373,15 @@
attachInfo.mIgnoreDirtyState = true;
view.mPrivateFlags |= View.DRAWN;
+ // TODO: Don't check the current context when we have one per UI thread
+ // TODO: Use a threadlocal flag to know whether the surface has changed
+ if (mEgl.eglGetCurrentContext() != mEglContext ||
+ mEgl.eglGetCurrentSurface(EGL10.EGL_DRAW) != mEglSurface) {
+ if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+ throw new RuntimeException("eglMakeCurrent failed");
+ }
+ }
+
onPreDraw();
Canvas canvas = mCanvas;
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index d6b9212..e86e3bf 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -28,6 +28,7 @@
import android.view.KeyEvent;
import android.view.InputEvent;
import android.view.MotionEvent;
+import android.view.InputChannel;
/**
* System private interface to the window manager.
@@ -119,6 +120,7 @@
int getKeycodeStateForDevice(int devid, int sw);
int getTrackballKeycodeState(int sw);
int getDPadKeycodeState(int sw);
+ InputChannel monitorInput(String inputChannelName);
// Report whether the hardware supports the given keys; returns true if successful
boolean hasKeys(in int[] keycodes, inout boolean[] keyExists);
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 8abbf58..faa4783 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -33,6 +33,7 @@
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.EventLog;
+import android.util.Slog;
import android.util.SparseArray;
import android.view.View.MeasureSpec;
import android.view.accessibility.AccessibilityEvent;
@@ -1719,7 +1720,7 @@
if (LOCAL_LOGV) Log.v(
TAG, "Dispatching key "
+ msg.obj + " to " + mView);
- deliverKeyEvent((KeyEvent)msg.obj, true);
+ deliverKeyEvent((KeyEvent)msg.obj, msg.arg1 != 0);
break;
case DISPATCH_POINTER: {
MotionEvent event = (MotionEvent) msg.obj;
@@ -1860,9 +1861,14 @@
}
private void finishKeyEvent(KeyEvent event) {
+ if (LOCAL_LOGV) Log.v(TAG, "Telling window manager key is finished");
+
if (mFinishedCallback != null) {
mFinishedCallback.run();
mFinishedCallback = null;
+ } else {
+ Slog.w(TAG, "Attempted to tell the input queue that the current key event "
+ + "is finished but there is no key event actually in progress.");
}
}
@@ -2321,8 +2327,6 @@
boolean handled = mView == null || mView.dispatchKeyEventPreIme(event);
if (handled) {
if (sendDone) {
- if (LOCAL_LOGV) Log.v(
- TAG, "Telling window manager key is finished");
finishKeyEvent(event);
}
return;
@@ -2353,8 +2357,6 @@
if (!handled) {
deliverKeyEventToViewHierarchy(event, sendDone);
} else if (sendDone) {
- if (LOCAL_LOGV) Log.v(
- TAG, "Telling window manager key is finished");
finishKeyEvent(event);
} else {
Log.w(TAG, "handleFinishedEvent(seq=" + seq
@@ -2428,8 +2430,6 @@
} finally {
if (sendDone) {
- if (LOCAL_LOGV) Log.v(
- TAG, "Telling window manager key is finished");
finishKeyEvent(event);
}
// Let the exception fall through -- the looper will catch
@@ -2613,9 +2613,14 @@
private final InputHandler mInputHandler = new InputHandler() {
public void handleKey(KeyEvent event, Runnable finishedCallback) {
+ if (mFinishedCallback != null) {
+ Slog.w(TAG, "Received a new key event from the input queue but there is "
+ + "already an unfinished key event in progress.");
+ }
+
mFinishedCallback = finishedCallback;
- dispatchKey(event);
+ dispatchKey(event, true);
}
public void handleMotion(MotionEvent event, Runnable finishedCallback) {
@@ -2626,9 +2631,13 @@
};
public void dispatchKey(KeyEvent event) {
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- //noinspection ConstantConditions
- if (false && event.getKeyCode() == KeyEvent.KEYCODE_CAMERA) {
+ dispatchKey(event, false);
+ }
+
+ private void dispatchKey(KeyEvent event, boolean sendDone) {
+ //noinspection ConstantConditions
+ if (false && event.getAction() == KeyEvent.ACTION_DOWN) {
+ if (event.getKeyCode() == KeyEvent.KEYCODE_CAMERA) {
if (DBG) Log.d("keydisp", "===================================================");
if (DBG) Log.d("keydisp", "Focused view Hierarchy is:");
@@ -2640,6 +2649,7 @@
Message msg = obtainMessage(DISPATCH_KEY);
msg.obj = event;
+ msg.arg1 = sendDone ? 1 : 0;
if (LOCAL_LOGV) Log.v(
TAG, "sending key " + event + " to " + mView);
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index f32ff77..36f6bb2 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -64,14 +64,24 @@
*/
public static final int FEATURE_ACTION_BAR = 8;
/**
+ * Flag for requesting an Action Bar that overlays window content.
+ * Normally an Action Bar will sit in the space above window content, but if this
+ * feature is requested along with {@link #FEATURE_ACTION_BAR} it will be layered over
+ * the window content itself. This is useful if you would like your app to have more control
+ * over how the Action Bar is displayed, such as letting application content scroll beneath
+ * an Action Bar with a transparent background or otherwise displaying a transparent/translucent
+ * Action Bar over application content.
+ */
+ public static final int FEATURE_ACTION_BAR_OVERLAY = 9;
+ /**
* Flag for specifying the behavior of action modes when an Action Bar is not present.
* If overlay is enabled, the action mode UI will be allowed to cover existing window content.
*/
- public static final int FEATURE_ACTION_MODE_OVERLAY = 9;
+ public static final int FEATURE_ACTION_MODE_OVERLAY = 10;
/**
* Flag for requesting this window to be hardware accelerated, if possible.
*/
- public static final int FEATURE_HARDWARE_ACCELERATED = 10;
+ public static final int FEATURE_HARDWARE_ACCELERATED = 11;
/** Flag for setting the progress bar's visibility to VISIBLE */
public static final int PROGRESS_VISIBILITY_ON = -1;
/** Flag for setting the progress bar's visibility to GONE */
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 33757f0..659f9cd 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -779,11 +779,6 @@
*/
public void enableScreenAfterBoot();
- /**
- * Called every time the window manager is dispatching a pointer event.
- */
- public void dispatchedPointerEventLw(MotionEvent ev, int targetX, int targetY);
-
public void setCurrentOrientationLw(int newOrientation);
/**
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 5c34c2c..35e0603 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -33,7 +33,7 @@
/**
* A ListPopupWindow anchors itself to a host view and displays a
- * list of choices. When one is selected, the popup is dismissed.
+ * list of choices.
*
* <p>ListPopupWindow contains a number of tricky behaviors surrounding
* positioning, scrolling parents to fit the dropdown, interacting
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 6b52409..dd2ad6c 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -397,6 +397,27 @@
trans.commit();
}
+ @Override
+ public int getHeight() {
+ return mActionView.getHeight();
+ }
+
+ @Override
+ public void show() {
+ // TODO animate!
+ mAnimatorView.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void hide() {
+ // TODO animate!
+ mAnimatorView.setVisibility(View.GONE);
+ }
+
+ public boolean isShowing() {
+ return mAnimatorView.getVisibility() == View.VISIBLE;
+ }
+
/**
* @hide
*/
@@ -510,6 +531,8 @@
}
public void onMenuModeChange(MenuBuilder menu) {
+ invalidate();
+ mUpperContextView.showOverflowMenu();
}
}
diff --git a/core/java/com/android/internal/view/StandaloneActionMode.java b/core/java/com/android/internal/view/StandaloneActionMode.java
index e6d6ba0..ab80c58 100644
--- a/core/java/com/android/internal/view/StandaloneActionMode.java
+++ b/core/java/com/android/internal/view/StandaloneActionMode.java
@@ -135,5 +135,7 @@
}
public void onMenuModeChange(MenuBuilder menu) {
+ invalidate();
+ mContextView.showOverflowMenu();
}
}
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index 1357251..cb5f179 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -20,6 +20,7 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.LinearLayout;
@@ -82,6 +83,7 @@
if (p instanceof LayoutParams) {
LayoutParams lp = (LayoutParams) p;
return lp.leftMargin == mItemMargin && lp.rightMargin == mItemMargin &&
+ lp.gravity == Gravity.CENTER_VERTICAL &&
lp.width == LayoutParams.WRAP_CONTENT && lp.height == LayoutParams.WRAP_CONTENT;
}
return false;
@@ -93,6 +95,7 @@
LayoutParams.WRAP_CONTENT);
params.leftMargin = mItemMargin;
params.rightMargin = mItemMargin;
+ params.gravity = Gravity.CENTER_VERTICAL;
return params;
}
@@ -145,14 +148,28 @@
public boolean showOverflowMenu() {
if (mOverflowButton != null) {
- MenuPopupHelper popup = new MenuPopupHelper(getContext(), mMenu, mOverflowButton, true);
- popup.show();
+ final MenuPopupHelper popup =
+ new MenuPopupHelper(getContext(), mMenu, mOverflowButton, true);
+ // Post this for later; we might still need a layout for the anchor to be right.
+ post(new Runnable() {
+ public void run() {
+ popup.show();
+ }
+ });
mOverflowPopup = new WeakReference<MenuPopupHelper>(popup);
return true;
}
return false;
}
+ public boolean isOverflowMenuShowing() {
+ MenuPopupHelper popup = mOverflowPopup != null ? mOverflowPopup.get() : null;
+ if (popup != null) {
+ return popup.isShowing();
+ }
+ return false;
+ }
+
public boolean hideOverflowMenu() {
MenuPopupHelper popup = mOverflowPopup != null ? mOverflowPopup.get() : null;
if (popup != null) {
@@ -174,7 +191,7 @@
final Resources res = context.getResources();
setClickable(true);
setFocusable(true);
- // TODO setTitle() to a localized string for accessibility
+ setContentDescription(res.getString(com.android.internal.R.string.more_item_label));
setImageDrawable(res.getDrawable(com.android.internal.R.drawable.ic_menu_more));
setVisibility(VISIBLE);
setEnabled(true);
@@ -186,7 +203,8 @@
return true;
}
- showOverflowMenu();
+ // Change to overflow mode
+ mMenu.getCallback().onMenuModeChange(mMenu);
return true;
}
}
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index ce0ec04..f52c93c 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -92,7 +92,9 @@
}
public void dismiss() {
- mPopup.dismiss();
+ if (isShowing()) {
+ mPopup.dismiss();
+ }
mPopup = null;
}
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 5518b3e..6a476d0 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -163,6 +163,27 @@
mMenuView = null;
}
+ public boolean showOverflowMenu() {
+ if (mMenuView != null) {
+ return mMenuView.showOverflowMenu();
+ }
+ return false;
+ }
+
+ public boolean hideOverflowMenu() {
+ if (mMenuView != null) {
+ return mMenuView.hideOverflowMenu();
+ }
+ return false;
+ }
+
+ public boolean isOverflowMenuShowing() {
+ if (mMenuView != null) {
+ return mMenuView.isOverflowMenuShowing();
+ }
+ return false;
+ }
+
@Override
protected LayoutParams generateDefaultLayoutParams() {
// Used by custom views if they don't supply layout params. Everything else
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index c641441..73d3c95 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -118,7 +118,6 @@
super(context, attrs);
final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
- mContentHeight = (int) (CONTENT_HEIGHT_DIP * metrics.density + 0.5f);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar);
@@ -157,14 +156,18 @@
LayoutInflater inflater = LayoutInflater.from(context);
mCustomNavView = (View) inflater.inflate(customNavId, null);
mNavigationMode = ActionBar.NAVIGATION_MODE_CUSTOM;
+ addView(mCustomNavView);
}
+ final int padding = a.getDimensionPixelSize(R.styleable.ActionBar_padding,
+ (int) (CONTENT_PADDING_DIP * metrics.density + 0.5f));
+ setPadding(padding, padding, padding, padding);
+ mContentHeight = a.getDimensionPixelSize(R.styleable.ActionBar_height,
+ (int) (CONTENT_PADDING_DIP * metrics.density + 0.5f)) - padding * 2;
+
a.recycle();
// TODO: Set this in the theme
- int padding = (int) (CONTENT_PADDING_DIP * metrics.density + 0.5f);
- setPadding(padding, padding, padding, padding);
-
mSpacing = (int) (CONTENT_SPACING_DIP * metrics.density + 0.5f);
mActionSpacing = (int) (CONTENT_ACTION_SPACING_DIP * metrics.density + 0.5f);
@@ -216,6 +219,13 @@
return false;
}
+ public boolean isOverflowMenuShowing() {
+ if (mMenuView != null) {
+ return mMenuView.isOverflowMenuShowing();
+ }
+ return false;
+ }
+
public boolean isOverflowReserved() {
return mMenuView != null && mMenuView.isOverflowReserved();
}
diff --git a/core/res/res/anim/animator_fade_in.xml b/core/res/res/anim/animator_fade_in.xml
new file mode 100644
index 0000000..cd5042f
--- /dev/null
+++ b/core/res/res/anim/animator_fade_in.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2010, 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.
+*/
+-->
+
+<property xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/accelerate_interpolator"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:propertyName="alpha"
+ android:duration="@android:integer/config_mediumAnimTime"
+/>
diff --git a/core/res/res/anim/animator_fade_out.xml b/core/res/res/anim/animator_fade_out.xml
new file mode 100644
index 0000000..dfb5d9c
--- /dev/null
+++ b/core/res/res/anim/animator_fade_out.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2010, 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.
+*/
+-->
+
+<property xmlns:android="http://schemas.android.com/apk/res/android"
+ android:interpolator="@anim/accelerate_interpolator"
+ android:valueFrom="1.0"
+ android:valueTo="0.0"
+ android:propertyName="alpha"
+ android:duration="@android:integer/config_mediumAnimTime"
+/>
diff --git a/core/res/res/anim/fragment_close_enter.xml b/core/res/res/anim/fragment_close_enter.xml
new file mode 100644
index 0000000..d4091e8
--- /dev/null
+++ b/core/res/res/anim/fragment_close_enter.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2010, 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.
+*/
+-->
+<sequencer xmlns:android="http://schemas.android.com/apk/res/android">
+ <property
+ android:interpolator="@anim/decelerate_interpolator"
+ android:valueFrom="2"
+ android:valueTo="1"
+ android:valueType="floatType"
+ android:propertyName="scaleX"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <property
+ android:interpolator="@anim/decelerate_interpolator"
+ android:valueFrom="2"
+ android:valueTo="1"
+ android:valueType="floatType"
+ android:propertyName="scaleY"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <property
+ android:interpolator="@anim/decelerate_interpolator"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType"
+ android:propertyName="alpha"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <property
+ android:interpolator="@anim/decelerate_interpolator"
+ android:valueFrom="-400"
+ android:valueTo="0"
+ android:valueType="floatType"
+ android:propertyName="translationX"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+</sequencer>
\ No newline at end of file
diff --git a/core/res/res/anim/fragment_close_exit.xml b/core/res/res/anim/fragment_close_exit.xml
new file mode 100644
index 0000000..3e2cd22
--- /dev/null
+++ b/core/res/res/anim/fragment_close_exit.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2010, 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.
+*/
+-->
+<sequencer xmlns:android="http://schemas.android.com/apk/res/android">
+ <property
+ android:interpolator="@anim/accelerate_interpolator"
+ android:valueFrom="1"
+ android:valueTo=".5"
+ android:valueType="floatType"
+ android:propertyName="scaleX"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <property
+ android:interpolator="@anim/accelerate_interpolator"
+ android:valueFrom="1"
+ android:valueTo=".5"
+ android:valueType="floatType"
+ android:propertyName="scaleY"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <property
+ android:interpolator="@anim/accelerate_interpolator"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType"
+ android:propertyName="alpha"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <property
+ android:interpolator="@anim/accelerate_interpolator"
+ android:valueFrom="0"
+ android:valueTo="400"
+ android:valueType="floatType"
+ android:propertyName="translationX"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+</sequencer>
\ No newline at end of file
diff --git a/core/res/res/anim/fragment_open_enter.xml b/core/res/res/anim/fragment_open_enter.xml
new file mode 100644
index 0000000..c89001c
--- /dev/null
+++ b/core/res/res/anim/fragment_open_enter.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2010, 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.
+*/
+-->
+<sequencer xmlns:android="http://schemas.android.com/apk/res/android">
+ <property
+ android:interpolator="@anim/decelerate_interpolator"
+ android:valueFrom="2"
+ android:valueTo="1"
+ android:valueType="floatType"
+ android:propertyName="scaleX"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <property
+ android:interpolator="@anim/decelerate_interpolator"
+ android:valueFrom="2"
+ android:valueTo="1"
+ android:valueType="floatType"
+ android:propertyName="scaleY"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <property
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType"
+ android:propertyName="alpha"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <property
+ android:valueFrom="400"
+ android:valueTo="0"
+ android:valueType="floatType"
+ android:propertyName="translationX"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+</sequencer>
\ No newline at end of file
diff --git a/core/res/res/anim/fragment_open_exit.xml b/core/res/res/anim/fragment_open_exit.xml
new file mode 100644
index 0000000..427fe4f
--- /dev/null
+++ b/core/res/res/anim/fragment_open_exit.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2010, 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.
+*/
+-->
+<sequencer xmlns:android="http://schemas.android.com/apk/res/android">
+ <property
+ android:interpolator="@anim/accelerate_interpolator"
+ android:valueFrom="1"
+ android:valueTo="2"
+ android:valueType="floatType"
+ android:propertyName="scaleX"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <property
+ android:interpolator="@anim/accelerate_interpolator"
+ android:valueFrom="1"
+ android:valueTo="2"
+ android:valueType="floatType"
+ android:propertyName="scaleY"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <property
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType"
+ android:propertyName="alpha"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+ <property
+ android:valueFrom="0"
+ android:valueTo="-400"
+ android:valueType="floatType"
+ android:propertyName="translationX"
+ android:duration="@android:integer/config_mediumAnimTime"/>
+</sequencer>
\ No newline at end of file
diff --git a/core/res/res/layout-xlarge/screen_action_bar_overlay.xml b/core/res/res/layout-xlarge/screen_action_bar_overlay.xml
new file mode 100644
index 0000000..d0277f0
--- /dev/null
+++ b/core/res/res/layout-xlarge/screen_action_bar_overlay.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+
+<!--
+This is an optimized layout for a screen with
+the Action Bar enabled overlaying application content.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fitsSystemWindows="true">
+ <FrameLayout android:id="@android:id/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+ <ViewAnimator android:id="@+id/action_bar_animator"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="top"
+ android:inAnimation="@anim/push_down_in"
+ android:outAnimation="@anim/push_down_out">
+ <com.android.internal.widget.ActionBarView
+ android:id="@+id/action_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="?android:attr/windowActionBarStyle" />
+ <com.android.internal.widget.ActionBarContextView
+ android:id="@+id/action_context_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </ViewAnimator>
+ <ImageView android:src="?android:attr/windowContentOverlay"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/action_bar_animator" />
+</RelativeLayout>
diff --git a/core/res/res/layout/preference_list_content.xml b/core/res/res/layout/preference_list_content.xml
index d530e96..eeba18e 100644
--- a/core/res/res/layout/preference_list_content.xml
+++ b/core/res/res/layout/preference_list_content.xml
@@ -59,15 +59,28 @@
android:drawablePadding="3dip"
android:text="@string/back_button_label"
/>
-
- <Button android:id="@+id/next_button"
- android:layout_width="150dip"
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_margin="5dip"
- android:layout_alignParentRight="true"
- android:drawableRight="@drawable/ic_btn_next"
- android:drawablePadding="3dip"
- android:text="@string/next_button_label"
- />
+ android:layout_alignParentRight="true">
+
+ <Button android:id="@+id/skip_button"
+ android:layout_width="150dip"
+ android:layout_height="wrap_content"
+ android:layout_margin="5dip"
+ android:text="@string/skip_button_label"
+ android:visibility="gone"
+ />
+
+ <Button android:id="@+id/next_button"
+ android:layout_width="150dip"
+ android:layout_height="wrap_content"
+ android:layout_margin="5dip"
+ android:drawableRight="@drawable/ic_btn_next"
+ android:drawablePadding="3dip"
+ android:text="@string/next_button_label"
+ />
+ </LinearLayout>
</RelativeLayout>
</LinearLayout>
diff --git a/core/res/res/layout/screen_action_bar_overlay.xml b/core/res/res/layout/screen_action_bar_overlay.xml
new file mode 100644
index 0000000..cb1ffc5
--- /dev/null
+++ b/core/res/res/layout/screen_action_bar_overlay.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+
+<!--
+This is an optimized layout for a screen with
+the Action Bar enabled overlaying application content.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fitsSystemWindows="true">
+ <FrameLayout android:id="@android:id/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+ <ViewAnimator android:id="@+id/action_bar_animator"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="top"
+ android:inAnimation="@anim/push_down_in"
+ android:outAnimation="@anim/push_down_out">
+ <com.android.internal.widget.ActionBarView
+ android:id="@+id/action_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="?android:attr/windowActionBarStyle" />
+ <com.android.internal.widget.ActionBarContextView
+ android:id="@+id/action_context_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ </ViewAnimator>
+ <ImageView android:src="?android:attr/windowContentOverlay"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/action_bar_animator" />
+ <LinearLayout android:id="@+id/lower_action_context_bar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ style="?android:attr/windowActionBarStyle"
+ android:visibility="gone" />
+</RelativeLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 97c5822..a75f1a6 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -248,6 +248,11 @@
in place of the usual title bar. -->
<attr name="windowActionBar" format="boolean" />
+ <!-- Flag indicating whether this window's Action Bar should overlay
+ application content. Does nothing if the window would not
+ have an Action Bar. -->
+ <attr name="windowActionBarOverlay" format="boolean" />
+
<!-- Reference to a style for the Action Bar -->
<attr name="windowActionBarStyle" format="reference" />
@@ -999,6 +1004,7 @@
<attr name="windowActionBar" />
<attr name="windowActionBarStyle" />
<attr name="windowActionModeOverlay" />
+ <attr name="windowActionBarOverlay" />
</declare-styleable>
<!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -1015,6 +1021,14 @@
<attr name="centerMedium" format="reference|color" />
</declare-styleable>
+ <!-- Fragment animation class attributes. -->
+ <declare-styleable name="FragmentAnimation">
+ <attr name="fragmentOpenEnterAnimation" format="reference" />
+ <attr name="fragmentOpenExitAnimation" format="reference" />
+ <attr name="fragmentCloseEnterAnimation" format="reference" />
+ <attr name="fragmentCloseExitAnimation" format="reference" />
+ </declare-styleable>
+
<!-- Window animation class attributes. -->
<declare-styleable name="WindowAnimation">
<!-- The animation used when a window is being added. -->
@@ -3987,6 +4001,10 @@
<attr name="background" />
<!-- Specifies a layout for custom navigation. Overrides navigationMode. -->
<attr name="customNavigationLayout" format="reference" />
+ <!-- Specifies a fixed height. -->
+ <attr name="height" />
+ <!-- Specifies padding around all sides. -->
+ <attr name="padding" />
</declare-styleable>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 99263d7..539f1c0 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1315,6 +1315,13 @@
<public type="attr" name="propertyName" />
<public type="attr" name="ordering" />
<public type="attr" name="fragment" />
+ <public type="attr" name="windowActionBarOverlay" />
+ <public type="attr" name="fragmentOpenEnterAnimation" />
+ <public type="attr" name="fragmentOpenExitAnimation" />
+ <public type="attr" name="fragmentCloseEnterAnimation" />
+ <public type="attr" name="fragmentCloseExitAnimation" />
+ <public type="anim" name="animator_fade_in" />
+ <public type="anim" name="animator_fade_out" />
<public type="id" name="home" />
<!-- Context menu ID for the "Select text..." menu item to switch to text
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 00ebe2b..2b27930 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -807,8 +807,8 @@
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_writeCalendar">add or modify calendar events and send email to guests</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_writeCalendar">Allows an application to add or change the
- events on your calendar, which may send email to guests. Malicious applications can use this
+ <string name="permdesc_writeCalendar">Allows an application to add or change the
+ events on your calendar, which may send email to guests. Malicious applications can use this
to erase or modify your calendar events or to send email to guests.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -1918,7 +1918,7 @@
<!-- Text shown by list fragment when waiting for data to display. -->
<string name="loading">Loading...</string>
-
+
<!-- Default text for a button that can be toggled on and off. -->
<string name="capital_on">ON</string>
<!-- Default text for a button that can be toggled on and off. -->
@@ -1969,23 +1969,23 @@
<!-- Notification text to tell the user that a heavy-weight application is running. -->
<string name="heavy_weight_notification"><xliff:g id="app">%1$s</xliff:g> running</string>
-
+
<!-- Notification details to tell the user that a heavy-weight application is running. -->
<string name="heavy_weight_notification_detail">Select to switch to application</string>
-
+
<!-- Title of dialog prompting whether user wants to switch between heavy-weight apps. -->
<string name="heavy_weight_switcher_title">Switch applications?</string>
-
+
<!-- Descriptive text for switching to a new heavy-weight application. -->
<string name="heavy_weight_switcher_text">Another application is already running
that must be stopped before you can start a new one.</string>
-
+
<string name="old_app_action">Return to <xliff:g id="old_app">%1$s</xliff:g></string>
<string name="old_app_description">Don\'t start the new application.</string>
-
+
<string name="new_app_action">Start <xliff:g id="old_app">%1$s</xliff:g></string>
<string name="new_app_description">Stop the old application without saving.</string>
-
+
<!-- Displayed in the title of the chooser for things to do with text that
is to be sent to another application. For example, I can send
text through SMS or IM. A dialog with those choices would be shown,
@@ -2278,6 +2278,9 @@
<string name="back_button_label">Back</string>
<string name="next_button_label">Next</string>
+ <!-- Optional button to Skip a PreferenceActivity [CHAR LIMIT=20] -->
+ <string name="skip_button_label">Skip</string>
+
<!-- Strings for throttling notification -->
<!-- Shown when the user is in danger of being throttled -->
<string name="throttle_warning_notification_title">High mobile data use</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index e0dc3a9..7e52ebd 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -74,6 +74,10 @@
<item name="wallpaperIntraOpenExitAnimation">@anim/wallpaper_intra_open_exit</item>
<item name="wallpaperIntraCloseEnterAnimation">@anim/wallpaper_intra_close_enter</item>
<item name="wallpaperIntraCloseExitAnimation">@anim/wallpaper_intra_close_exit</item>
+ <item name="fragmentOpenEnterAnimation">@anim/fragment_open_enter</item>
+ <item name="fragmentOpenExitAnimation">@anim/fragment_open_exit</item>
+ <item name="fragmentCloseEnterAnimation">@anim/fragment_close_enter</item>
+ <item name="fragmentCloseExitAnimation">@anim/fragment_close_exit</item>
</style>
<!-- Standard animations for a non-full-screen window or activity. -->
@@ -889,6 +893,8 @@
<item name="android:background">@android:drawable/action_bar_background</item>
<item name="android:displayOptions">useLogo</item>
<item name="android:divider">@android:drawable/action_bar_divider</item>
+ <item name="android:height">56dip</item>
+ <item name="android:padding">3dip</item>
</style>
<style name="Widget.ActionButton">
diff --git a/include/utils/String8.h b/include/utils/String8.h
index 4e41410..ef0b51a 100644
--- a/include/utils/String8.h
+++ b/include/utils/String8.h
@@ -171,7 +171,8 @@
status_t append(const char* other);
status_t append(const char* other, size_t numChars);
- status_t appendFormat(const char* fmt, ...);
+ status_t appendFormat(const char* fmt, ...)
+ __attribute__((format (printf, 2, 3)));
// Note that this function takes O(N) time to calculate the value.
// No cache value is stored.
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index aaf7564..3c1fe2a 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -160,7 +160,9 @@
mTextureCache.clear();
mLayerCache.clear();
mGradientCache.clear();
+ mPathCache.clear();
mPatchCache.clear();
+ mProgramCache.clear();
}
///////////////////////////////////////////////////////////////////////////////
@@ -410,8 +412,14 @@
}
bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) {
- Rect r(left, top, right, bottom);
- mSnapshot->transform.mapRect(r);
+ SkRect sr;
+ sr.set(left, top, right, bottom);
+
+ SkMatrix m;
+ mSnapshot->transform.copyTo(m);
+ m.mapRect(&sr);
+
+ Rect r(sr.fLeft, sr.fTop, sr.fRight, sr.fBottom);
return !mSnapshot->clipRect.intersects(r);
}
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index dbae38e..6528d91 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -51,6 +51,8 @@
LOGE("Error while linking shaders: %s", log);
delete log;
}
+ glDeleteShader(vertexShader);
+ glDeleteShader(fragmentShader);
glDeleteProgram(id);
}
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index 54850ee..fa4b8c4 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -35,7 +35,7 @@
///////////////////////////////////////////////////////////////////////////////
// Debug
-#define DEBUG_PROGRAM_CACHE 1
+#define DEBUG_PROGRAM_CACHE 0
// Debug
#if DEBUG_PROGRAM_CACHE
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 399ae68..342e5b1 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -96,9 +96,14 @@
bool clip(float left, float top, float right, float bottom, SkRegion::Op op) {
bool clipped = false;
- Rect r(left, top, right, bottom);
- transform.mapRect(r);
+ SkRect sr;
+ sr.set(left, top, right, bottom);
+ SkMatrix m;
+ transform.copyTo(m);
+ m.mapRect(&sr);
+
+ Rect r(sr.fLeft, sr.fTop, sr.fRight, sr.fBottom);
switch (op) {
case SkRegion::kDifference_Op:
break;
@@ -137,8 +142,16 @@
if (flags & Snapshot::kFlagDirtyLocalClip) {
mat4 inverse;
inverse.loadInverse(transform);
- localClip.set(clipRect);
- inverse.mapRect(localClip);
+
+ SkRect sr;
+ sr.set(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
+
+ SkMatrix m;
+ inverse.copyTo(m);
+ m.mapRect(&sr);
+
+ localClip.set(sr.fLeft, sr.fTop, sr.fRight, sr.fBottom);
+
flags &= ~Snapshot::kFlagDirtyLocalClip;
}
return localClip;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 8a6428b..546c0f4 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -599,7 +599,7 @@
// The panel key was pushed, so set the chording key
mPanelChordingKey = keyCode;
mPanelMayLongPress = false;
-
+
PanelFeatureState st = getPanelState(featureId, true);
if (!st.isOpen) {
if (getContext().getResources().getConfiguration().keyboard
@@ -608,7 +608,6 @@
}
return preparePanel(st, event);
}
-
} else if (mPanelMayLongPress && mPanelChordingKey == keyCode
&& (event.getFlags()&KeyEvent.FLAG_LONG_PRESS) != 0) {
// We have had a long press while in a state where this
@@ -643,25 +642,40 @@
}
boolean playSoundEffect = false;
- PanelFeatureState st = getPanelState(featureId, true);
- if (st.isOpen || st.isHandled) {
+ final PanelFeatureState st = getPanelState(featureId, true);
+ if (featureId == FEATURE_OPTIONS_PANEL && mActionBar != null) {
+ if (mActionBar.isOverflowReserved()) {
+ if (!mActionBar.isOverflowMenuShowing()) {
+ final Callback cb = getCallback();
+ if (cb != null) {
+ if (cb.onPreparePanel(featureId, st.createdPanelView, st.menu)) {
+ playSoundEffect = mActionBar.showOverflowMenu();
+ }
+ }
+ } else {
+ playSoundEffect = mActionBar.hideOverflowMenu();
+ }
+ }
+ } else {
+ if (st.isOpen || st.isHandled) {
- // Play the sound effect if the user closed an open menu (and not if
- // they just released a menu shortcut)
- playSoundEffect = st.isOpen;
+ // Play the sound effect if the user closed an open menu (and not if
+ // they just released a menu shortcut)
+ playSoundEffect = st.isOpen;
- // Close menu
- closePanel(st, true);
+ // Close menu
+ closePanel(st, true);
- } else if (st.isPrepared) {
+ } else if (st.isPrepared) {
- // Write 'menu opened' to event log
- EventLog.writeEvent(50001, 0);
+ // Write 'menu opened' to event log
+ EventLog.writeEvent(50001, 0);
- // Show menu
- openPanel(st, event);
+ // Show menu
+ openPanel(st, event);
- playSoundEffect = true;
+ playSoundEffect = true;
+ }
}
if (playSoundEffect) {
@@ -841,6 +855,21 @@
}
private void reopenMenu(boolean toggleMenuMode) {
+ if (mActionBar != null) {
+ if (!mActionBar.isOverflowMenuShowing() || !toggleMenuMode) {
+ final Callback cb = getCallback();
+ if (cb != null) {
+ final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
+ if (cb.onPreparePanel(FEATURE_OPTIONS_PANEL, st.createdPanelView, st.menu)) {
+ mActionBar.showOverflowMenu();
+ }
+ }
+ } else {
+ mActionBar.hideOverflowMenu();
+ }
+ return;
+ }
+
PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
// Save the future expanded mode state since closePanel will reset it
@@ -1387,12 +1416,8 @@
}
case KeyEvent.KEYCODE_MENU: {
- if (mActionBar != null && mActionBar.isOverflowReserved()) {
- mActionBar.showOverflowMenu();
- } else {
- onKeyUpPanel(featureId < 0 ? FEATURE_OPTIONS_PANEL : featureId,
- event);
- }
+ onKeyUpPanel(featureId < 0 ? FEATURE_OPTIONS_PANEL : featureId,
+ event);
return true;
}
@@ -2247,6 +2272,10 @@
requestFeature(FEATURE_ACTION_BAR);
}
+ if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionBarOverlay, false)) {
+ requestFeature(FEATURE_ACTION_BAR_OVERLAY);
+ }
+
if (a.getBoolean(com.android.internal.R.styleable.Window_windowActionModeOverlay, false)) {
requestFeature(FEATURE_ACTION_MODE_OVERLAY);
}
@@ -2333,7 +2362,11 @@
if (mIsFloating) {
layoutResource = com.android.internal.R.layout.dialog_title;
} else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
- layoutResource = com.android.internal.R.layout.screen_action_bar;
+ if ((features & (1 << FEATURE_ACTION_BAR_OVERLAY)) != 0) {
+ layoutResource = com.android.internal.R.layout.screen_action_bar_overlay;
+ } else {
+ layoutResource = com.android.internal.R.layout.screen_action_bar;
+ }
} else {
layoutResource = com.android.internal.R.layout.screen_title;
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index cb7fe06..a07c385 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -37,6 +37,7 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.LocalPowerManager;
+import android.os.Looper;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -48,15 +49,20 @@
import com.android.internal.policy.PolicyManager;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.telephony.ITelephony;
+import com.android.internal.view.BaseInputHandler;
import com.android.internal.widget.PointerLocationView;
import android.util.Config;
import android.util.EventLog;
import android.util.Log;
+import android.util.Slog;
import android.view.Display;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.IWindowManager;
+import android.view.InputChannel;
+import android.view.InputQueue;
+import android.view.InputHandler;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.WindowOrientationListener;
@@ -221,6 +227,17 @@
int mPointerLocationMode = 0;
PointerLocationView mPointerLocationView = null;
+ InputChannel mPointerLocationInputChannel;
+
+ private final InputHandler mPointerLocationInputHandler = new BaseInputHandler() {
+ @Override
+ public void handleMotion(MotionEvent event, Runnable finishedCallback) {
+ finishedCallback.run();
+ synchronized (mLock) {
+ mPointerLocationView.addTouchEvent(event);
+ }
+ }
+ };
// The current size of the screen.
int mW, mH;
@@ -617,8 +634,26 @@
WindowManagerImpl wm = (WindowManagerImpl)
mContext.getSystemService(Context.WINDOW_SERVICE);
wm.addView(addView, lp);
+
+ if (mPointerLocationInputChannel == null) {
+ try {
+ mPointerLocationInputChannel =
+ mWindowManager.monitorInput("PointerLocationView");
+ InputQueue.registerInputChannel(mPointerLocationInputChannel,
+ mPointerLocationInputHandler, mHandler.getLooper().getQueue());
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Could not set up input monitoring channel for PointerLocation.",
+ ex);
+ }
+ }
}
if (removeView != null) {
+ if (mPointerLocationInputChannel != null) {
+ InputQueue.unregisterInputChannel(mPointerLocationInputChannel);
+ mPointerLocationInputChannel.dispose();
+ mPointerLocationInputChannel = null;
+ }
+
WindowManagerImpl wm = (WindowManagerImpl)
mContext.getSystemService(Context.WINDOW_SERVICE);
wm.removeView(removeView);
@@ -732,20 +767,6 @@
: Configuration.KEYBOARDHIDDEN_YES;
}
- public void dispatchedPointerEventLw(MotionEvent ev, int targetX, int targetY) {
- if (mPointerLocationView == null) {
- return;
- }
- synchronized (mLock) {
- if (mPointerLocationView == null) {
- return;
- }
- ev.offsetLocation(targetX, targetY);
- mPointerLocationView.addTouchEvent(ev);
- ev.offsetLocation(-targetX, -targetY);
- }
- }
-
/** {@inheritDoc} */
public int windowTypeToLayerLw(int type) {
if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index 9195123..c2c799b 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -75,7 +75,8 @@
int sw);
private static native boolean nativeHasKeys(int deviceId, int sourceMask,
int[] keyCodes, boolean[] keyExists);
- private static native void nativeRegisterInputChannel(InputChannel inputChannel);
+ private static native void nativeRegisterInputChannel(InputChannel inputChannel,
+ boolean monitor);
private static native void nativeUnregisterInputChannel(InputChannel inputChannel);
private static native int nativeInjectInputEvent(InputEvent event,
int injectorPid, int injectorUid, int syncMode, int timeoutMillis);
@@ -225,14 +226,38 @@
return nativeHasKeys(deviceId, sourceMask, keyCodes, keyExists);
}
+ /**
+ * Creates an input channel that will receive all input from the input dispatcher.
+ * @param inputChannelName The input channel name.
+ * @return The input channel.
+ */
+ public InputChannel monitorInput(String inputChannelName) {
+ if (inputChannelName == null) {
+ throw new IllegalArgumentException("inputChannelName must not be null.");
+ }
+
+ InputChannel[] inputChannels = InputChannel.openInputChannelPair(inputChannelName);
+ nativeRegisterInputChannel(inputChannels[0], true);
+ inputChannels[0].dispose(); // don't need to retain the Java object reference
+ return inputChannels[1];
+ }
+
+ /**
+ * Registers an input channel so that it can be used as an input event target.
+ * @param inputChannel The input channel to register.
+ */
public void registerInputChannel(InputChannel inputChannel) {
if (inputChannel == null) {
throw new IllegalArgumentException("inputChannel must not be null.");
}
- nativeRegisterInputChannel(inputChannel);
+ nativeRegisterInputChannel(inputChannel, false);
}
+ /**
+ * Unregisters an input channel.
+ * @param inputChannel The input channel to unregister.
+ */
public void unregisterInputChannel(InputChannel inputChannel) {
if (inputChannel == null) {
throw new IllegalArgumentException("inputChannel must not be null.");
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index e4ef09c..3f5888b 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -62,10 +62,14 @@
import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
+import android.graphics.Canvas;
import android.graphics.Matrix;
+import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Region;
+import android.graphics.Typeface;
+import android.graphics.Paint.FontMetricsInt;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Bundle;
@@ -92,6 +96,7 @@
import android.util.Log;
import android.util.Slog;
import android.util.SparseIntArray;
+import android.util.TypedValue;
import android.view.Display;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
@@ -115,6 +120,7 @@
import android.view.WindowManager;
import android.view.WindowManagerImpl;
import android.view.WindowManagerPolicy;
+import android.view.Surface.OutOfResourcesException;
import android.view.WindowManager.LayoutParams;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
@@ -369,6 +375,7 @@
private DimAnimator mDimAnimator = null;
Surface mBlurSurface;
boolean mBlurShown;
+ Watermark mWatermark;
int mTransactionSequence = 0;
@@ -4373,11 +4380,19 @@
}
return mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD, sw);
}
-
+
public boolean hasKeys(int[] keycodes, boolean[] keyExists) {
return mInputManager.hasKeys(-1, InputDevice.SOURCE_ANY, keycodes, keyExists);
}
+ public InputChannel monitorInput(String inputChannelName) {
+ if (!checkCallingPermission(android.Manifest.permission.READ_INPUT_STATE,
+ "monitorInput()")) {
+ throw new SecurityException("Requires READ_INPUT_STATE permission");
+ }
+ return mInputManager.monitorInput(inputChannelName);
+ }
+
public void enableScreenAfterBoot() {
synchronized(mWindowMap) {
if (mSystemBooted) {
@@ -8516,12 +8531,6 @@
updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
}
- if (mFxSession == null) {
- mFxSession = new SurfaceSession();
- }
-
- if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION");
-
// Initialize state of exiting tokens.
for (i=mExitingTokens.size()-1; i>=0; i--) {
mExitingTokens.get(i).hasVisible = false;
@@ -8538,8 +8547,24 @@
float buttonBrightness = -1;
boolean focusDisplayed = false;
boolean animating = false;
+ boolean createWatermark = false;
+
+ if (mFxSession == null) {
+ mFxSession = new SurfaceSession();
+ createWatermark = true;
+ }
+
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION");
Surface.openTransaction();
+
+ if (createWatermark) {
+ createWatermark();
+ }
+ if (mWatermark != null) {
+ mWatermark.positionSurface(dw, dh);
+ }
+
try {
boolean wallpaperForceHidingChanged = false;
int repeats = 0;
@@ -10042,6 +10067,93 @@
mScreenFrozenLock.release();
}
+ static int getPropertyInt(String name, int defUnits, int defDps, DisplayMetrics dm) {
+ String str = SystemProperties.get(name);
+ try {
+ int val = Integer.parseInt(str);
+ return val;
+ } catch (Exception e) {
+ }
+ if (defUnits == TypedValue.COMPLEX_UNIT_PX) {
+ return defDps;
+ }
+ int val = (int)TypedValue.applyDimension(defUnits, defDps, dm);
+ return val;
+ }
+
+ class Watermark {
+ Surface mSurface;
+ int mWidth;
+ int mHeight;
+ int mXPercent;
+ int mYPercent;
+
+ Watermark(SurfaceSession session, String text) {
+ final DisplayMetrics dm = new DisplayMetrics();
+ mDisplay.getMetrics(dm);
+
+ int fontSize = getPropertyInt("ro.watermark.height",
+ TypedValue.COMPLEX_UNIT_DIP, 48, dm);
+ mXPercent = getPropertyInt("ro.watermark.x",
+ TypedValue.COMPLEX_UNIT_PX, 50, dm);
+ mYPercent = getPropertyInt("ro.watermark.y",
+ TypedValue.COMPLEX_UNIT_PX, 99, dm);
+ int color = getPropertyInt("ro.watermark.color",
+ TypedValue.COMPLEX_UNIT_PX, 0x80ffffff, dm);
+ int shadowRadius = getPropertyInt("ro.watermark.shadow.radius",
+ TypedValue.COMPLEX_UNIT_PX, 5, dm);
+ int shadowDx = getPropertyInt("ro.watermark.shadow.dx",
+ TypedValue.COMPLEX_UNIT_PX, 0, dm);
+ int shadowDy = getPropertyInt("ro.watermark.shadow.dy",
+ TypedValue.COMPLEX_UNIT_PX, 0, dm);
+ int shadowColor = getPropertyInt("ro.watermark.shadow.color",
+ TypedValue.COMPLEX_UNIT_PX, 0xff000000, dm);
+
+ Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ paint.setTextSize(fontSize);
+ paint.setColor(color);
+ paint.setShadowLayer(shadowRadius, shadowDx, shadowDy, shadowColor);
+ paint.setTypeface(Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD));
+
+ FontMetricsInt fm = paint.getFontMetricsInt();
+ mHeight = fm.descent - fm.ascent + 20;
+ mWidth = (int)paint.measureText(text) + 20;
+
+ try {
+ mSurface = new Surface(session, 0,
+ "WatermarkSurface",
+ -1, mWidth, mHeight, PixelFormat.TRANSLUCENT, 0);
+ mSurface.setLayer(TYPE_LAYER_MULTIPLIER*100);
+ Rect dirty = new Rect(0, 0, mWidth, mHeight);
+ Canvas c = mSurface.lockCanvas(dirty);
+ c.drawText(text, 10, -fm.ascent+10, paint);
+ mSurface.unlockCanvasAndPost(c);
+ mSurface.show();
+ } catch (OutOfResourcesException e) {
+ }
+ }
+
+ void positionSurface(int dw, int dh) {
+ int availW = dw - mWidth;
+ int availH = dh - mHeight;
+ mSurface.setPosition((availW*mXPercent)/100,
+ (availH*mYPercent)/100);
+ }
+ }
+
+ void createWatermark() {
+ if (mWatermark != null) {
+ return;
+ }
+
+ String text = SystemProperties.get("ro.watermark.text");
+ if (text == null || text.length() <= 0) {
+ return;
+ }
+
+ mWatermark = new Watermark(mFxSession, text);
+ }
+
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index a32cd4c..df930ad 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3578,6 +3578,7 @@
if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
// Tell anyone interested that we are done booting!
+ SystemProperties.set("sys.boot_completed", "1");
broadcastIntentLocked(null, null,
new Intent(Intent.ACTION_BOOT_COMPLETED, null),
null, null, 0, null, null,
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 0982b32..ebe71ab 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -213,7 +213,7 @@
void setDisplayOrientation(int32_t displayId, int32_t orientation);
status_t registerInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel,
- jweak inputChannelObjWeak);
+ jweak inputChannelObjWeak, bool monitor);
status_t unregisterInputChannel(JNIEnv* env, const sp<InputChannel>& inputChannel);
void setInputWindows(JNIEnv* env, jobjectArray windowObjArray);
@@ -334,6 +334,7 @@
bool mWindowsReady;
Vector<InputWindow> mWindows;
Vector<InputWindow*> mWallpaperWindows;
+ Vector<sp<InputChannel> > mMonitoringChannels;
// Focus tracking for keys, trackball, etc.
InputWindow* mFocusedWindow;
@@ -382,6 +383,10 @@
static void addTarget(const InputWindow* window, int32_t targetFlags,
nsecs_t timeSpentWaitingForApplication, Vector<InputTarget>& outTargets);
+ void registerMonitoringChannel(const sp<InputChannel>& inputChannel);
+ void unregisterMonitoringChannel(const sp<InputChannel>& inputChannel);
+ void addMonitoringTargetsLd(Vector<InputTarget>& outTargets);
+
static inline JNIEnv* jniEnv() {
return AndroidRuntime::getJNIEnv();
}
@@ -492,7 +497,7 @@
}
status_t NativeInputManager::registerInputChannel(JNIEnv* env,
- const sp<InputChannel>& inputChannel, jobject inputChannelObj) {
+ const sp<InputChannel>& inputChannel, jobject inputChannelObj, bool monitor) {
jweak inputChannelObjWeak = env->NewWeakGlobalRef(inputChannelObj);
if (! inputChannelObjWeak) {
LOGE("Could not create weak reference for input channel.");
@@ -519,9 +524,14 @@
status = mInputManager->registerInputChannel(inputChannel);
if (! status) {
+ // Success.
+ if (monitor) {
+ registerMonitoringChannel(inputChannel);
+ }
return OK;
}
+ // Failed!
{
AutoMutex _l(mInputChannelRegistryLock);
mInputChannelObjWeakByReceiveFd.removeItem(inputChannel->getReceivePipeFd());
@@ -552,6 +562,8 @@
env->DeleteWeakGlobalRef(inputChannelObjWeak);
+ unregisterMonitoringChannel(inputChannel);
+
return mInputManager->unregisterInputChannel(inputChannel);
}
@@ -829,6 +841,8 @@
env->DeleteLocalRef(inputChannelObjLocal);
}
+
+ unregisterMonitoringChannel(inputChannel);
}
bool NativeInputManager::notifyInputChannelANR(const sp<InputChannel>& inputChannel,
@@ -1429,7 +1443,9 @@
// If there is no currently touched window then fail.
if (! mTouchedWindow) {
- LOGW("Dropping event because there is no touched window to receive it.");
+#if DEBUG_INPUT_DISPATCHER_POLICY
+ LOGD("Dropping event because there is no touched window to receive it.");
+#endif
injectionResult = INPUT_EVENT_INJECTION_FAILED;
injectionPermission = INJECTION_PERMISSION_GRANTED;
break; // failed, exit wait loop
@@ -1587,6 +1603,8 @@
outTargets.clear();
return INPUT_EVENT_INJECTION_SUCCEEDED;
}
+
+ addMonitoringTargetsLd(outTargets);
}
pokeUserActivityIfNeeded(windowType, POWER_MANAGER_BUTTON_EVENT);
@@ -1631,6 +1649,8 @@
}
windowType = focusedWindow->layoutParamsType;
+
+ addMonitoringTargetsLd(outTargets);
} // release lock
pokeUserActivityIfNeeded(windowType, POWER_MANAGER_BUTTON_EVENT);
@@ -1657,6 +1677,8 @@
}
windowType = touchedWindow->layoutParamsType;
+
+ addMonitoringTargetsLd(outTargets);
} // release lock
int32_t eventType;
@@ -1714,6 +1736,39 @@
android_server_PowerManagerService_userActivity(eventTime, eventType);
}
+void NativeInputManager::registerMonitoringChannel(const sp<InputChannel>& inputChannel) {
+ { // acquire lock
+ AutoMutex _l(mDispatchLock);
+ mMonitoringChannels.push(inputChannel);
+ } // release lock
+}
+
+void NativeInputManager::unregisterMonitoringChannel(const sp<InputChannel>& inputChannel) {
+ { // acquire lock
+ AutoMutex _l(mDispatchLock);
+
+ for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
+ if (mMonitoringChannels[i] == inputChannel) {
+ mMonitoringChannels.removeAt(i);
+ break;
+ }
+ }
+ } // release lock
+}
+
+void NativeInputManager::addMonitoringTargetsLd(Vector<InputTarget>& outTargets) {
+ for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
+ outTargets.push();
+
+ InputTarget& target = outTargets.editTop();
+ target.inputChannel = mMonitoringChannels[i];
+ target.flags = 0;
+ target.timeout = -1;
+ target.xOffset = 0;
+ target.yOffset = 0;
+ }
+}
+
static void dumpMotionRange(String8& dump,
const char* name, const InputDeviceInfo::MotionRange* range) {
if (range) {
@@ -1805,6 +1860,11 @@
mWindows[i].ownerPid, mWindows[i].ownerUid,
mWindows[i].dispatchingTimeout / 1000000.0);
}
+
+ for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
+ dump.appendFormat(" monitoringChannel[%d]: '%s'\n",
+ i, mMonitoringChannels[i]->getName().string());
+ }
}
// ----------------------------------------------------------------------------
@@ -2012,7 +2072,7 @@
}
static void android_server_InputManager_nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
- jobject inputChannelObj) {
+ jobject inputChannelObj, jboolean monitor) {
if (checkInputManagerUnitialized(env)) {
return;
}
@@ -2026,15 +2086,17 @@
status_t status = gNativeInputManager->registerInputChannel(
- env, inputChannel, inputChannelObj);
+ env, inputChannel, inputChannelObj, monitor);
if (status) {
jniThrowRuntimeException(env, "Failed to register input channel. "
"Check logs for details.");
return;
}
- android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
- android_server_InputManager_handleInputChannelDisposed, NULL);
+ if (! monitor) {
+ android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
+ android_server_InputManager_handleInputChannelDisposed, NULL);
+ }
}
static void android_server_InputManager_nativeUnregisterInputChannel(JNIEnv* env, jclass clazz,
@@ -2149,7 +2211,7 @@
(void*) android_server_InputManager_nativeGetSwitchState },
{ "nativeHasKeys", "(II[I[Z)Z",
(void*) android_server_InputManager_nativeHasKeys },
- { "nativeRegisterInputChannel", "(Landroid/view/InputChannel;)V",
+ { "nativeRegisterInputChannel", "(Landroid/view/InputChannel;Z)V",
(void*) android_server_InputManager_nativeRegisterInputChannel },
{ "nativeUnregisterInputChannel", "(Landroid/view/InputChannel;)V",
(void*) android_server_InputManager_nativeUnregisterInputChannel },
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index a14bfb5..79772ed 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -5,6 +5,7 @@
clz.cpp.arm \
DisplayHardware/DisplayHardware.cpp \
DisplayHardware/DisplayHardwareBase.cpp \
+ DisplayHardware/HWComposer.cpp \
BlurFilter.cpp.arm \
GLExtensions.cpp \
Layer.cpp \
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 2eac0a8..166c528 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -36,11 +36,11 @@
#include "DisplayHardware/DisplayHardware.h"
-#include <hardware/copybit.h>
#include <hardware/overlay.h>
#include <hardware/gralloc.h>
#include "GLExtensions.h"
+#include "HWComposer.h"
using namespace android;
@@ -76,7 +76,7 @@
const sp<SurfaceFlinger>& flinger,
uint32_t dpy)
: DisplayHardwareBase(flinger, dpy),
- mFlags(0)
+ mFlags(0), mHwc(0)
{
init(dpy);
}
@@ -262,6 +262,17 @@
// Unbind the context from this thread
eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+
+
+ // initialize the H/W composer
+ mHwc = new HWComposer();
+ if (mHwc->initCheck() == NO_ERROR) {
+ mHwc->setFrameBuffer(mDisplay, mSurface);
+ }
+}
+
+HWComposer& DisplayHardware::getHwComposer() const {
+ return *mHwc;
}
/*
@@ -317,7 +328,12 @@
}
mPageFlipCount++;
- eglSwapBuffers(dpy, surface);
+
+ if (mHwc->initCheck() == NO_ERROR) {
+ mHwc->commit();
+ } else {
+ eglSwapBuffers(dpy, surface);
+ }
checkEGLErrors("eglSwapBuffers");
// for debugging
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index 66bf521..f2cfd2d 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -34,12 +34,11 @@
#include "DisplayHardware/DisplayHardwareBase.h"
struct overlay_control_device_t;
-struct framebuffer_device_t;
-struct copybit_image_t;
namespace android {
class FramebufferNativeWindow;
+class HWComposer;
class DisplayHardware : public DisplayHardwareBase
{
@@ -80,6 +79,9 @@
uint32_t getPageFlipCount() const;
EGLDisplay getEGLDisplay() const { return mDisplay; }
overlay_control_device_t* getOverlayEngine() const { return mOverlayEngine; }
+
+ // Hardware Composer
+ HWComposer& getHwComposer() const;
status_t compositionComplete() const;
@@ -107,6 +109,8 @@
GLint mMaxViewportDims;
GLint mMaxTextureSize;
+ HWComposer* mHwc;
+
sp<FramebufferNativeWindow> mNativeWindow;
overlay_control_device_t* mOverlayEngine;
};
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
new file mode 100644
index 0000000..8ca880b
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include <hardware/hardware.h>
+
+#include <cutils/log.h>
+
+#include <EGL/egl.h>
+
+#include "HWComposer.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+HWComposer::HWComposer()
+ : mModule(0), mHwc(0), mList(0),
+ mDpy(EGL_NO_DISPLAY), mSur(EGL_NO_SURFACE)
+{
+ int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);
+ LOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID);
+ if (err == 0) {
+ err = hwc_open(mModule, &mHwc);
+ LOGE_IF(err, "%s device failed to initialize (%s)",
+ HWC_HARDWARE_COMPOSER, strerror(-err));
+ }
+}
+
+HWComposer::~HWComposer() {
+ free(mList);
+ if (mHwc) {
+ hwc_close(mHwc);
+ }
+}
+
+status_t HWComposer::initCheck() const {
+ return mHwc ? NO_ERROR : NO_INIT;
+}
+
+void HWComposer::setFrameBuffer(EGLDisplay dpy, EGLSurface sur) {
+ mDpy = (hwc_display_t)dpy;
+ mSur = (hwc_surface_t)sur;
+}
+
+status_t HWComposer::createWorkList(size_t numLayers) {
+ if (mHwc && (!mList || mList->numHwLayers < numLayers)) {
+ free(mList);
+ size_t size = sizeof(hwc_layer_list) + numLayers*sizeof(hwc_layer_t);
+ mList = (hwc_layer_list_t*)malloc(size);
+ mList->flags = HWC_GEOMETRY_CHANGED;
+ mList->numHwLayers = numLayers;
+ }
+ return NO_ERROR;
+}
+
+status_t HWComposer::prepare() const {
+ int err = mHwc->prepare(mHwc, mList);
+ return (status_t)err;
+}
+
+status_t HWComposer::commit() const {
+ int err = mHwc->set(mHwc, mDpy, mSur, mList);
+ mList->flags &= ~HWC_GEOMETRY_CHANGED;
+ return (status_t)err;
+}
+
+HWComposer::iterator HWComposer::begin() {
+ return mList ? &(mList->hwLayers[0]) : NULL;
+}
+
+HWComposer::iterator HWComposer::end() {
+ return mList ? &(mList->hwLayers[mList->numHwLayers]) : NULL;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
new file mode 100644
index 0000000..729f23b
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ANDROID_SF_HWCOMPOSER_H
+#define ANDROID_SF_HWCOMPOSER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <EGL/egl.h>
+
+#include <hardware/hwcomposer.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class HWComposer
+{
+public:
+
+ HWComposer();
+ ~HWComposer();
+
+ status_t initCheck() const;
+
+ // tells the HAL what the framebuffer is
+ void setFrameBuffer(EGLDisplay dpy, EGLSurface sur);
+
+ // create a work list for numLayers layer
+ status_t createWorkList(size_t numLayers);
+
+ // Asks the HAL what it can do
+ status_t prepare() const;
+
+ // commits the list
+ status_t commit() const;
+
+
+ typedef hwc_layer_t const * const_iterator;
+ typedef hwc_layer_t* iterator;
+
+ iterator begin();
+ iterator end();
+
+private:
+ hw_module_t const* mModule;
+ hwc_composer_device_t* mHwc;
+ hwc_layer_list_t* mList;
+ hwc_display_t mDpy;
+ hwc_surface_t mSur;
+};
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SF_HWCOMPOSER_H
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 629d993..3720e1669 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -35,6 +35,7 @@
#include "Layer.h"
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
+#include "DisplayHardware/HWComposer.h"
#define DEBUG_RESIZE 0
@@ -177,6 +178,62 @@
return NO_ERROR;
}
+void Layer::setGeometry(hwc_layer_t* hwcl)
+{
+ hwcl->compositionType = HWC_FRAMEBUFFER;
+ hwcl->hints = 0;
+ hwcl->flags = 0;
+ hwcl->transform = 0;
+ hwcl->blending = HWC_BLENDING_NONE;
+
+ // we can't do alpha-fade with the hwc HAL
+ const State& s(drawingState());
+ if (s.alpha < 0xFF) {
+ hwcl->flags = HWC_SKIP_LAYER;
+ return;
+ }
+
+ // we can only handle simple transformation
+ if (mOrientation & Transform::ROT_INVALID) {
+ hwcl->flags = HWC_SKIP_LAYER;
+ return;
+ }
+
+ hwcl->transform = mOrientation;
+
+ if (needsBlending()) {
+ hwcl->blending = mPremultipliedAlpha ?
+ HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
+ }
+
+ hwcl->displayFrame.left = mTransformedBounds.left;
+ hwcl->displayFrame.top = mTransformedBounds.top;
+ hwcl->displayFrame.right = mTransformedBounds.right;
+ hwcl->displayFrame.bottom = mTransformedBounds.bottom;
+
+ hwcl->visibleRegionScreen.rects =
+ reinterpret_cast<hwc_rect_t const *>(
+ visibleRegionScreen.getArray(
+ &hwcl->visibleRegionScreen.numRects));
+}
+
+void Layer::setPerFrameData(hwc_layer_t* hwcl) {
+ sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
+ if (buffer == NULL) {
+ // this situation can happen if we ran out of memory for instance.
+ // not much we can do. continue to use whatever texture was bound
+ // to this context.
+ hwcl->handle = NULL;
+ return;
+ }
+ hwcl->handle = const_cast<native_handle_t*>(buffer->handle);
+ // TODO: set the crop value properly
+ hwcl->sourceCrop.left = 0;
+ hwcl->sourceCrop.top = 0;
+ hwcl->sourceCrop.right = buffer->width;
+ hwcl->sourceCrop.bottom = buffer->height;
+}
+
void Layer::reloadTexture(const Region& dirty)
{
sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index e1d283b..188da6a 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -68,6 +68,8 @@
bool isFixedSize() const;
// LayerBase interface
+ virtual void setGeometry(hwc_layer_t* hwcl);
+ virtual void setPerFrameData(hwc_layer_t* hwcl);
virtual void onDraw(const Region& clip) const;
virtual uint32_t doTransaction(uint32_t transactionFlags);
virtual void lockPageFlip(bool& recomputeVisibleRegions);
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index d5aa53f..043d54d 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -39,8 +39,11 @@
// ---------------------------------------------------------------------------
+int32_t LayerBase::sSequence = 1;
+
LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
: dpy(display), contentDirty(false),
+ sequence(uint32_t(android_atomic_inc(&sSequence))),
mFlinger(flinger),
mNeedsFiltering(false),
mOrientation(0),
@@ -304,22 +307,17 @@
}
}
-void LayerBase::draw(const Region& inClip) const
+void LayerBase::setGeometry(hwc_layer_t* hwcl) {
+ hwcl->flags |= HWC_SKIP_LAYER;
+}
+
+void LayerBase::setPerFrameData(hwc_layer_t* hwcl) {
+ hwcl->compositionType = HWC_FRAMEBUFFER;
+ hwcl->handle = NULL;
+}
+
+void LayerBase::draw(const Region& clip) const
{
- // invalidate the region we'll update
- Region clip(inClip); // copy-on-write, so no-op most of the time
-
- // Remove the transparent area from the clipping region
- const State& s = drawingState();
- if (LIKELY(!s.transparentRegion.isEmpty())) {
- clip.subtract(transparentRegionScreen);
- if (clip.isEmpty()) {
- // usually this won't happen because this should be taken care of
- // by SurfaceFlinger::computeVisibleRegions()
- return;
- }
- }
-
// reset GL state
glEnable(GL_SCISSOR_TEST);
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 4288cf7..dd1cd05 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -35,6 +35,8 @@
#include <pixelflinger/pixelflinger.h>
+#include <hardware/hwcomposer.h>
+
#include "Transform.h"
namespace android {
@@ -53,6 +55,8 @@
class LayerBase : public RefBase
{
+ static int32_t sSequence;
+
public:
LayerBase(SurfaceFlinger* flinger, DisplayID display);
@@ -61,6 +65,7 @@
Region visibleRegionScreen;
Region transparentRegionScreen;
Region coveredRegionScreen;
+ int32_t sequence;
struct State {
uint32_t w;
@@ -105,6 +110,10 @@
virtual const char* getTypeId() const { return "LayerBase"; }
+ virtual void setGeometry(hwc_layer_t* hwcl);
+
+ virtual void setPerFrameData(hwc_layer_t* hwcl);
+
/**
* draw - performs some global clipping optimizations
* and calls onDraw().
@@ -210,12 +219,6 @@
inline const State& currentState() const { return mCurrentState; }
inline State& currentState() { return mCurrentState; }
- static int compareCurrentStateZ(
- sp<LayerBase> const * layerA,
- sp<LayerBase> const * layerB) {
- return layerA[0]->currentState().z - layerB[0]->currentState().z;
- }
-
int32_t getOrientation() const { return mOrientation; }
int tx() const { return mLeft; }
int ty() const { return mTop; }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3167c4c..47bb4c1 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -52,6 +52,7 @@
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
+#include "DisplayHardware/HWComposer.h"
/* ideally AID_GRAPHICS would be in a semi-public header
* or there would be a way to map a user/group name to its id
@@ -65,95 +66,6 @@
namespace android {
// ---------------------------------------------------------------------------
-SurfaceFlinger::LayerVector::LayerVector(const SurfaceFlinger::LayerVector& rhs)
- : lookup(rhs.lookup), layers(rhs.layers)
-{
-}
-
-ssize_t SurfaceFlinger::LayerVector::indexOf(
- const sp<LayerBase>& key, size_t guess) const
-{
- if (guess<size() && lookup.keyAt(guess) == key)
- return guess;
- const ssize_t i = lookup.indexOfKey(key);
- if (i>=0) {
- const size_t idx = lookup.valueAt(i);
- LOGE_IF(layers[idx]!=key,
- "LayerVector[%p]: layers[%d]=%p, key=%p",
- this, int(idx), layers[idx].get(), key.get());
- return idx;
- }
- return i;
-}
-
-ssize_t SurfaceFlinger::LayerVector::add(
- const sp<LayerBase>& layer,
- Vector< sp<LayerBase> >::compar_t cmp)
-{
- size_t count = layers.size();
- ssize_t l = 0;
- ssize_t h = count-1;
- ssize_t mid;
- sp<LayerBase> const* a = layers.array();
- while (l <= h) {
- mid = l + (h - l)/2;
- const int c = cmp(a+mid, &layer);
- if (c == 0) { l = mid; break; }
- else if (c<0) { l = mid+1; }
- else { h = mid-1; }
- }
- size_t order = l;
- while (order<count && !cmp(&layer, a+order)) {
- order++;
- }
- count = lookup.size();
- for (size_t i=0 ; i<count ; i++) {
- if (lookup.valueAt(i) >= order) {
- lookup.editValueAt(i)++;
- }
- }
- layers.insertAt(layer, order);
- lookup.add(layer, order);
- return order;
-}
-
-ssize_t SurfaceFlinger::LayerVector::remove(const sp<LayerBase>& layer)
-{
- const ssize_t keyIndex = lookup.indexOfKey(layer);
- if (keyIndex >= 0) {
- const size_t index = lookup.valueAt(keyIndex);
- LOGE_IF(layers[index]!=layer,
- "LayerVector[%p]: layers[%u]=%p, layer=%p",
- this, int(index), layers[index].get(), layer.get());
- layers.removeItemsAt(index);
- lookup.removeItemsAt(keyIndex);
- const size_t count = lookup.size();
- for (size_t i=0 ; i<count ; i++) {
- if (lookup.valueAt(i) >= size_t(index)) {
- lookup.editValueAt(i)--;
- }
- }
- return index;
- }
- return NAME_NOT_FOUND;
-}
-
-ssize_t SurfaceFlinger::LayerVector::reorder(
- const sp<LayerBase>& layer,
- Vector< sp<LayerBase> >::compar_t cmp)
-{
- // XXX: it's a little lame. but oh well...
- ssize_t err = remove(layer);
- if (err >=0)
- err = add(layer, cmp);
- return err;
-}
-
-// ---------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(), Thread(false),
mTransactionFlags(0),
@@ -165,6 +77,7 @@
mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"),
mDump("android.permission.DUMP"),
mVisibleRegionsDirty(false),
+ mHwWorkListDirty(false),
mDeferReleaseConsole(false),
mFreezeDisplay(false),
mFreezeCount(0),
@@ -457,6 +370,11 @@
// post surfaces (if needed)
handlePageFlip();
+ if (UNLIKELY(mHwWorkListDirty)) {
+ // build the h/w work list
+ handleWorkList();
+ }
+
const DisplayHardware& hw(graphicPlane(0).displayHardware());
if (LIKELY(hw.canDraw() && !isFrozen())) {
// repaint the framebuffer (if needed)
@@ -521,6 +439,10 @@
{
Vector< sp<LayerBase> > ditchedLayers;
+ /*
+ * Perform and commit the transaction
+ */
+
{ // scope for the lock
Mutex::Autolock _l(mStateLock);
const nsecs_t now = systemTime();
@@ -528,9 +450,15 @@
handleTransactionLocked(transactionFlags, ditchedLayers);
mLastTransactionTime = systemTime() - now;
mDebugInTransaction = 0;
+ mHwWorkListDirty = true;
+ // here the transaction has been committed
}
- // do this without lock held
+ /*
+ * Clean-up all layers that went away
+ * (do this without the lock held)
+ */
+
const size_t count = ditchedLayers.size();
for (size_t i=0 ; i<count ; i++) {
if (ditchedLayers[i] != 0) {
@@ -764,8 +692,8 @@
void SurfaceFlinger::handlePageFlip()
{
bool visibleRegions = mVisibleRegionsDirty;
- LayerVector& currentLayers = const_cast<LayerVector&>(
- mDrawingState.layersSortedByZ);
+ LayerVector& currentLayers(
+ const_cast<LayerVector&>(mDrawingState.layersSortedByZ));
visibleRegions |= lockPageFlip(currentLayers);
const DisplayHardware& hw = graphicPlane(0).displayHardware();
@@ -773,8 +701,22 @@
if (visibleRegions) {
Region opaqueRegion;
computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion);
+
+ /*
+ * rebuild the visible layer list
+ */
+ mVisibleLayersSortedByZ.clear();
+ const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
+ size_t count = currentLayers.size();
+ mVisibleLayersSortedByZ.setCapacity(count);
+ for (size_t i=0 ; i<count ; i++) {
+ if (!currentLayers[i]->visibleRegionScreen.isEmpty())
+ mVisibleLayersSortedByZ.add(currentLayers[i]);
+ }
+
mWormholeRegion = screenRegion.subtract(opaqueRegion);
mVisibleRegionsDirty = false;
+ mHwWorkListDirty = true;
}
unlockPageFlip(currentLayers);
@@ -805,6 +747,21 @@
}
}
+void SurfaceFlinger::handleWorkList()
+{
+ mHwWorkListDirty = false;
+ HWComposer& hwc(graphicPlane(0).displayHardware().getHwComposer());
+ if (hwc.initCheck() == NO_ERROR) {
+ const Vector< sp<LayerBase> >& currentLayers(mVisibleLayersSortedByZ);
+ const size_t count = currentLayers.size();
+ hwc.createWorkList(count);
+ HWComposer::iterator cur(hwc.begin());
+ HWComposer::iterator last(hwc.end());
+ for (size_t i=0 ; (i<count) && (cur!=last) ; ++i, ++cur) {
+ currentLayers[i]->setGeometry(cur);
+ }
+ }
+}
void SurfaceFlinger::handleRepaint()
{
@@ -869,18 +826,61 @@
// draw something...
drawWormhole();
}
- const SurfaceFlinger& flinger(*this);
- const LayerVector& drawingLayers(mDrawingState.layersSortedByZ);
- const size_t count = drawingLayers.size();
- sp<LayerBase> const* const layers = drawingLayers.array();
+
+ status_t err = NO_ERROR;
+ const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
+ const size_t count = layers.size();
+
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ HWComposer& hwc(hw.getHwComposer());
+ HWComposer::iterator cur(hwc.begin());
+ HWComposer::iterator last(hwc.end());
+
+ // update the per-frame h/w composer data for each layer
+ if (cur != last) {
+ for (size_t i=0 ; i<count && cur!=last ; ++i, ++cur) {
+ layers[i]->setPerFrameData(cur);
+ }
+ err = hwc.prepare();
+ LOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
+ }
+
+ // and then, render the layers targeted at the framebuffer
+ Region transparent(hw.bounds());
for (size_t i=0 ; i<count ; ++i) {
- const sp<LayerBase>& layer = layers[i];
- const Region& visibleRegion(layer->visibleRegionScreen);
- if (!visibleRegion.isEmpty()) {
- const Region clip(dirty.intersect(visibleRegion));
- if (!clip.isEmpty()) {
- layer->draw(clip);
+
+ // see if we need to skip this layer
+ if (!err && cur != last) {
+ if (!((cur->compositionType == HWC_FRAMEBUFFER) ||
+ (cur->flags & HWC_SKIP_LAYER))) {
+ ++cur;
+ continue;
}
+ ++cur;
+ }
+
+ // draw the layer into the framebuffer
+ const sp<LayerBase>& layer(layers[i]);
+ transparent.subtractSelf(layer->visibleRegionScreen);
+ const Region clip(dirty.intersect(layer->visibleRegionScreen));
+ if (!clip.isEmpty()) {
+ layer->draw(clip);
+ }
+ }
+
+ // finally clear everything we didn't draw as a result of calling
+ // prepare (this leaves the FB transparent).
+ transparent.andSelf(dirty);
+ if (!transparent.isEmpty()) {
+ glClearColor(0,0,0,0);
+ Region::const_iterator it = transparent.begin();
+ Region::const_iterator const end = transparent.end();
+ const int32_t height = hw.getHeight();
+ while (it != end) {
+ const Rect& r(*it++);
+ const GLint sy = height - (r.top + r.height());
+ glScissor(r.left, sy, r.width(), r.height());
+ glClear(GL_COLOR_BUFFER_BIT);
}
}
}
@@ -1029,8 +1029,7 @@
status_t SurfaceFlinger::addLayer_l(const sp<LayerBase>& layer)
{
- ssize_t i = mCurrentState.layersSortedByZ.add(
- layer, &LayerBase::compareCurrentStateZ);
+ ssize_t i = mCurrentState.layersSortedByZ.add(layer);
return (i < 0) ? status_t(i) : status_t(NO_ERROR);
}
@@ -1372,9 +1371,10 @@
flags |= eTraversalNeeded;
}
if (what & eLayerChanged) {
+ ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
if (layer->setLayer(s.z)) {
- mCurrentState.layersSortedByZ.reorder(
- layer, &Layer::compareCurrentStateZ);
+ mCurrentState.layersSortedByZ.removeAt(idx);
+ mCurrentState.layersSortedByZ.add(layer);
// we need traversal (state changed)
// AND transaction (list changed)
flags |= eTransactionNeeded|eTraversalNeeded;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 8821e5c..8e286e5 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -40,9 +40,6 @@
#include "MessageQueue.h"
-struct copybit_device_t;
-struct overlay_device_t;
-
namespace android {
// ---------------------------------------------------------------------------
@@ -246,21 +243,19 @@
status_t setClientState(const sp<Client>& client,
int32_t count, const layer_state_t* states);
-
- class LayerVector {
+ class LayerVector : public SortedVector< sp<LayerBase> > {
public:
- inline LayerVector() { }
- LayerVector(const LayerVector&);
- inline size_t size() const { return layers.size(); }
- inline sp<LayerBase> const* array() const { return layers.array(); }
- ssize_t add(const sp<LayerBase>&, Vector< sp<LayerBase> >::compar_t);
- ssize_t remove(const sp<LayerBase>&);
- ssize_t reorder(const sp<LayerBase>&, Vector< sp<LayerBase> >::compar_t);
- ssize_t indexOf(const sp<LayerBase>& key, size_t guess=0) const;
- inline sp<LayerBase> operator [] (size_t i) const { return layers[i]; }
- private:
- KeyedVector< sp<LayerBase> , size_t> lookup;
- Vector< sp<LayerBase> > layers;
+ LayerVector() { }
+ LayerVector(const LayerVector& rhs) : SortedVector< sp<LayerBase> >(rhs) { }
+ virtual int do_compare(const void* lhs, const void* rhs) const {
+ const sp<LayerBase>& l(*reinterpret_cast<const sp<LayerBase>*>(lhs));
+ const sp<LayerBase>& r(*reinterpret_cast<const sp<LayerBase>*>(rhs));
+ // sort layers by Z order
+ uint32_t lz = l->currentState().z;
+ uint32_t rz = r->currentState().z;
+ // then by sequence, so we get a stable ordering
+ return (lz != rz) ? (lz - rz) : (l->sequence - r->sequence);
+ }
};
struct State {
@@ -301,6 +296,7 @@
void handlePageFlip();
bool lockPageFlip(const LayerVector& currentLayers);
void unlockPageFlip(const LayerVector& currentLayers);
+ void handleWorkList();
void handleRepaint();
void postFramebuffer();
void composeSurfaces(const Region& dirty);
@@ -375,10 +371,13 @@
Region mInvalidRegion;
Region mWormholeRegion;
bool mVisibleRegionsDirty;
+ bool mHwWorkListDirty;
bool mDeferReleaseConsole;
bool mFreezeDisplay;
int32_t mFreezeCount;
nsecs_t mFreezeDisplayTime;
+ Vector< sp<LayerBase> > mVisibleLayersSortedByZ;
+
// don't use a lock for these, we don't care
int mDebugRegion;