Merge "Avoid caller NPE if callback null in AppOpsService"
diff --git a/api/current.txt b/api/current.txt
index dd22a40..1e99d56 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -41832,6 +41832,7 @@
method public abstract void setContentView(int);
method public abstract void setContentView(android.view.View);
method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+ method public abstract void setDecorCaptionShade(int);
method protected void setDefaultWindowFormat(int);
method public void setDimAmount(float);
method public void setElevation(float);
@@ -41852,6 +41853,8 @@
method public void setMediaController(android.media.session.MediaController);
method public abstract void setNavigationBarColor(int);
method public void setReenterTransition(android.transition.Transition);
+ method public abstract void setResizingCaptionDrawable(android.graphics.drawable.Drawable);
+ method public final void setRestrictedCaptionAreaListener(android.view.Window.RestrictedCaptionAreaListener);
method public void setReturnTransition(android.transition.Transition);
method public void setSharedElementEnterTransition(android.transition.Transition);
method public void setSharedElementExitTransition(android.transition.Transition);
@@ -41880,6 +41883,9 @@
method public abstract void takeKeyEvents(boolean);
method public abstract void takeSurface(android.view.SurfaceHolder.Callback2);
method public abstract void togglePanel(int, android.view.KeyEvent);
+ field public static final int DECOR_CAPTION_SHADE_AUTO = 0; // 0x0
+ field public static final int DECOR_CAPTION_SHADE_DARK = 2; // 0x2
+ field public static final int DECOR_CAPTION_SHADE_LIGHT = 1; // 0x1
field protected static final deprecated int DEFAULT_FEATURES = 65; // 0x41
field public static final int FEATURE_ACTION_BAR = 8; // 0x8
field public static final int FEATURE_ACTION_BAR_OVERLAY = 9; // 0x9
@@ -41934,6 +41940,10 @@
method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
}
+ public static abstract interface Window.RestrictedCaptionAreaListener {
+ method public abstract void onRestrictedCaptionAreaChanged(android.graphics.Rect);
+ }
+
public final class WindowAnimationFrameStats extends android.view.FrameStats implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index ee20e5b..8be751c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -44170,6 +44170,7 @@
method public abstract void setContentView(int);
method public abstract void setContentView(android.view.View);
method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+ method public abstract void setDecorCaptionShade(int);
method protected void setDefaultWindowFormat(int);
method public void setDimAmount(float);
method public void setDisableWallpaperTouchEvents(boolean);
@@ -44191,6 +44192,8 @@
method public void setMediaController(android.media.session.MediaController);
method public abstract void setNavigationBarColor(int);
method public void setReenterTransition(android.transition.Transition);
+ method public abstract void setResizingCaptionDrawable(android.graphics.drawable.Drawable);
+ method public final void setRestrictedCaptionAreaListener(android.view.Window.RestrictedCaptionAreaListener);
method public void setReturnTransition(android.transition.Transition);
method public void setSharedElementEnterTransition(android.transition.Transition);
method public void setSharedElementExitTransition(android.transition.Transition);
@@ -44219,6 +44222,9 @@
method public abstract void takeKeyEvents(boolean);
method public abstract void takeSurface(android.view.SurfaceHolder.Callback2);
method public abstract void togglePanel(int, android.view.KeyEvent);
+ field public static final int DECOR_CAPTION_SHADE_AUTO = 0; // 0x0
+ field public static final int DECOR_CAPTION_SHADE_DARK = 2; // 0x2
+ field public static final int DECOR_CAPTION_SHADE_LIGHT = 1; // 0x1
field protected static final deprecated int DEFAULT_FEATURES = 65; // 0x41
field public static final int FEATURE_ACTION_BAR = 8; // 0x8
field public static final int FEATURE_ACTION_BAR_OVERLAY = 9; // 0x9
@@ -44273,6 +44279,10 @@
method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
}
+ public static abstract interface Window.RestrictedCaptionAreaListener {
+ method public abstract void onRestrictedCaptionAreaChanged(android.graphics.Rect);
+ }
+
public final class WindowAnimationFrameStats extends android.view.FrameStats implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
diff --git a/api/test-current.txt b/api/test-current.txt
index 032507b..3e455102 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -41834,6 +41834,7 @@
method public abstract void setContentView(int);
method public abstract void setContentView(android.view.View);
method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+ method public abstract void setDecorCaptionShade(int);
method protected void setDefaultWindowFormat(int);
method public void setDimAmount(float);
method public void setElevation(float);
@@ -41854,6 +41855,8 @@
method public void setMediaController(android.media.session.MediaController);
method public abstract void setNavigationBarColor(int);
method public void setReenterTransition(android.transition.Transition);
+ method public abstract void setResizingCaptionDrawable(android.graphics.drawable.Drawable);
+ method public final void setRestrictedCaptionAreaListener(android.view.Window.RestrictedCaptionAreaListener);
method public void setReturnTransition(android.transition.Transition);
method public void setSharedElementEnterTransition(android.transition.Transition);
method public void setSharedElementExitTransition(android.transition.Transition);
@@ -41882,6 +41885,9 @@
method public abstract void takeKeyEvents(boolean);
method public abstract void takeSurface(android.view.SurfaceHolder.Callback2);
method public abstract void togglePanel(int, android.view.KeyEvent);
+ field public static final int DECOR_CAPTION_SHADE_AUTO = 0; // 0x0
+ field public static final int DECOR_CAPTION_SHADE_DARK = 2; // 0x2
+ field public static final int DECOR_CAPTION_SHADE_LIGHT = 1; // 0x1
field protected static final deprecated int DEFAULT_FEATURES = 65; // 0x41
field public static final int FEATURE_ACTION_BAR = 8; // 0x8
field public static final int FEATURE_ACTION_BAR_OVERLAY = 9; // 0x9
@@ -41936,6 +41942,10 @@
method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
}
+ public static abstract interface Window.RestrictedCaptionAreaListener {
+ method public abstract void onRestrictedCaptionAreaChanged(android.graphics.Rect);
+ }
+
public final class WindowAnimationFrameStats extends android.view.FrameStats implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 381ca4c..74fd8cd 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3323,6 +3323,7 @@
PUBLIC_SETTINGS.add(SOUND_EFFECTS_ENABLED);
PUBLIC_SETTINGS.add(HAPTIC_FEEDBACK_ENABLED);
PUBLIC_SETTINGS.add(SHOW_WEB_SUGGESTIONS);
+ PUBLIC_SETTINGS.add(VIBRATE_WHEN_RINGING);
}
/**
@@ -3344,7 +3345,6 @@
PRIVATE_SETTINGS.add(VIBRATE_IN_SILENT);
PRIVATE_SETTINGS.add(MEDIA_BUTTON_RECEIVER);
PRIVATE_SETTINGS.add(HIDE_ROTATION_LOCK_TOGGLE_FOR_ACCESSIBILITY);
- PRIVATE_SETTINGS.add(VIBRATE_WHEN_RINGING);
PRIVATE_SETTINGS.add(DTMF_TONE_TYPE_WHEN_DIALING);
PRIVATE_SETTINGS.add(HEARING_AID);
PRIVATE_SETTINGS.add(TTY_MODE);
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 7a359e7..53490b4 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -29,6 +29,7 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.PixelFormat;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.media.session.MediaController;
import android.net.Uri;
@@ -247,12 +248,30 @@
private static final String PROPERTY_HARDWARE_UI = "persist.sys.ui.hw";
+ /**
+ * Flag for letting the theme drive the color of the window caption controls. Use with
+ * {@link #setDecorCaptionShade(int)}. This is the default value.
+ */
+ public static final int DECOR_CAPTION_SHADE_AUTO = 0;
+ /**
+ * Flag for setting light-color controls on the window caption. Use with
+ * {@link #setDecorCaptionShade(int)}.
+ */
+ public static final int DECOR_CAPTION_SHADE_LIGHT = 1;
+ /**
+ * Flag for setting dark-color controls on the window caption. Use with
+ * {@link #setDecorCaptionShade(int)}.
+ */
+ public static final int DECOR_CAPTION_SHADE_DARK = 2;
+
private final Context mContext;
private TypedArray mWindowStyle;
private Callback mCallback;
private OnWindowDismissedCallback mOnWindowDismissedCallback;
private WindowControllerCallback mWindowControllerCallback;
+ private RestrictedCaptionAreaListener mRestrictedCaptionAreaListener;
+ private Rect mRestrictedCaptionAreaRect;
private WindowManager mWindowManager;
private IBinder mAppToken;
private String mAppName;
@@ -565,6 +584,18 @@
int getWindowStackId() throws RemoteException;
}
+ /**
+ * Callback for clients that want to be aware of where caption draws content.
+ */
+ public interface RestrictedCaptionAreaListener {
+ /**
+ * Called when the area where caption draws content changes.
+ *
+ * @param rect The area where caption content is positioned, relative to the top view.
+ */
+ void onRestrictedCaptionAreaChanged(Rect rect);
+ }
+
public Window(Context context) {
mContext = context;
mFeatures = mLocalFeatures = getDefaultFeatures(context);
@@ -778,6 +809,16 @@
}
/**
+ * Set a callback for changes of area where caption will draw its content.
+ *
+ * @param listener Callback that will be called when the area changes.
+ */
+ public final void setRestrictedCaptionAreaListener(RestrictedCaptionAreaListener listener) {
+ mRestrictedCaptionAreaListener = listener;
+ mRestrictedCaptionAreaRect = listener != null ? new Rect() : null;
+ }
+
+ /**
* Take ownership of this window's surface. The window's view hierarchy
* will no longer draw into the surface, though it will otherwise continue
* to operate (such as for receiving input events). The given SurfaceHolder
@@ -2040,5 +2081,29 @@
return mOverlayWithDecorCaption;
}
+ /** @hide */
+ public void notifyRestrictedCaptionAreaCallback(int left, int top, int right, int bottom) {
+ if (mRestrictedCaptionAreaListener != null) {
+ mRestrictedCaptionAreaRect.set(left, top, right, bottom);
+ mRestrictedCaptionAreaListener.onRestrictedCaptionAreaChanged(
+ mRestrictedCaptionAreaRect);
+ }
+ }
+ /**
+ * Set what color should the caption controls be. By default the system will try to determine
+ * the color from the theme. You can overwrite this by using {@link #DECOR_CAPTION_SHADE_DARK}
+ * or {@link #DECOR_CAPTION_SHADE_DARK}.
+ */
+ public abstract void setDecorCaptionShade(int decorCaptionShade);
+
+ /**
+ * Set the drawable that is drawn underneath the caption during the resizing.
+ *
+ * During the resizing the caption might not be drawn fast enough to match the new dimensions.
+ * There is a second caption drawn underneath it that will be fast enough. By default the
+ * caption is constructed from the theme. You can provide a drawable, that will be drawn instead
+ * to better match your application.
+ */
+ public abstract void setResizingCaptionDrawable(Drawable drawable);
}
diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
index 75ca639..1b44ff3 100644
--- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java
+++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
@@ -63,17 +63,18 @@
private boolean mReportNextDraw;
private Drawable mCaptionBackgroundDrawable;
+ private Drawable mUserCaptionBackgroundDrawable;
private Drawable mResizingBackgroundDrawable;
private ColorDrawable mStatusBarColor;
public BackdropFrameRenderer(DecorView decorView, ThreadedRenderer renderer, Rect initialBounds,
Drawable resizingBackgroundDrawable, Drawable captionBackgroundDrawable,
- int statusBarColor) {
+ Drawable userCaptionBackgroundDrawable, int statusBarColor) {
setName("ResizeFrame");
mRenderer = renderer;
onResourcesLoaded(decorView, resizingBackgroundDrawable, captionBackgroundDrawable,
- statusBarColor);
+ userCaptionBackgroundDrawable, statusBarColor);
// Create a render node for the content and frame backdrop
// which can be resized independently from the content.
@@ -92,10 +93,12 @@
}
void onResourcesLoaded(DecorView decorView, Drawable resizingBackgroundDrawable,
- Drawable captionBackgroundDrawableDrawable, int statusBarColor) {
+ Drawable captionBackgroundDrawableDrawable, Drawable userCaptionBackgroundDrawable,
+ int statusBarColor) {
mDecorView = decorView;
mResizingBackgroundDrawable = resizingBackgroundDrawable;
mCaptionBackgroundDrawable = captionBackgroundDrawableDrawable;
+ mUserCaptionBackgroundDrawable = userCaptionBackgroundDrawable;
if (statusBarColor != 0) {
mStatusBarColor = new ColorDrawable(statusBarColor);
addSystemBarNodeIfNeeded();
@@ -281,8 +284,10 @@
// Draw the caption and content backdrops in to our render node.
DisplayListCanvas canvas = mFrameAndBackdropNode.start(width, height);
- mCaptionBackgroundDrawable.setBounds(0, 0, left + width, top + mLastCaptionHeight);
- mCaptionBackgroundDrawable.draw(canvas);
+ final Drawable drawable = mUserCaptionBackgroundDrawable != null
+ ? mUserCaptionBackgroundDrawable : mCaptionBackgroundDrawable;
+ drawable.setBounds(0, 0, left + width, top + mLastCaptionHeight);
+ drawable.draw(canvas);
// The backdrop: clear everything with the background. Clipping is done elsewhere.
mResizingBackgroundDrawable.setBounds(0, mLastCaptionHeight, left + width, top + height);
@@ -324,4 +329,8 @@
mChoreographer.postFrameCallback(this);
}
}
+
+ void setUserCaptionBackgroundDrawable(Drawable userCaptionBackgroundDrawable) {
+ mUserCaptionBackgroundDrawable = userCaptionBackgroundDrawable;
+ }
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 531ba2f..e405564 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -74,6 +74,8 @@
import static android.view.View.MeasureSpec.getMode;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.view.Window.DECOR_CAPTION_SHADE_DARK;
+import static android.view.Window.DECOR_CAPTION_SHADE_LIGHT;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
@@ -184,9 +186,10 @@
private boolean mWindowResizeCallbacksAdded = false;
- BackdropFrameRenderer mBackdropFrameRenderer = null;
+ private BackdropFrameRenderer mBackdropFrameRenderer = null;
private Drawable mResizingBackgroundDrawable;
private Drawable mCaptionBackgroundDrawable;
+ private Drawable mUserCaptionBackgroundDrawable;
DecorView(Context context, int featureId, PhoneWindow window) {
super(context);
@@ -1580,18 +1583,20 @@
initializeElevation();
}
- View onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
+ void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
mStackId = getStackId();
mResizingBackgroundDrawable = getResizingBackgroundDrawable(
mWindow.mBackgroundResource, mWindow.mBackgroundFallbackResource);
- mCaptionBackgroundDrawable =
- getContext().getDrawable(R.drawable.decor_caption_title_focused);
+ if (mCaptionBackgroundDrawable == null) {
+ mCaptionBackgroundDrawable = getContext().getDrawable(
+ R.drawable.decor_caption_title_focused);
+ }
if (mBackdropFrameRenderer != null) {
mBackdropFrameRenderer.onResourcesLoaded(
this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
- getCurrentColor(mStatusColorViewState));
+ mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState));
}
mDecorCaptionView = createDecorCaptionView(inflater);
@@ -1608,17 +1613,16 @@
}
mContentRoot = (ViewGroup) root;
initializeElevation();
- return root;
}
// Free floating overlapping windows require a caption.
private DecorCaptionView createDecorCaptionView(LayoutInflater inflater) {
- DecorCaptionView DecorCaptionView = null;
- for (int i = getChildCount() - 1; i >= 0 && DecorCaptionView == null; i--) {
+ DecorCaptionView decorCaptionView = null;
+ for (int i = getChildCount() - 1; i >= 0 && decorCaptionView == null; i--) {
View view = getChildAt(i);
if (view instanceof DecorCaptionView) {
// The decor was most likely saved from a relaunch - so reuse it.
- DecorCaptionView = (DecorCaptionView) view;
+ decorCaptionView = (DecorCaptionView) view;
removeViewAt(i);
}
}
@@ -1630,27 +1634,72 @@
&& ActivityManager.StackId.hasWindowDecor(mStackId)) {
// Dependent on the brightness of the used title we either use the
// dark or the light button frame.
- if (DecorCaptionView == null) {
- Context context = getContext();
- TypedValue value = new TypedValue();
- context.getTheme().resolveAttribute(R.attr.colorPrimary, value, true);
- inflater = inflater.from(context);
- if (Color.luminance(value.data) < 0.5) {
- DecorCaptionView = (DecorCaptionView) inflater.inflate(
- R.layout.decor_caption_dark, null);
- } else {
- DecorCaptionView = (DecorCaptionView) inflater.inflate(
- R.layout.decor_caption_light, null);
- }
+ if (decorCaptionView == null) {
+ decorCaptionView = inflateDecorCaptionView(inflater);
}
- DecorCaptionView.setPhoneWindow(mWindow, true /*showDecor*/);
+ decorCaptionView.setPhoneWindow(mWindow, true /*showDecor*/);
} else {
- DecorCaptionView = null;
+ decorCaptionView = null;
}
// Tell the decor if it has a visible caption.
- enableCaption(DecorCaptionView != null);
- return DecorCaptionView;
+ enableCaption(decorCaptionView != null);
+ return decorCaptionView;
+ }
+
+ private DecorCaptionView inflateDecorCaptionView(LayoutInflater inflater) {
+ final Context context = getContext();
+ // We make a copy of the inflater, so it has the right context associated with it.
+ inflater = inflater.from(context);
+ final DecorCaptionView view = (DecorCaptionView) inflater.inflate(R.layout.decor_caption,
+ null);
+ setDecorCaptionShade(context, view);
+ return view;
+ }
+
+ private void setDecorCaptionShade(Context context, DecorCaptionView view) {
+ final int shade = mWindow.getDecorCaptionShade();
+ switch (shade) {
+ case DECOR_CAPTION_SHADE_LIGHT:
+ setLightDecorCaptionShade(view);
+ break;
+ case DECOR_CAPTION_SHADE_DARK:
+ setDarkDecorCaptionShade(view);
+ break;
+ default: {
+ TypedValue value = new TypedValue();
+ context.getTheme().resolveAttribute(R.attr.colorPrimary, value, true);
+ // We invert the shade depending on brightness of the theme. Dark shade for light
+ // theme and vice versa. Thanks to this the buttons should be visible on the
+ // background.
+ if (Color.luminance(value.data) < 0.5) {
+ setLightDecorCaptionShade(view);
+ } else {
+ setDarkDecorCaptionShade(view);
+ }
+ break;
+ }
+ }
+ }
+
+ void updateDecorCaptionShade() {
+ if (mDecorCaptionView != null) {
+ setDecorCaptionShade(getContext(), mDecorCaptionView);
+ }
+ }
+
+ private void setLightDecorCaptionShade(DecorCaptionView view) {
+ view.findViewById(R.id.maximize_window).setBackgroundResource(
+ R.drawable.decor_maximize_button_light);
+ view.findViewById(R.id.close_window).setBackgroundResource(
+ R.drawable.decor_close_button_light);
+ }
+
+ private void setDarkDecorCaptionShade(DecorCaptionView view) {
+ view.findViewById(R.id.maximize_window).setBackgroundResource(
+ R.drawable.decor_maximize_button_dark);
+ view.findViewById(R.id.close_window).setBackgroundResource(
+ R.drawable.decor_close_button_dark);
}
/**
@@ -1735,11 +1784,11 @@
if (mBackdropFrameRenderer != null) {
return;
}
- final ThreadedRenderer renderer = (ThreadedRenderer) getHardwareRenderer();
+ final ThreadedRenderer renderer = getHardwareRenderer();
if (renderer != null) {
mBackdropFrameRenderer = new BackdropFrameRenderer(this, renderer,
initialBounds, mResizingBackgroundDrawable, mCaptionBackgroundDrawable,
- getCurrentColor(mStatusColorViewState));
+ mUserCaptionBackgroundDrawable, getCurrentColor(mStatusColorViewState));
// Get rid of the shadow while we are resizing. Shadow drawing takes considerable time.
// If we want to get the shadow shown while resizing, we would need to elevate a new
@@ -1849,6 +1898,16 @@
getResources().getDisplayMetrics());
}
+ /**
+ * Provide an override of the caption background drawable.
+ */
+ void setUserCaptionBackgroundDrawable(Drawable drawable) {
+ mUserCaptionBackgroundDrawable = drawable;
+ if (mBackdropFrameRenderer != null) {
+ mBackdropFrameRenderer.setUserCaptionBackgroundDrawable(drawable);
+ }
+ }
+
private static class ColorViewState {
View view = null;
int targetVisibility = View.INVISIBLE;
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 337bb69..86bd782 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -94,7 +94,6 @@
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
-import android.widget.LinearLayout;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
@@ -273,6 +272,8 @@
private boolean mIsStartingWindow;
private int mTheme = -1;
+ private int mDecorCaptionShade = DECOR_CAPTION_SHADE_AUTO;
+
static class WindowManagerHolder {
static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
@@ -2527,7 +2528,7 @@
}
mDecor.startChanging();
- final View in = mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
+ mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {
@@ -3720,4 +3721,21 @@
}
}
}
+
+ @Override
+ public void setResizingCaptionDrawable(Drawable drawable) {
+ mDecor.setUserCaptionBackgroundDrawable(drawable);
+ }
+
+ @Override
+ public void setDecorCaptionShade(int decorCaptionShade) {
+ mDecorCaptionShade = decorCaptionShade;
+ if (mDecor != null) {
+ mDecor.updateDecorCaptionShade();
+ }
+ }
+
+ int getDecorCaptionShade() {
+ return mDecorCaptionShade;
+ }
}
diff --git a/core/java/com/android/internal/widget/DecorCaptionView.java b/core/java/com/android/internal/widget/DecorCaptionView.java
index d747686..c3fe9e7 100644
--- a/core/java/com/android/internal/widget/DecorCaptionView.java
+++ b/core/java/com/android/internal/widget/DecorCaptionView.java
@@ -319,6 +319,10 @@
captionHeight + mContent.getMeasuredHeight());
}
}
+
+ // This assumes that the caption bar is at the top.
+ mOwner.notifyRestrictedCaptionAreaCallback(mMaximize.getLeft(), mMaximize.getTop(),
+ mClose.getRight(), mClose.getBottom());
}
/**
* Determine if the workspace is entirely covered by the window.
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 1ee7ea8..71f881e 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -595,6 +595,36 @@
MEMINFO_COUNT
};
+static long get_zram_mem_used()
+{
+#define ZRAM_SYSFS "/sys/block/zram0/"
+ FILE *f = fopen(ZRAM_SYSFS "mm_stat", "r");
+ if (f) {
+ long mem_used_total = 0;
+
+ int matched = fscanf(f, "%*d %*d %ld %*d %*d %*d %*d", &mem_used_total);
+ if (matched != 1)
+ ALOGW("failed to parse " ZRAM_SYSFS "mm_stat");
+
+ fclose(f);
+ return mem_used_total;
+ }
+
+ f = fopen(ZRAM_SYSFS "mem_used_total", "r");
+ if (f) {
+ long mem_used_total = 0;
+
+ int matched = fscanf(f, "%ld", &mem_used_total);
+ if (matched != 1)
+ ALOGW("failed to parse " ZRAM_SYSFS "mem_used_total");
+
+ fclose(f);
+ return mem_used_total;
+ }
+
+ return 0;
+}
+
static void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray out)
{
char buffer[1024];
@@ -680,15 +710,7 @@
if (*p) p++;
}
- fd = open("/sys/block/zram0/mem_used_total", O_RDONLY);
- if (fd >= 0) {
- len = read(fd, buffer, sizeof(buffer)-1);
- close(fd);
- if (len > 0) {
- buffer[len] = 0;
- mem[MEMINFO_ZRAM_TOTAL] = atoll(buffer)/1024;
- }
- }
+ mem[MEMINFO_ZRAM_TOTAL] = get_zram_mem_used() / 1024;
// Recompute Vmalloc Used since the value in meminfo
// doesn't account for I/O remapping which doesn't use RAM.
mem[MEMINFO_VMALLOC_USED] = get_allocated_vmalloc_memory() / 1024;
diff --git a/core/res/res/drawable/ic_decor_close_button_dark_focused.xml b/core/res/res/drawable/ic_decor_close_button_dark_focused.xml
index d7b167dd..0794ed3 100644
--- a/core/res/res/drawable/ic_decor_close_button_dark_focused.xml
+++ b/core/res/res/drawable/ic_decor_close_button_dark_focused.xml
@@ -23,7 +23,7 @@
android:translateX="8.0"
android:translateY="8.0" >
<path
- android:fillColor="#FFFFFFFF"
+ android:fillColor="#ff000000"
android:pathData="M6.9,4.0l-2.9,2.9 9.1,9.1 -9.1,9.200001 2.9,2.799999 9.1,-9.1 9.1,9.1 2.9,-2.799999 -9.1,-9.200001 9.1,-9.1 -2.9,-2.9 -9.1,9.2z"/>
</group>
</vector>
diff --git a/core/res/res/drawable/ic_decor_close_button_dark_unfocused.xml b/core/res/res/drawable/ic_decor_close_button_dark_unfocused.xml
index e2e81b9..bd1db51 100644
--- a/core/res/res/drawable/ic_decor_close_button_dark_unfocused.xml
+++ b/core/res/res/drawable/ic_decor_close_button_dark_unfocused.xml
@@ -23,7 +23,7 @@
android:translateX="8.0"
android:translateY="8.0" >
<path
- android:fillColor="#33FFFFFF"
+ android:fillColor="#33000000"
android:pathData="M6.9,4.0l-2.9,2.9 9.1,9.1 -9.1,9.200001 2.9,2.799999 9.1,-9.1 9.1,9.1 2.9,-2.799999 -9.1,-9.200001 9.1,-9.1 -2.9,-2.9 -9.1,9.2z"/>
</group>
</vector>
diff --git a/core/res/res/drawable/ic_decor_close_button_light_focused.xml b/core/res/res/drawable/ic_decor_close_button_light_focused.xml
index 0794ed3..d7b167dd 100644
--- a/core/res/res/drawable/ic_decor_close_button_light_focused.xml
+++ b/core/res/res/drawable/ic_decor_close_button_light_focused.xml
@@ -23,7 +23,7 @@
android:translateX="8.0"
android:translateY="8.0" >
<path
- android:fillColor="#ff000000"
+ android:fillColor="#FFFFFFFF"
android:pathData="M6.9,4.0l-2.9,2.9 9.1,9.1 -9.1,9.200001 2.9,2.799999 9.1,-9.1 9.1,9.1 2.9,-2.799999 -9.1,-9.200001 9.1,-9.1 -2.9,-2.9 -9.1,9.2z"/>
</group>
</vector>
diff --git a/core/res/res/drawable/ic_decor_close_button_light_unfocused.xml b/core/res/res/drawable/ic_decor_close_button_light_unfocused.xml
index bd1db51..e2e81b9 100644
--- a/core/res/res/drawable/ic_decor_close_button_light_unfocused.xml
+++ b/core/res/res/drawable/ic_decor_close_button_light_unfocused.xml
@@ -23,7 +23,7 @@
android:translateX="8.0"
android:translateY="8.0" >
<path
- android:fillColor="#33000000"
+ android:fillColor="#33FFFFFF"
android:pathData="M6.9,4.0l-2.9,2.9 9.1,9.1 -9.1,9.200001 2.9,2.799999 9.1,-9.1 9.1,9.1 2.9,-2.799999 -9.1,-9.200001 9.1,-9.1 -2.9,-2.9 -9.1,9.2z"/>
</group>
</vector>
diff --git a/core/res/res/drawable/ic_decor_maximize_button_dark_focused.xml b/core/res/res/drawable/ic_decor_maximize_button_dark_focused.xml
index 73d808b..c23390e 100644
--- a/core/res/res/drawable/ic_decor_maximize_button_dark_focused.xml
+++ b/core/res/res/drawable/ic_decor_maximize_button_dark_focused.xml
@@ -23,10 +23,10 @@
android:translateX="8.0"
android:translateY="8.0" >
<path
- android:fillColor="#FFFFFFFF"
+ android:fillColor="#FF000000"
android:pathData="M2.0,4.0l0.0,16.0l28.0,0.0L30.0,4.0L2.0,4.0zM26.0,16.0L6.0,16.0L6.0,8.0l20.0,0.0L26.0,16.0z"/>
<path
- android:fillColor="#B2FFFFFF"
+ android:fillColor="#B2000000"
android:pathData="M2.0,24.0l28.0,0.0l0.0,4.0l-28.0,0.0z"/>
</group>
</vector>
diff --git a/core/res/res/drawable/ic_decor_maximize_button_dark_unfocused.xml b/core/res/res/drawable/ic_decor_maximize_button_dark_unfocused.xml
index dc79e10..a194a39 100644
--- a/core/res/res/drawable/ic_decor_maximize_button_dark_unfocused.xml
+++ b/core/res/res/drawable/ic_decor_maximize_button_dark_unfocused.xml
@@ -23,10 +23,10 @@
android:translateX="8.0"
android:translateY="8.0" >
<path
- android:fillColor="#33FFFFFF"
+ android:fillColor="#33000000"
android:pathData="M2.0,4.0l0.0,16.0l28.0,0.0L30.0,4.0L2.0,4.0zM26.0,16.0L6.0,16.0L6.0,8.0l20.0,0.0L26.0,16.0z"/>
<path
- android:fillColor="#33FFFFFF"
+ android:fillColor="#33000000"
android:pathData="M2.0,24.0l28.0,0.0l0.0,4.0l-28.0,0.0z"/>
</group>
</vector>
diff --git a/core/res/res/drawable/ic_decor_maximize_button_light_focused.xml b/core/res/res/drawable/ic_decor_maximize_button_light_focused.xml
index c23390e..73d808b 100644
--- a/core/res/res/drawable/ic_decor_maximize_button_light_focused.xml
+++ b/core/res/res/drawable/ic_decor_maximize_button_light_focused.xml
@@ -23,10 +23,10 @@
android:translateX="8.0"
android:translateY="8.0" >
<path
- android:fillColor="#FF000000"
+ android:fillColor="#FFFFFFFF"
android:pathData="M2.0,4.0l0.0,16.0l28.0,0.0L30.0,4.0L2.0,4.0zM26.0,16.0L6.0,16.0L6.0,8.0l20.0,0.0L26.0,16.0z"/>
<path
- android:fillColor="#B2000000"
+ android:fillColor="#B2FFFFFF"
android:pathData="M2.0,24.0l28.0,0.0l0.0,4.0l-28.0,0.0z"/>
</group>
</vector>
diff --git a/core/res/res/drawable/ic_decor_maximize_button_light_unfocused.xml b/core/res/res/drawable/ic_decor_maximize_button_light_unfocused.xml
index a194a39..dc79e10 100644
--- a/core/res/res/drawable/ic_decor_maximize_button_light_unfocused.xml
+++ b/core/res/res/drawable/ic_decor_maximize_button_light_unfocused.xml
@@ -23,10 +23,10 @@
android:translateX="8.0"
android:translateY="8.0" >
<path
- android:fillColor="#33000000"
+ android:fillColor="#33FFFFFF"
android:pathData="M2.0,4.0l0.0,16.0l28.0,0.0L30.0,4.0L2.0,4.0zM26.0,16.0L6.0,16.0L6.0,8.0l20.0,0.0L26.0,16.0z"/>
<path
- android:fillColor="#33000000"
+ android:fillColor="#33FFFFFF"
android:pathData="M2.0,24.0l28.0,0.0l0.0,4.0l-28.0,0.0z"/>
</group>
</vector>
diff --git a/core/res/res/layout/decor_caption.xml b/core/res/res/layout/decor_caption.xml
new file mode 100644
index 0000000..0246736
--- /dev/null
+++ b/core/res/res/layout/decor_caption.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2015, 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.
+*/
+-->
+
+<com.android.internal.widget.DecorCaptionView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:descendantFocusability="beforeDescendants" >
+ <LinearLayout
+ android:id="@+id/caption"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="end"
+ android:background="@drawable/decor_caption_title"
+ android:focusable="false"
+ android:descendantFocusability="blocksDescendants" >
+ <Button
+ android:id="@+id/maximize_window"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_margin="5dp"
+ android:padding="4dp"
+ android:layout_gravity="center_vertical|end"
+ android:contentDescription="@string/maximize_button_text"
+ android:background="@drawable/decor_maximize_button_dark" />
+ <Button
+ android:id="@+id/close_window"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_margin="5dp"
+ android:padding="4dp"
+ android:layout_gravity="center_vertical|end"
+ android:contentDescription="@string/close_button_text"
+ android:background="@drawable/decor_close_button_dark" />
+ </LinearLayout>
+</com.android.internal.widget.DecorCaptionView>
diff --git a/core/res/res/layout/decor_caption_dark.xml b/core/res/res/layout/decor_caption_dark.xml
deleted file mode 100644
index 95d2289..0000000
--- a/core/res/res/layout/decor_caption_dark.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2015, 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.
-*/
--->
-
-<com.android.internal.widget.DecorCaptionView xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:descendantFocusability="beforeDescendants" >
- <LinearLayout
- android:id="@+id/caption"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="end"
- android:background="@drawable/decor_caption_title"
- android:focusable="false"
- android:descendantFocusability="blocksDescendants" >
- <Button
- android:id="@+id/maximize_window"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:layout_margin="5dp"
- android:padding="4dp"
- android:layout_gravity="center_vertical|end"
- android:contentDescription="@string/maximize_button_text"
- android:background="@drawable/decor_maximize_button_dark" />
- <Button
- android:id="@+id/close_window"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:layout_margin="5dp"
- android:padding="4dp"
- android:layout_gravity="center_vertical|end"
- android:contentDescription="@string/close_button_text"
- android:background="@drawable/decor_close_button_dark" />
- </LinearLayout>
-</com.android.internal.widget.DecorCaptionView>
diff --git a/core/res/res/layout/decor_caption_light.xml b/core/res/res/layout/decor_caption_light.xml
deleted file mode 100644
index f0f661e..0000000
--- a/core/res/res/layout/decor_caption_light.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2015, 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.
-*/
--->
-
-<com.android.internal.widget.DecorCaptionView xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:descendantFocusability="beforeDescendants" >
- <LinearLayout
- android:id="@+id/caption"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="end"
- android:background="@drawable/decor_caption_title"
- android:focusable="false"
- android:descendantFocusability="blocksDescendants" >
- <Button
- android:id="@+id/maximize_window"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:layout_margin="5dp"
- android:padding="4dp"
- android:layout_gravity="center_vertical|end"
- android:contentDescription="@string/maximize_button_text"
- android:background="@drawable/decor_maximize_button_light" />
- <Button
- android:id="@+id/close_window"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:layout_margin="5dp"
- android:padding="4dp"
- android:layout_gravity="center_vertical|end"
- android:contentDescription="@string/close_button_text"
- android:background="@drawable/decor_close_button_light" />
- </LinearLayout>
-</com.android.internal.widget.DecorCaptionView>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index eadcae0..177ca60 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1958,9 +1958,12 @@
<java-symbol type="bool" name="config_built_in_sip_phone" />
<java-symbol type="id" name="maximize_window" />
<java-symbol type="id" name="close_window" />
- <java-symbol type="layout" name="decor_caption_light" />
- <java-symbol type="layout" name="decor_caption_dark" />
+ <java-symbol type="layout" name="decor_caption" />
<java-symbol type="drawable" name="decor_caption_title_focused" />
+ <java-symbol type="drawable" name="decor_close_button_dark" />
+ <java-symbol type="drawable" name="decor_close_button_light" />
+ <java-symbol type="drawable" name="decor_maximize_button_dark" />
+ <java-symbol type="drawable" name="decor_maximize_button_light" />
<!-- From TelephonyProvider -->
<java-symbol type="xml" name="apns" />
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index 3d35dd5..f1c89b8 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -20,6 +20,7 @@
#include "Caches.h"
#include "Glop.h"
#include "GlopBuilder.h"
+#include "Patch.h"
#include "PathTessellator.h"
#include "renderstate/OffscreenBufferPool.h"
#include "renderstate/RenderState.h"
@@ -56,8 +57,6 @@
if (entry) {
entry->uvMapper.map(texCoords);
}
- // init to non-empty, so we can safely expandtoCoverRect
- Rect totalBounds = firstState.computedState.clippedBounds;
for (size_t i = 0; i < opList.count; i++) {
const BakedOpState& state = *(opList.states[i]);
TextureVertex* rectVerts = &vertices[i * 4];
@@ -68,8 +67,6 @@
}
storeTexturedRect(rectVerts, opBounds, texCoords);
renderer.dirtyRenderTarget(opBounds);
-
- totalBounds.expandToCover(opBounds);
}
const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType)
@@ -80,7 +77,111 @@
.setMeshTexturedIndexedQuads(vertices, opList.count * 6)
.setFillTexturePaint(*texture, textureFillFlags, firstState.op->paint, firstState.alpha)
.setTransform(Matrix4::identity(), TransformFlags::None)
- .setModelViewOffsetRect(0, 0, totalBounds) // don't snap here, we snap per-quad above
+ .setModelViewIdentityEmptyBounds()
+ .build();
+ renderer.renderGlop(nullptr, opList.clipSideFlags ? &opList.clip : nullptr, glop);
+}
+
+void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
+ const MergedBakedOpList& opList) {
+ const PatchOp& firstOp = *(static_cast<const PatchOp*>(opList.states[0]->op));
+ const BakedOpState& firstState = *(opList.states[0]);
+ AssetAtlas::Entry* entry = renderer.renderState().assetAtlas().getEntry(
+ firstOp.bitmap->pixelRef());
+
+ // Batches will usually contain a small number of items so it's
+ // worth performing a first iteration to count the exact number
+ // of vertices we need in the new mesh
+ uint32_t totalVertices = 0;
+
+ for (size_t i = 0; i < opList.count; i++) {
+ const PatchOp& op = *(static_cast<const PatchOp*>(opList.states[i]->op));
+
+ // TODO: cache mesh lookups
+ const Patch* opMesh = renderer.caches().patchCache.get(
+ entry, op.bitmap->width(), op.bitmap->height(),
+ op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch);
+ totalVertices += opMesh->verticesCount;
+ }
+
+ const bool dirtyRenderTarget = renderer.offscreenRenderTarget();
+
+ uint32_t indexCount = 0;
+
+ TextureVertex vertices[totalVertices];
+ TextureVertex* vertex = &vertices[0];
+ // Create a mesh that contains the transformed vertices for all the
+ // 9-patch objects that are part of the batch. Note that onDefer()
+ // enforces ops drawn by this function to have a pure translate or
+ // identity matrix
+ for (size_t i = 0; i < opList.count; i++) {
+ const PatchOp& op = *(static_cast<const PatchOp*>(opList.states[i]->op));
+ const BakedOpState& state = *opList.states[i];
+
+ // TODO: cache mesh lookups
+ const Patch* opMesh = renderer.caches().patchCache.get(
+ entry, op.bitmap->width(), op.bitmap->height(),
+ op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch);
+
+
+ uint32_t vertexCount = opMesh->verticesCount;
+ if (vertexCount == 0) continue;
+
+ // We use the bounds to know where to translate our vertices
+ // Using patchOp->state.mBounds wouldn't work because these
+ // bounds are clipped
+ const float tx = floorf(state.computedState.transform.getTranslateX()
+ + op.unmappedBounds.left + 0.5f);
+ const float ty = floorf(state.computedState.transform.getTranslateY()
+ + op.unmappedBounds.top + 0.5f);
+
+ // Copy & transform all the vertices for the current operation
+ TextureVertex* opVertices = opMesh->vertices.get();
+ for (uint32_t j = 0; j < vertexCount; j++, opVertices++) {
+ TextureVertex::set(vertex++,
+ opVertices->x + tx, opVertices->y + ty,
+ opVertices->u, opVertices->v);
+ }
+
+ // Dirty the current layer if possible. When the 9-patch does not
+ // contain empty quads we can take a shortcut and simply set the
+ // dirty rect to the object's bounds.
+ if (dirtyRenderTarget) {
+ if (!opMesh->hasEmptyQuads) {
+ renderer.dirtyRenderTarget(Rect(tx, ty,
+ tx + op.unmappedBounds.getWidth(), ty + op.unmappedBounds.getHeight()));
+ } else {
+ const size_t count = opMesh->quads.size();
+ for (size_t i = 0; i < count; i++) {
+ const Rect& quadBounds = opMesh->quads[i];
+ const float x = tx + quadBounds.left;
+ const float y = ty + quadBounds.top;
+ renderer.dirtyRenderTarget(Rect(x, y,
+ x + quadBounds.getWidth(), y + quadBounds.getHeight()));
+ }
+ }
+ }
+
+ indexCount += opMesh->indexCount;
+ }
+
+
+ Texture* texture = entry ? entry->texture : renderer.caches().textureCache.get(firstOp.bitmap);
+ if (!texture) return;
+ const AutoTexture autoCleanup(texture);
+
+ // 9 patches are built for stretching - always filter
+ int textureFillFlags = TextureFillFlags::ForceFilter;
+ if (firstOp.bitmap->colorType() == kAlpha_8_SkColorType) {
+ textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture;
+ }
+ Glop glop;
+ GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+ .setRoundRectClipState(firstState.roundRectClipState)
+ .setMeshTexturedIndexedQuads(vertices, indexCount)
+ .setFillTexturePaint(*texture, textureFillFlags, firstOp.paint, firstState.alpha)
+ .setTransform(Matrix4::identity(), TransformFlags::None)
+ .setModelViewIdentityEmptyBounds()
.build();
renderer.renderGlop(nullptr, opList.clipSideFlags ? &opList.clip : nullptr, glop);
}
@@ -310,6 +411,105 @@
renderer.renderGlop(state, glop);
}
+void BakedOpDispatcher::onBitmapMeshOp(BakedOpRenderer& renderer, const BitmapMeshOp& op, const BakedOpState& state) {
+ const static UvMapper defaultUvMapper;
+ const uint32_t elementCount = op.meshWidth * op.meshHeight * 6;
+
+ std::unique_ptr<ColorTextureVertex[]> mesh(new ColorTextureVertex[elementCount]);
+ ColorTextureVertex* vertex = &mesh[0];
+
+ const int* colors = op.colors;
+ std::unique_ptr<int[]> tempColors;
+ if (!colors) {
+ uint32_t colorsCount = (op.meshWidth + 1) * (op.meshHeight + 1);
+ tempColors.reset(new int[colorsCount]);
+ memset(tempColors.get(), 0xff, colorsCount * sizeof(int));
+ colors = tempColors.get();
+ }
+
+ Texture* texture = renderer.renderState().assetAtlas().getEntryTexture(op.bitmap->pixelRef());
+ const UvMapper& mapper(texture && texture->uvMapper ? *texture->uvMapper : defaultUvMapper);
+
+ for (int32_t y = 0; y < op.meshHeight; y++) {
+ for (int32_t x = 0; x < op.meshWidth; x++) {
+ uint32_t i = (y * (op.meshWidth + 1) + x) * 2;
+
+ float u1 = float(x) / op.meshWidth;
+ float u2 = float(x + 1) / op.meshWidth;
+ float v1 = float(y) / op.meshHeight;
+ float v2 = float(y + 1) / op.meshHeight;
+
+ mapper.map(u1, v1, u2, v2);
+
+ int ax = i + (op.meshWidth + 1) * 2;
+ int ay = ax + 1;
+ int bx = i;
+ int by = bx + 1;
+ int cx = i + 2;
+ int cy = cx + 1;
+ int dx = i + (op.meshWidth + 1) * 2 + 2;
+ int dy = dx + 1;
+
+ const float* vertices = op.vertices;
+ ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
+ ColorTextureVertex::set(vertex++, vertices[ax], vertices[ay], u1, v2, colors[ax / 2]);
+ ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
+
+ ColorTextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2, colors[dx / 2]);
+ ColorTextureVertex::set(vertex++, vertices[bx], vertices[by], u1, v1, colors[bx / 2]);
+ ColorTextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1, colors[cx / 2]);
+ }
+ }
+
+ if (!texture) {
+ texture = renderer.caches().textureCache.get(op.bitmap);
+ if (!texture) {
+ return;
+ }
+ }
+ const AutoTexture autoCleanup(texture);
+
+ /*
+ * TODO: handle alpha_8 textures correctly by applying paint color, but *not*
+ * shader in that case to mimic the behavior in SkiaCanvas::drawBitmapMesh.
+ */
+ const int textureFillFlags = TextureFillFlags::None;
+ Glop glop;
+ GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+ .setRoundRectClipState(state.roundRectClipState)
+ .setMeshColoredTexturedMesh(mesh.get(), elementCount)
+ .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
+ .setTransform(state.computedState.transform, TransformFlags::None)
+ .setModelViewOffsetRect(0, 0, op.unmappedBounds)
+ .build();
+ renderer.renderGlop(state, glop);
+}
+
+void BakedOpDispatcher::onBitmapRectOp(BakedOpRenderer& renderer, const BitmapRectOp& op, const BakedOpState& state) {
+ Texture* texture = renderer.getTexture(op.bitmap);
+ if (!texture) return;
+ const AutoTexture autoCleanup(texture);
+
+ Rect uv(std::max(0.0f, op.src.left / texture->width),
+ std::max(0.0f, op.src.top / texture->height),
+ std::min(1.0f, op.src.right / texture->width),
+ std::min(1.0f, op.src.bottom / texture->height));
+
+ const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType)
+ ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
+ const bool tryToSnap = MathUtils::areEqual(op.src.getWidth(), op.unmappedBounds.getWidth())
+ && MathUtils::areEqual(op.src.getHeight(), op.unmappedBounds.getHeight());
+ Glop glop;
+ GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+ .setRoundRectClipState(state.roundRectClipState)
+ .setMeshTexturedUvQuad(texture->uvMapper, uv)
+ .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
+ .setTransform(state.computedState.transform, TransformFlags::None)
+ .setModelViewMapUnitToRectOptionalSnap(tryToSnap, op.unmappedBounds)
+ .build();
+ renderer.renderGlop(state, glop);
+}
+
void BakedOpDispatcher::onLinesOp(BakedOpRenderer& renderer, const LinesOp& op, const BakedOpState& state) {
VertexBuffer buffer;
PathTessellator::tessellateLines(op.points, op.floatCount, op.paint,
@@ -334,6 +534,35 @@
}
}
+void BakedOpDispatcher::onPatchOp(BakedOpRenderer& renderer, const PatchOp& op, const BakedOpState& state) {
+ // 9 patches are built for stretching - always filter
+ int textureFillFlags = TextureFillFlags::ForceFilter;
+ if (op.bitmap->colorType() == kAlpha_8_SkColorType) {
+ textureFillFlags |= TextureFillFlags::IsAlphaMaskTexture;
+ }
+
+ // TODO: avoid redoing the below work each frame:
+ AssetAtlas::Entry* entry = renderer.renderState().assetAtlas().getEntry(op.bitmap->pixelRef());
+ const Patch* mesh = renderer.caches().patchCache.get(
+ entry, op.bitmap->width(), op.bitmap->height(),
+ op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch);
+
+ Texture* texture = entry ? entry->texture : renderer.caches().textureCache.get(op.bitmap);
+ if (!texture) return;
+ const AutoTexture autoCleanup(texture);
+ Glop glop;
+ GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+ .setRoundRectClipState(state.roundRectClipState)
+ .setMeshPatchQuads(*mesh)
+ .setMeshTexturedUnitQuad(texture->uvMapper)
+ .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
+ .setTransform(state.computedState.transform, TransformFlags::None)
+ .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top,
+ Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight()))
+ .build();
+ renderer.renderGlop(state, glop);
+}
+
void BakedOpDispatcher::onPathOp(BakedOpRenderer& renderer, const PathOp& op, const BakedOpState& state) {
PathTexture* texture = renderer.caches().pathCache.get(op.path, op.paint);
const AutoTexture holder(texture);
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 9c8649f..8acdb62 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -73,7 +73,7 @@
.setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
.setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, bakedState->alpha)
.setTransform(bakedState->computedState.transform, transformFlags)
- .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
+ .setModelViewIdentityEmptyBounds()
.build();
// Note: don't pass dirty bounds here, so user must manage passing dirty bounds to renderer
renderer->renderGlop(nullptr, clip, glop);
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
index 4785ea4..bcf819e 100644
--- a/libs/hwui/Glop.h
+++ b/libs/hwui/Glop.h
@@ -64,7 +64,7 @@
// Canvas transform isn't applied to the mesh at draw time,
//since it's already built in.
- MeshIgnoresCanvasTransform = 1 << 1,
+ MeshIgnoresCanvasTransform = 1 << 1, // TODO: remove
};
};
diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h
index b647b90..6e5797d 100644
--- a/libs/hwui/GlopBuilder.h
+++ b/libs/hwui/GlopBuilder.h
@@ -95,6 +95,10 @@
return setModelViewOffsetRect(offsetX, offsetY, source);
}
}
+ GlopBuilder& setModelViewIdentityEmptyBounds() {
+ // pass empty rect since not needed for damage / snap
+ return setModelViewOffsetRect(0, 0, Rect());
+ }
GlopBuilder& setRoundRectClipState(const RoundRectClipState* roundRectClipState);
diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp
index f948f18..b936e6d5 100644
--- a/libs/hwui/OpReorderer.cpp
+++ b/libs/hwui/OpReorderer.cpp
@@ -757,6 +757,18 @@
}
}
+void OpReorderer::onBitmapMeshOp(const BitmapMeshOp& op) {
+ BakedOpState* bakedState = tryBakeOpState(op);
+ if (!bakedState) return; // quick rejected
+ currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
+}
+
+void OpReorderer::onBitmapRectOp(const BitmapRectOp& op) {
+ BakedOpState* bakedState = tryBakeOpState(op);
+ if (!bakedState) return; // quick rejected
+ currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
+}
+
void OpReorderer::onLinesOp(const LinesOp& op) {
batchid_t batch = op.paint->isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices;
onStrokeableOp(op, batch, BakedOpState::StrokeBehavior::Forced);
@@ -766,6 +778,23 @@
onStrokeableOp(op, tessBatchId(op));
}
+void OpReorderer::onPatchOp(const PatchOp& op) {
+ BakedOpState* bakedState = tryBakeOpState(op);
+ if (!bakedState) return; // quick rejected
+
+ if (bakedState->computedState.transform.isPureTranslate()
+ && PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode) {
+ mergeid_t mergeId = (mergeid_t) op.bitmap->getGenerationID();
+ // TODO: AssetAtlas in mergeId
+
+ // Only use the MergedPatch batchId when merged, so Bitmap+Patch don't try to merge together
+ currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::MergedPatch, mergeId);
+ } else {
+ // Use Bitmap batchId since Bitmap+Patch use same shader
+ currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
+ }
+}
+
void OpReorderer::onPathOp(const PathOp& op) {
onStrokeableOp(op, OpBatchType::Bitmap);
}
diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h
index 58b607c..0b88f04 100644
--- a/libs/hwui/OpReorderer.h
+++ b/libs/hwui/OpReorderer.h
@@ -45,7 +45,7 @@
enum {
None = 0, // Don't batch
Bitmap,
- Patch,
+ MergedPatch,
AlphaVertices,
Vertices,
AlphaMaskTexture,
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index 8ce5473..75ecdae 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -24,7 +24,8 @@
#include "utils/LinearAllocator.h"
#include "Vector.h"
-#include "SkXfermode.h"
+#include <androidfw/ResourceTypes.h>
+#include <SkXfermode.h>
class SkBitmap;
class SkPaint;
@@ -45,8 +46,11 @@
#define MAP_OPS_BASED_ON_MERGEABILITY(U_OP_FN, M_OP_FN) \
U_OP_FN(ArcOp) \
M_OP_FN(BitmapOp) \
+ U_OP_FN(BitmapMeshOp) \
+ U_OP_FN(BitmapRectOp) \
U_OP_FN(LinesOp) \
U_OP_FN(OvalOp) \
+ M_OP_FN(PatchOp) \
U_OP_FN(PathOp) \
U_OP_FN(PointsOp) \
U_OP_FN(RectOp) \
@@ -152,6 +156,31 @@
// TODO: asset atlas/texture id lookup?
};
+struct BitmapMeshOp : RecordedOp {
+ BitmapMeshOp(BASE_PARAMS, const SkBitmap* bitmap, int meshWidth, int meshHeight,
+ const float* vertices, const int* colors)
+ : SUPER(BitmapMeshOp)
+ , bitmap(bitmap)
+ , meshWidth(meshWidth)
+ , meshHeight(meshHeight)
+ , vertices(vertices)
+ , colors(colors) {}
+ const SkBitmap* bitmap;
+ const int meshWidth;
+ const int meshHeight;
+ const float* vertices;
+ const int* colors;
+};
+
+struct BitmapRectOp : RecordedOp {
+ BitmapRectOp(BASE_PARAMS, const SkBitmap* bitmap, const Rect& src)
+ : SUPER(BitmapRectOp)
+ , bitmap(bitmap)
+ , src(src) {}
+ const SkBitmap* bitmap;
+ const Rect src;
+};
+
struct LinesOp : RecordedOp {
LinesOp(BASE_PARAMS, const float* points, const int floatCount)
: SUPER(LinesOp)
@@ -166,6 +195,16 @@
: SUPER(OvalOp) {}
};
+
+struct PatchOp : RecordedOp {
+ PatchOp(BASE_PARAMS, const SkBitmap* bitmap, const Res_png_9patch* patch)
+ : SUPER(PatchOp)
+ , bitmap(bitmap)
+ , patch(patch) {}
+ const SkBitmap* bitmap;
+ const Res_png_9patch* patch;
+};
+
struct PathOp : RecordedOp {
PathOp(BASE_PARAMS, const SkPath* path)
: SUPER(PathOp)
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 148c940..57f0d34 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -418,19 +418,35 @@
drawBitmap(&bitmap, paint);
restore();
} else {
- LOG_ALWAYS_FATAL("TODO!");
+ addOp(new (alloc()) BitmapRectOp(
+ Rect(dstLeft, dstTop, dstRight, dstBottom),
+ *(mState.currentSnapshot()->transform),
+ mState.getRenderTargetClipBounds(),
+ refPaint(paint), refBitmap(bitmap),
+ Rect(srcLeft, srcTop, srcRight, srcBottom)));
}
}
void RecordingCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
const float* vertices, const int* colors, const SkPaint* paint) {
- LOG_ALWAYS_FATAL("TODO!");
+ int vertexCount = (meshWidth + 1) * (meshHeight + 1);
+ addOp(new (alloc()) BitmapMeshOp(
+ calcBoundsOfPoints(vertices, vertexCount * 2),
+ *(mState.currentSnapshot()->transform),
+ mState.getRenderTargetClipBounds(),
+ refPaint(paint), refBitmap(bitmap), meshWidth, meshHeight,
+ refBuffer<float>(vertices, vertexCount * 2), // 2 floats per vertex
+ refBuffer<int>(colors, vertexCount))); // 1 color per vertex
}
-void RecordingCanvas::drawNinePatch(const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
+void RecordingCanvas::drawNinePatch(const SkBitmap& bitmap, const android::Res_png_9patch& patch,
float dstLeft, float dstTop, float dstRight, float dstBottom,
const SkPaint* paint) {
- LOG_ALWAYS_FATAL("TODO!");
+ addOp(new (alloc()) PatchOp(
+ Rect(dstLeft, dstTop, dstRight, dstBottom),
+ *(mState.currentSnapshot()->transform),
+ mState.getRenderTargetClipBounds(),
+ refPaint(paint), refBitmap(bitmap), refPatch(&patch)));
}
// Text
@@ -452,7 +468,6 @@
void RecordingCanvas::drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
float hOffset, float vOffset, const SkPaint& paint) {
- // NOTE: can't use refPaint() directly, since it forces left alignment
LOG_ALWAYS_FATAL("TODO!");
}
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index 0e31cdf..44018a0 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -40,6 +40,8 @@
import java.util.zip.ZipOutputStream;
import libcore.io.Streams;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningServiceInfo;
import android.app.Instrumentation;
import android.app.NotificationManager;
import android.content.Context;
@@ -130,7 +132,8 @@
Bundle extras = sendBugreportFinishedIntent(42, PLAIN_TEXT_PATH, SCREENSHOT_PATH);
assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT);
- // TODO: assert service is down
+ String service = BugreportProgressService.class.getName();
+ assertFalse("Service '" + service + "' is still running", isServiceRunning(service));
}
public void testBugreportFinished_withWarning() throws Exception {
@@ -306,6 +309,17 @@
fail("Did not find entry '" + entryName + "' on file '" + uri + "'");
}
+ private boolean isServiceRunning(String name) {
+ ActivityManager manager = (ActivityManager) mContext
+ .getSystemService(Context.ACTIVITY_SERVICE);
+ for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
+ if (service.service.getClassName().equals(name)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private static void createTextFile(String path, String content) throws IOException {
Log.v(TAG, "createFile(" + path + ")");
try (Writer writer = new BufferedWriter(new OutputStreamWriter(
diff --git a/packages/Shell/tests/src/com/android/shell/UiBot.java b/packages/Shell/tests/src/com/android/shell/UiBot.java
index 5e8bab1..7d37137 100644
--- a/packages/Shell/tests/src/com/android/shell/UiBot.java
+++ b/packages/Shell/tests/src/com/android/shell/UiBot.java
@@ -118,7 +118,8 @@
// TODO: UI Automator should provide such logic.
public void chooseActivity(String name) {
// First check if the activity is the default option.
- String shareText = String.format("Share with %s", name);
+ String shareText = "Share with " + name;
+ Log.v(TAG, "Waiting for ActivityChooser text: '" + shareText + "'");
boolean gotIt = mDevice.wait(Until.hasObject(By.text(shareText)), mTimeout);
if (gotIt) {
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 4e812aa..8737d43 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -45,8 +45,11 @@
<!-- Height of a large notification in the status bar -->
<dimen name="notification_max_height">276dp</dimen>
- <!-- Height of a medium notification in the status bar -->
- <dimen name="notification_mid_height">128dp</dimen>
+ <!-- Height of a heads up notification in the status bar for legacy custom views -->
+ <dimen name="notification_max_heads_up_height_legacy">128dp</dimen>
+
+ <!-- Height of a heads up notification in the status bar -->
+ <dimen name="notification_max_heads_up_height">140dp</dimen>
<!-- Height of a the summary ("more card") notification on keyguard. -->
<dimen name="notification_summary_height">44dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java b/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
index 5b8d3d6..c9ba885 100644
--- a/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
+import android.content.Context;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
@@ -35,13 +36,19 @@
private final Paint mDarkPaint = new Paint();
private final Interpolator mLinearOutSlowInInterpolator;
- private final ArrayList<View> mTargets;
private final ColorMatrix mMatrix = new ColorMatrix();
private final ColorMatrix mGrayscaleMatrix = new ColorMatrix();
private final long mFadeDuration;
+ private final ArrayList<View> mTargets = new ArrayList<>();
- public ViewInvertHelper(View target, long fadeDuration) {
- this(constructArray(target), fadeDuration);
+ public ViewInvertHelper(View v, long fadeDuration) {
+ this(v.getContext(), fadeDuration);
+ addTarget(v);
+ }
+ public ViewInvertHelper(Context context, long fadeDuration) {
+ mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+ android.R.interpolator.linear_out_slow_in);
+ mFadeDuration = fadeDuration;
}
private static ArrayList<View> constructArray(View target) {
@@ -50,11 +57,12 @@
return views;
}
- public ViewInvertHelper(ArrayList<View> targets, long fadeDuration) {
- mTargets = targets;
- mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(mTargets.get(0).getContext(),
- android.R.interpolator.linear_out_slow_in);
- mFadeDuration = fadeDuration;
+ public void clearTargets() {
+ mTargets.clear();
+ }
+
+ public void addTarget(View target) {
+ mTargets.add(target);
}
public void fade(final boolean invert, long delay) {
@@ -112,4 +120,12 @@
mMatrix.preConcat(mGrayscaleMatrix);
mDarkPaint.setColorFilter(new ColorMatrixColorFilter(mMatrix));
}
+
+ public void setInverted(boolean invert, boolean fade, long delay) {
+ if (fade) {
+ fade(invert, delay);
+ } else {
+ update(invert);
+ }
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 879624e..b1847e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -127,8 +127,8 @@
public static final boolean ENABLE_REMOTE_INPUT =
SystemProperties.getBoolean("debug.enable_remote_input", true);
- public static final boolean ENABLE_CHILD_NOTIFICATIONS = Build.IS_DEBUGGABLE
- && SystemProperties.getBoolean("debug.child_notifs", false);
+ public static final boolean ENABLE_CHILD_NOTIFICATIONS
+ = SystemProperties.getBoolean("debug.child_notifs", true);
protected static final int MSG_SHOW_RECENT_APPS = 1019;
protected static final int MSG_HIDE_RECENT_APPS = 1020;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 5c79c7d..2b93554 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -51,6 +51,8 @@
private static final int COLORED_DIVIDER_ALPHA = 0x7B;
private final LinearInterpolator mLinearInterpolator = new LinearInterpolator();
private final int mNotificationMinHeightLegacy;
+ private final int mMaxHeadsUpHeightLegacy;
+ private final int mMaxHeadsUpHeight;
private final int mNotificationMinHeight;
private final int mNotificationMaxHeight;
private int mRowMinHeight;
@@ -95,6 +97,7 @@
private boolean mIsHeadsUp;
private boolean mLastChronometerRunning = true;
private NotificationHeaderView mNotificationHeader;
+ private NotificationViewWrapper mNotificationHeaderWrapper;
private ViewStub mChildrenContainerStub;
private NotificationGroupManager mGroupManager;
private boolean mChildrenExpanded;
@@ -218,10 +221,15 @@
boolean beforeN = mEntry.targetSdk < Build.VERSION_CODES.N;
int minHeight = customView && beforeN && !mIsSummaryWithChildren ?
mNotificationMinHeightLegacy : mNotificationMinHeight;
+ boolean headsUpCustom = getPrivateLayout().getHeadsUpChild() != null &&
+ getPrivateLayout().getHeadsUpChild().getId()
+ != com.android.internal.R.id.status_bar_latest_event_content;
+ int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
+ : mMaxHeadsUpHeight;
mRowMinHeight = minHeight;
mMaxViewHeight = mNotificationMaxHeight;
- mPrivateLayout.setSmallHeight(mRowMinHeight);
- mPublicLayout.setSmallHeight(mRowMinHeight);
+ mPrivateLayout.setHeights(mRowMinHeight, headsUpheight);
+ mPublicLayout.setHeights(mRowMinHeight, headsUpheight);
}
public StatusBarNotification getStatusBarNotification() {
@@ -385,6 +393,9 @@
}
public int getHeadsUpHeight() {
+ if (mIsSummaryWithChildren) {
+ return mChildrenContainer.getIntrinsicHeight();
+ }
return mHeadsUpHeight;
}
@@ -462,6 +473,10 @@
R.dimen.notification_min_height);
mNotificationMaxHeight = getResources().getDimensionPixelSize(
R.dimen.notification_max_height);
+ mMaxHeadsUpHeightLegacy = getResources().getDimensionPixelSize(
+ R.dimen.notification_max_heads_up_height_legacy);
+ mMaxHeadsUpHeight = getResources().getDimensionPixelSize(
+ R.dimen.notification_max_heads_up_height);
}
/**
@@ -570,6 +585,10 @@
if (showing != null) {
showing.setDark(dark, fade, delay);
}
+ if (mIsSummaryWithChildren) {
+ mChildrenContainer.setDark(dark, fade, delay);
+ mNotificationHeaderWrapper.setDark(dark, fade, delay);
+ }
}
public boolean isExpandable() {
@@ -967,9 +986,12 @@
com.android.internal.R.id.expand_button);
expandButton.setVisibility(VISIBLE);
mNotificationHeader.setOnClickListener(mExpandClickListener);
+ mNotificationHeaderWrapper = NotificationViewWrapper.wrap(getContext(),
+ mNotificationHeader);
addView(mNotificationHeader);
} else {
header.reapply(getContext(), mNotificationHeader);
+ mNotificationHeaderWrapper.notifyContentUpdated();
}
updateHeaderExpandButton();
updateChildrenHeaderAppearance();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index da01d54..2944c4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -52,7 +52,6 @@
private static final int VISIBLE_TYPE_SINGLELINE = 3;
private final Rect mClipBounds = new Rect();
- private final int mHeadsUpHeight;
private final int mRoundRectRadius;
private final Interpolator mLinearInterpolator = new LinearInterpolator();
private final boolean mRoundRectClippingEnabled;
@@ -77,6 +76,7 @@
private boolean mShowingLegacyBackground;
private boolean mIsChildInGroup;
private int mSmallHeight;
+ private int mHeadsUpHeight;
private StatusBarNotification mStatusBarNotification;
private NotificationGroupManager mGroupManager;
@@ -103,7 +103,6 @@
super(context, attrs);
mHybridViewManager = new HybridNotificationViewManager(getContext(), this);
mFadePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
- mHeadsUpHeight = getResources().getDimensionPixelSize(R.dimen.notification_mid_height);
mRoundRectRadius = getResources().getDimensionPixelSize(
R.dimen.notification_material_rounded_rect_radius);
mRoundRectClippingEnabled = getResources().getBoolean(
@@ -112,8 +111,9 @@
setOutlineProvider(mOutlineProvider);
}
- public void setSmallHeight(int smallHeight) {
+ public void setHeights(int smallHeight, int headsUpMaxHeight) {
mSmallHeight = smallHeight;
+ mHeadsUpHeight = headsUpMaxHeight;
}
@Override
@@ -150,7 +150,7 @@
ViewGroup.LayoutParams layoutParams = mHeadsUpChild.getLayoutParams();
if (layoutParams.height >= 0) {
// An actual height is set
- size = Math.min(maxSize, layoutParams.height);
+ size = Math.min(size, layoutParams.height);
}
mHeadsUpChild.measure(widthMeasureSpec,
MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST));
@@ -283,10 +283,10 @@
}
public int getMaxHeight() {
- if (mIsHeadsUp && mHeadsUpChild != null) {
- return mHeadsUpChild.getHeight();
- } else if (mExpandedChild != null) {
+ if (mExpandedChild != null) {
return mExpandedChild.getHeight();
+ } else if (mIsHeadsUp && mHeadsUpChild != null) {
+ return mHeadsUpChild.getHeight();
}
return mSmallHeight;
}
@@ -457,6 +457,9 @@
if (mDark == dark || mContractedChild == null) return;
mDark = dark;
mContractedWrapper.setDark(dark && !mShowingLegacyBackground, fade, delay);
+ if (mSingleLineView != null) {
+ mSingleLineView.setDark(dark, fade, delay);
+ }
}
public void setHeadsUp(boolean headsUp) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderViewWrapper.java
new file mode 100644
index 0000000..ddad2e0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderViewWrapper.java
@@ -0,0 +1,239 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
+import android.view.NotificationHeaderView;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+import com.android.systemui.ViewInvertHelper;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
+
+import java.util.ArrayList;
+
+/**
+ * Wraps a notification header view.
+ */
+public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
+
+ private final ColorMatrix mGrayscaleColorMatrix = new ColorMatrix();
+ private final PorterDuffColorFilter mIconColorFilter = new PorterDuffColorFilter(
+ 0, PorterDuff.Mode.SRC_ATOP);
+ private final int mIconDarkAlpha;
+ private final int mIconDarkColor = 0xffffffff;
+ protected final Interpolator mLinearOutSlowInInterpolator;
+ protected final ViewInvertHelper mInvertHelper;
+
+ protected int mColor;
+ private ImageView mIcon;
+
+ private ImageView mExpandButton;
+ private NotificationHeaderView mNotificationHeader;
+
+ protected NotificationHeaderViewWrapper(Context ctx, View view) {
+ super(view);
+ mIconDarkAlpha = ctx.getResources().getInteger(R.integer.doze_small_icon_alpha);
+ mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(ctx,
+ android.R.interpolator.linear_out_slow_in);
+ mInvertHelper = new ViewInvertHelper(ctx, NotificationPanelView.DOZE_ANIMATION_DURATION);
+ resolveHeaderViews();
+ }
+
+ protected void resolveHeaderViews() {
+ mIcon = (ImageView) mView.findViewById(com.android.internal.R.id.icon);
+ mExpandButton = (ImageView) mView.findViewById(com.android.internal.R.id.expand_button);
+ mColor = resolveColor(mExpandButton);
+ mNotificationHeader = (NotificationHeaderView) mView.findViewById(
+ com.android.internal.R.id.notification_header);
+ for (int i = 0; i < mNotificationHeader.getChildCount(); i++) {
+ View child = mNotificationHeader.getChildAt(i);
+ if (child != mIcon) {
+ mInvertHelper.addTarget(child);
+ }
+ }
+ }
+
+ private int resolveColor(ImageView icon) {
+ if (icon != null && icon.getDrawable() != null) {
+ ColorFilter filter = icon.getDrawable().getColorFilter();
+ if (filter instanceof PorterDuffColorFilter) {
+ return ((PorterDuffColorFilter) filter).getColor();
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public void notifyContentUpdated() {
+ mInvertHelper.clearTargets();
+ // Reinspect the notification.
+ resolveHeaderViews();
+ }
+
+ @Override
+ public void setDark(boolean dark, boolean fade, long delay) {
+ if (fade) {
+ mInvertHelper.fade(dark, delay);
+ } else {
+ mInvertHelper.update(dark);
+ }
+ if (mIcon != null) {
+ boolean hadColorFilter = mNotificationHeader.getOriginalIconColor()
+ != NotificationHeaderView.NO_COLOR;
+ if (fade) {
+ if (hadColorFilter) {
+ fadeIconColorFilter(mIcon, dark, delay);
+ fadeIconAlpha(mIcon, dark, delay);
+ } else {
+ fadeGrayscale(mIcon, dark, delay);
+ }
+ } else {
+ if (hadColorFilter) {
+ updateIconColorFilter(mIcon, dark);
+ updateIconAlpha(mIcon, dark);
+ } else {
+ updateGrayscale(mIcon, dark);
+ }
+ }
+ }
+ }
+
+ protected void startIntensityAnimation(ValueAnimator.AnimatorUpdateListener updateListener,
+ boolean dark, long delay, Animator.AnimatorListener listener) {
+ float startIntensity = dark ? 0f : 1f;
+ float endIntensity = dark ? 1f : 0f;
+ ValueAnimator animator = ValueAnimator.ofFloat(startIntensity, endIntensity);
+ animator.addUpdateListener(updateListener);
+ animator.setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
+ animator.setInterpolator(mLinearOutSlowInInterpolator);
+ animator.setStartDelay(delay);
+ if (listener != null) {
+ animator.addListener(listener);
+ }
+ animator.start();
+ }
+
+ private void fadeIconColorFilter(final ImageView target, boolean dark, long delay) {
+ startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ updateIconColorFilter(target, (Float) animation.getAnimatedValue());
+ }
+ }, dark, delay, null /* listener */);
+ }
+
+ private void fadeIconAlpha(final ImageView target, boolean dark, long delay) {
+ startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float t = (float) animation.getAnimatedValue();
+ target.setImageAlpha((int) (255 * (1f - t) + mIconDarkAlpha * t));
+ }
+ }, dark, delay, null /* listener */);
+ }
+
+ protected void fadeGrayscale(final ImageView target, final boolean dark, long delay) {
+ startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ updateGrayscaleMatrix((float) animation.getAnimatedValue());
+ target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
+ }
+ }, dark, delay, new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!dark) {
+ target.setColorFilter(null);
+ }
+ }
+ });
+ }
+
+ private void updateIconColorFilter(ImageView target, boolean dark) {
+ updateIconColorFilter(target, dark ? 1f : 0f);
+ }
+
+ private void updateIconColorFilter(ImageView target, float intensity) {
+ int color = interpolateColor(mColor, mIconDarkColor, intensity);
+ mIconColorFilter.setColor(color);
+ Drawable iconDrawable = target.getDrawable();
+
+ // Also, the notification might have been modified during the animation, so background
+ // might be null here.
+ if (iconDrawable != null) {
+ iconDrawable.mutate().setColorFilter(mIconColorFilter);
+ }
+ }
+
+ private void updateIconAlpha(ImageView target, boolean dark) {
+ target.setImageAlpha(dark ? mIconDarkAlpha : 255);
+ }
+
+ protected void updateGrayscale(ImageView target, boolean dark) {
+ if (dark) {
+ updateGrayscaleMatrix(1f);
+ target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
+ } else {
+ target.setColorFilter(null);
+ }
+ }
+
+ @Override
+ public void updateExpandability(boolean expandable, View.OnClickListener onClickListener) {
+ mExpandButton.setVisibility(expandable ? View.VISIBLE : View.GONE);
+ mNotificationHeader.setOnClickListener(expandable ? onClickListener : null);
+ }
+
+ private void updateGrayscaleMatrix(float intensity) {
+ mGrayscaleColorMatrix.setSaturation(1 - intensity);
+ }
+
+ private static int interpolateColor(int source, int target, float t) {
+ int aSource = Color.alpha(source);
+ int rSource = Color.red(source);
+ int gSource = Color.green(source);
+ int bSource = Color.blue(source);
+ int aTarget = Color.alpha(target);
+ int rTarget = Color.red(target);
+ int gTarget = Color.green(target);
+ int bTarget = Color.blue(target);
+ return Color.argb(
+ (int) (aSource * (1f - t) + aTarget * t),
+ (int) (rSource * (1f - t) + rTarget * t),
+ (int) (gSource * (1f - t) + gTarget * t),
+ (int) (bSource * (1f - t) + bTarget * t));
+ }
+
+ @Override
+ public NotificationHeaderView getNotificationHeader() {
+ return mNotificationHeader;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
index fb0a419..77e8c55 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
@@ -16,74 +16,31 @@
package com.android.systemui.statusbar;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.graphics.Color;
-import android.graphics.ColorFilter;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.text.TextUtils;
-import android.view.MotionEvent;
-import android.view.NotificationHeaderView;
import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
import android.widget.ImageView;
import android.widget.ProgressBar;
-import android.widget.TextView;
-
-import com.android.systemui.R;
-import com.android.systemui.ViewInvertHelper;
-import com.android.systemui.statusbar.phone.NotificationPanelView;
-
-import java.util.ArrayList;
/**
* Wraps a notification view inflated from a template.
*/
-public class NotificationTemplateViewWrapper extends NotificationViewWrapper {
+public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapper {
- private final ColorMatrix mGrayscaleColorMatrix = new ColorMatrix();
- private final PorterDuffColorFilter mIconColorFilter = new PorterDuffColorFilter(
- 0, PorterDuff.Mode.SRC_ATOP);
- private final int mIconDarkAlpha;
- private final int mIconDarkColor = 0xffffffff;
- private final int mDarkProgressTint = 0xffffffff;
- private final Interpolator mLinearOutSlowInInterpolator;
+ private static final int mDarkProgressTint = 0xffffffff;
- private int mColor;
- private ViewInvertHelper mInvertHelper;
- private ImageView mIcon;
protected ImageView mPicture;
-
- private ImageView mExpandButton;
- private NotificationHeaderView mNotificationHeader;
private ProgressBar mProgressBar;
protected NotificationTemplateViewWrapper(Context ctx, View view) {
- super(view);
- mIconDarkAlpha = ctx.getResources().getInteger(R.integer.doze_small_icon_alpha);
- mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(ctx,
- android.R.interpolator.linear_out_slow_in);
-
- resolveViews();
+ super(ctx, view);
+ resolveTemplateViews();
}
- private void resolveViews() {
+ private void resolveTemplateViews() {
View mainColumn = mView.findViewById(com.android.internal.R.id.notification_main_column);
- mIcon = (ImageView) mView.findViewById(com.android.internal.R.id.icon);
mPicture = (ImageView) mView.findViewById(com.android.internal.R.id.right_icon);
- mExpandButton = (ImageView) mView.findViewById(com.android.internal.R.id.expand_button);
- mColor = resolveColor(mExpandButton);
final View progress = mView.findViewById(com.android.internal.R.id.progress);
if (progress instanceof ProgressBar) {
mProgressBar = (ProgressBar) progress;
@@ -91,30 +48,9 @@
// It's still a viewstub
mProgressBar = null;
}
- mNotificationHeader = (NotificationHeaderView) mView.findViewById(
- com.android.internal.R.id.notification_header);
- ArrayList<View> viewsToInvert = new ArrayList<>();
if (mainColumn != null) {
- viewsToInvert.add(mainColumn);
+ mInvertHelper.addTarget(mainColumn);
}
- for (int i = 0; i < mNotificationHeader.getChildCount(); i++) {
- View child = mNotificationHeader.getChildAt(i);
- if (child != mIcon) {
- viewsToInvert.add(child);
- }
- }
- mInvertHelper = new ViewInvertHelper(viewsToInvert,
- NotificationPanelView.DOZE_ANIMATION_DURATION);
- }
-
- private int resolveColor(ImageView icon) {
- if (icon != null && icon.getDrawable() != null) {
- ColorFilter filter = icon.getDrawable().getColorFilter();
- if (filter instanceof PorterDuffColorFilter) {
- return ((PorterDuffColorFilter) filter).getColor();
- }
- }
- return 0;
}
@Override
@@ -122,37 +58,12 @@
super.notifyContentUpdated();
// Reinspect the notification.
- resolveViews();
+ resolveTemplateViews();
}
@Override
public void setDark(boolean dark, boolean fade, long delay) {
- if (mInvertHelper != null) {
- if (fade) {
- mInvertHelper.fade(dark, delay);
- } else {
- mInvertHelper.update(dark);
- }
- }
- if (mIcon != null) {
- boolean hadColorFilter = mNotificationHeader.getOriginalIconColor()
- != NotificationHeaderView.NO_COLOR;
- if (fade) {
- if (hadColorFilter) {
- fadeIconColorFilter(mIcon, dark, delay);
- fadeIconAlpha(mIcon, dark, delay);
- } else {
- fadeGrayscale(mIcon, dark, delay);
- }
- } else {
- if (hadColorFilter) {
- updateIconColorFilter(mIcon, dark);
- updateIconAlpha(mIcon, dark);
- } else {
- updateGrayscale(mIcon, dark);
- }
- }
- }
+ super.setDark(dark, fade, delay);
setPictureGrayscale(dark, fade, delay);
setProgressBarDark(dark, fade, delay);
}
@@ -197,96 +108,6 @@
}
}
- private void startIntensityAnimation(ValueAnimator.AnimatorUpdateListener updateListener,
- boolean dark, long delay, Animator.AnimatorListener listener) {
- float startIntensity = dark ? 0f : 1f;
- float endIntensity = dark ? 1f : 0f;
- ValueAnimator animator = ValueAnimator.ofFloat(startIntensity, endIntensity);
- animator.addUpdateListener(updateListener);
- animator.setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
- animator.setInterpolator(mLinearOutSlowInInterpolator);
- animator.setStartDelay(delay);
- if (listener != null) {
- animator.addListener(listener);
- }
- animator.start();
- }
-
- private void fadeIconColorFilter(final ImageView target, boolean dark, long delay) {
- startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- updateIconColorFilter(target, (Float) animation.getAnimatedValue());
- }
- }, dark, delay, null /* listener */);
- }
-
- private void fadeIconAlpha(final ImageView target, boolean dark, long delay) {
- startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float t = (float) animation.getAnimatedValue();
- target.setImageAlpha((int) (255 * (1f - t) + mIconDarkAlpha * t));
- }
- }, dark, delay, null /* listener */);
- }
-
- protected void fadeGrayscale(final ImageView target, final boolean dark, long delay) {
- startIntensityAnimation(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- updateGrayscaleMatrix((float) animation.getAnimatedValue());
- target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
- }
- }, dark, delay, new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- if (!dark) {
- target.setColorFilter(null);
- }
- }
- });
- }
-
- private void updateIconColorFilter(ImageView target, boolean dark) {
- updateIconColorFilter(target, dark ? 1f : 0f);
- }
-
- private void updateIconColorFilter(ImageView target, float intensity) {
- int color = interpolateColor(mColor, mIconDarkColor, intensity);
- mIconColorFilter.setColor(color);
- Drawable iconDrawable = target.getDrawable();
-
- // Also, the notification might have been modified during the animation, so background
- // might be null here.
- if (iconDrawable != null) {
- iconDrawable.mutate().setColorFilter(mIconColorFilter);
- }
- }
-
- private void updateIconAlpha(ImageView target, boolean dark) {
- target.setImageAlpha(dark ? mIconDarkAlpha : 255);
- }
-
- protected void updateGrayscale(ImageView target, boolean dark) {
- if (dark) {
- updateGrayscaleMatrix(1f);
- target.setColorFilter(new ColorMatrixColorFilter(mGrayscaleColorMatrix));
- } else {
- target.setColorFilter(null);
- }
- }
-
- @Override
- public void updateExpandability(boolean expandable, View.OnClickListener onClickListener) {
- mExpandButton.setVisibility(expandable ? View.VISIBLE : View.GONE);
- mNotificationHeader.setOnClickListener(expandable ? onClickListener : null);
- }
-
- private void updateGrayscaleMatrix(float intensity) {
- mGrayscaleColorMatrix.setSaturation(1 - intensity);
- }
-
private static int interpolateColor(int source, int target, float t) {
int aSource = Color.alpha(source);
int rSource = Color.red(source);
@@ -302,9 +123,4 @@
(int) (gSource * (1f - t) + gTarget * t),
(int) (bSource * (1f - t) + bTarget * t));
}
-
- @Override
- public NotificationHeaderView getNotificationHeader() {
- return mNotificationHeader;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
index 119d57b..61499de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
@@ -26,16 +26,13 @@
*/
public abstract class NotificationViewWrapper {
- private static final String TAG_BIG_MEDIA_NARROW = "bigMediaNarrow";
- private static final String TAG_MEDIA = "media";
- private static final String TAG_BIG_PICTURE = "bigPicture";
-
protected final View mView;
- private boolean mSubTextVisible = true;
public static NotificationViewWrapper wrap(Context ctx, View v) {
if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
return new NotificationTemplateViewWrapper(ctx, v);
+ } else if (v instanceof NotificationHeaderView) {
+ return new NotificationHeaderViewWrapper(ctx, v);
} else {
return new NotificationCustomViewWrapper(v);
}
@@ -57,9 +54,7 @@
/**
* Notifies this wrapper that the content of the view might have changed.
*/
- public void notifyContentUpdated() {
- setSubTextVisible(mSubTextVisible);
- }
+ public void notifyContentUpdated() {};
/**
* @return true if this template might need to be clipped with a round rect to make it look
@@ -70,14 +65,6 @@
}
/**
- * Change the subTextVisibility
- * @param visible Should the subtext be visible
- */
- public void setSubTextVisible(boolean visible) {
- mSubTextVisible = visible;
- }
-
- /**
* Update the appearance of the expand button.
*
* @param expandable should this view be expandable
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
index fafea98..5fb6fec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
@@ -23,6 +23,8 @@
import com.android.keyguard.AlphaOptimizedLinearLayout;
import com.android.systemui.R;
+import com.android.systemui.ViewInvertHelper;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
/**
* A hybrid view which may contain information about one ore more notifications.
@@ -31,6 +33,7 @@
protected TextView mTitleView;
protected TextView mTextView;
+ private ViewInvertHelper mInvertHelper;
public HybridNotificationView(Context context) {
this(context, null);
@@ -54,6 +57,7 @@
super.onFinishInflate();
mTitleView = (TextView) findViewById(R.id.notification_title);
mTextView = (TextView) findViewById(R.id.notification_text);
+ mInvertHelper = new ViewInvertHelper(this, NotificationPanelView.DOZE_ANIMATION_DURATION);
}
public void bind(CharSequence title) {
@@ -65,4 +69,8 @@
mTextView.setText(text);
requestLayout();
}
+
+ public void setDark(boolean dark, boolean fade, long delay) {
+ mInvertHelper.setInverted(dark, fade, delay);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index 9015a0e..2b71ce9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -23,9 +23,11 @@
import android.view.ViewGroup;
import com.android.systemui.R;
+import com.android.systemui.ViewInvertHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.HybridNotificationViewManager;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
import java.util.ArrayList;
import java.util.List;
@@ -49,6 +51,7 @@
private final int mNotificatonTopPadding;
private final HybridNotificationViewManager mHybridViewManager;
private final float mCollapsedBottompadding;
+ private ViewInvertHelper mOverflowInvertHelper;
private boolean mChildrenExpanded;
private ExpandableNotificationRow mNotificationParent;
private HybridNotificationView mGroupOverflowContainer;
@@ -172,12 +175,17 @@
if (hasOverflow) {
mGroupOverflowContainer = mHybridViewManager.bindFromNotificationGroup(
mGroupOverflowContainer, mChildren, lastVisibleIndex + 1);
+ if (mOverflowInvertHelper == null) {
+ mOverflowInvertHelper= new ViewInvertHelper(mGroupOverflowContainer,
+ NotificationPanelView.DOZE_ANIMATION_DURATION);
+ }
if (mGroupOverFlowState == null) {
mGroupOverFlowState = new ViewState();
}
} else if (mGroupOverflowContainer != null) {
removeView(mGroupOverflowContainer);
mGroupOverflowContainer = null;
+ mOverflowInvertHelper = null;
mGroupOverFlowState = null;
}
}
@@ -324,7 +332,7 @@
if (!likeCollapsed && (mChildrenExpanded || mNotificationParent.isUserLocked())) {
return NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED;
}
- if (mNotificationParent.isExpanded()) {
+ if (mNotificationParent.isExpanded() || mNotificationParent.isHeadsUp()) {
return NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED;
}
return NUMBER_OF_CHILDREN_WHEN_COLLAPSED;
@@ -387,16 +395,17 @@
boolean withDelays, long baseDelay, long duration) {
int childCount = mChildren.size();
ViewState tmpState = new ViewState();
- int notGoneIndex = 0;
- for (int i = 0; i < childCount; i++) {
+ int delayIndex = 0;
+ int maxAllowChildCount = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
+ for (int i = childCount - 1; i >= 0; i--) {
ExpandableNotificationRow child = mChildren.get(i);
StackViewState viewState = state.getViewStateForView(child);
int difference = Math.min(StackStateAnimator.DELAY_EFFECT_MAX_INDEX_DIFFERENCE_CHILDREN,
- notGoneIndex + 1);
+ delayIndex);
long delay = withDelays
? difference * StackStateAnimator.ANIMATION_DELAY_PER_ELEMENT_EXPAND_CHILDREN
: 0;
- delay += baseDelay;
+ delay = (long) (delay * (mChildrenExpanded ? 1.0f : 0.5f) + baseDelay);
stateAnimator.startStackAnimations(child, viewState, state, -1, delay);
// layout the divider
@@ -405,11 +414,13 @@
tmpState.yTranslation = viewState.yTranslation - mDividerHeight;
tmpState.alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
stateAnimator.startViewAnimations(divider, tmpState, delay, duration);
-
- notGoneIndex++;
+ if (i < maxAllowChildCount) {
+ delayIndex++;
+ }
}
if (mGroupOverflowContainer != null) {
- stateAnimator.startViewAnimations(mGroupOverflowContainer, mGroupOverFlowState, -1, 0);
+ stateAnimator.startViewAnimations(mGroupOverflowContainer, mGroupOverFlowState,
+ baseDelay, duration);
}
}
@@ -443,4 +454,10 @@
public int getMinHeight() {
return getIntrinsicHeight(getMaxAllowedVisibleChildren(true /* forceCollapsed */));
}
+
+ public void setDark(boolean dark, boolean fade, long delay) {
+ if (mGroupOverflowContainer != null) {
+ mOverflowInvertHelper.setInverted(dark, fade, delay);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 960fb4b..5f57a76 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1233,14 +1233,6 @@
}
}
- // direct-callback alarms must be wakeup alarms (otherwise they should just be
- // posting work to a Handler)
- if (directReceiver != null) {
- if (type != RTC_WAKEUP && type != ELAPSED_REALTIME_WAKEUP) {
- throw new IllegalArgumentException("Only wakeup alarms can use AlarmReceivers");
- }
- }
-
if (workSource != null) {
getContext().enforcePermission(
android.Manifest.permission.UPDATE_DEVICE_STATS,
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 33f39bc..c83012c 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -159,8 +159,8 @@
public class NotificationManagerService extends SystemService {
static final String TAG = "NotificationService";
static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
- public static final boolean ENABLE_CHILD_NOTIFICATIONS = Build.IS_DEBUGGABLE
- && SystemProperties.getBoolean("debug.child_notifs", false);
+ public static final boolean ENABLE_CHILD_NOTIFICATIONS
+ = SystemProperties.getBoolean("debug.child_notifs", true);
static final int MAX_PACKAGE_NOTIFICATIONS = 50;