diff options
88 files changed, 1714 insertions, 717 deletions
diff --git a/api/current.txt b/api/current.txt index 44df33319b71..67dd3659de53 100644 --- a/api/current.txt +++ b/api/current.txt @@ -2666,6 +2666,7 @@ package android.accessibilityservice { field public static final int GLOBAL_ACTION_POWER_DIALOG = 6; // 0x6 field public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5; // 0x5 field public static final int GLOBAL_ACTION_RECENTS = 3; // 0x3 + field public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; // 0x7 field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService"; field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice"; } @@ -19172,7 +19173,6 @@ package android.location { method public short getLeapSecond(); method public long getTimeInNs(); method public double getTimeUncertaintyInNs(); - method public byte getType(); method public boolean hasBiasInNs(); method public boolean hasBiasUncertaintyInNs(); method public boolean hasDriftInNsPerSec(); @@ -19198,17 +19198,10 @@ package android.location { method public void setLeapSecond(short); method public void setTimeInNs(long); method public void setTimeUncertaintyInNs(double); - method public void setType(byte); method public void writeToParcel(android.os.Parcel, int); - field public static final byte CLOCK_TYPE_GPS_TIME = 2; // 0x2 - field public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1; // 0x1 - field public static final byte CLOCK_TYPE_UNKNOWN = 0; // 0x0 field public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR; } - public static abstract class GnssClock.GnssClockType implements java.lang.annotation.Annotation { - } - public final class GnssMeasurement implements android.os.Parcelable { method public int describeContents(); method public double getAccumulatedDeltaRangeInMeters(); @@ -44085,6 +44078,7 @@ package android.view.accessibility { field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4 field public static final int TYPE_APPLICATION = 1; // 0x1 field public static final int TYPE_INPUT_METHOD = 2; // 0x2 + field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5 field public static final int TYPE_SYSTEM = 3; // 0x3 } diff --git a/api/system-current.txt b/api/system-current.txt index 79d0cd74a241..0629fe95181a 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -2768,6 +2768,7 @@ package android.accessibilityservice { field public static final int GLOBAL_ACTION_POWER_DIALOG = 6; // 0x6 field public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5; // 0x5 field public static final int GLOBAL_ACTION_RECENTS = 3; // 0x3 + field public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; // 0x7 field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService"; field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice"; } @@ -20361,7 +20362,6 @@ package android.location { method public short getLeapSecond(); method public long getTimeInNs(); method public double getTimeUncertaintyInNs(); - method public byte getType(); method public boolean hasBiasInNs(); method public boolean hasBiasUncertaintyInNs(); method public boolean hasDriftInNsPerSec(); @@ -20387,17 +20387,10 @@ package android.location { method public void setLeapSecond(short); method public void setTimeInNs(long); method public void setTimeUncertaintyInNs(double); - method public void setType(byte); method public void writeToParcel(android.os.Parcel, int); - field public static final byte CLOCK_TYPE_GPS_TIME = 2; // 0x2 - field public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1; // 0x1 - field public static final byte CLOCK_TYPE_UNKNOWN = 0; // 0x0 field public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR; } - public static abstract class GnssClock.GnssClockType implements java.lang.annotation.Annotation { - } - public final class GnssMeasurement implements android.os.Parcelable { method public int describeContents(); method public double getAccumulatedDeltaRangeInMeters(); @@ -46869,6 +46862,7 @@ package android.view.accessibility { field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4 field public static final int TYPE_APPLICATION = 1; // 0x1 field public static final int TYPE_INPUT_METHOD = 2; // 0x2 + field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5 field public static final int TYPE_SYSTEM = 3; // 0x3 } diff --git a/api/test-current.txt b/api/test-current.txt index 4b62e28b9553..ae539d813ba3 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -2666,6 +2666,7 @@ package android.accessibilityservice { field public static final int GLOBAL_ACTION_POWER_DIALOG = 6; // 0x6 field public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5; // 0x5 field public static final int GLOBAL_ACTION_RECENTS = 3; // 0x3 + field public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; // 0x7 field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService"; field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice"; } @@ -19180,7 +19181,6 @@ package android.location { method public short getLeapSecond(); method public long getTimeInNs(); method public double getTimeUncertaintyInNs(); - method public byte getType(); method public boolean hasBiasInNs(); method public boolean hasBiasUncertaintyInNs(); method public boolean hasDriftInNsPerSec(); @@ -19206,17 +19206,10 @@ package android.location { method public void setLeapSecond(short); method public void setTimeInNs(long); method public void setTimeUncertaintyInNs(double); - method public void setType(byte); method public void writeToParcel(android.os.Parcel, int); - field public static final byte CLOCK_TYPE_GPS_TIME = 2; // 0x2 - field public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1; // 0x1 - field public static final byte CLOCK_TYPE_UNKNOWN = 0; // 0x0 field public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR; } - public static abstract class GnssClock.GnssClockType implements java.lang.annotation.Annotation { - } - public final class GnssMeasurement implements android.os.Parcelable { method public int describeContents(); method public double getAccumulatedDeltaRangeInMeters(); @@ -44102,6 +44095,7 @@ package android.view.accessibility { field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4 field public static final int TYPE_APPLICATION = 1; // 0x1 field public static final int TYPE_INPUT_METHOD = 2; // 0x2 + field public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; // 0x5 field public static final int TYPE_SYSTEM = 3; // 0x3 } diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 24449d43b350..4025553b7674 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -1490,7 +1490,7 @@ public final class Pm { System.err.println(" -i: specify the installer package name"); System.err.println(" -s: install application on sdcard"); System.err.println(" -f: install application on internal flash"); - System.err.println(" -d: allow version code downgrade"); + System.err.println(" -d: allow version code downgrade (debuggable packages only)"); System.err.println(" -p: partial application install"); System.err.println(" -g: grant all runtime permissions"); System.err.println(" -S: size in bytes of entire session"); diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 4bc6b97c834d..fb5f5b9e1efc 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -334,7 +334,7 @@ public abstract class AccessibilityService extends Service { public static final int GLOBAL_ACTION_HOME = 2; /** - * Action to open the recent apps. + * Action to toggle showing the overview of recent apps */ public static final int GLOBAL_ACTION_RECENTS = 3; @@ -353,6 +353,11 @@ public abstract class AccessibilityService extends Service { */ public static final int GLOBAL_ACTION_POWER_DIALOG = 6; + /** + * Action to toggle docking the current app's window + */ + public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; + private static final String LOG_TAG = "AccessibilityService"; /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index eaff1acf1468..cb45deb54922 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -58,6 +58,7 @@ import android.text.TextUtils; import android.util.AndroidException; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.LocaleList; import android.util.Log; import com.android.internal.util.ArrayUtils; @@ -2071,6 +2072,8 @@ public final class Settings { if (outConfig.fontScale < 0) { outConfig.fontScale = 1; } + outConfig.setLocales(LocaleList.forLanguageTags( + Settings.System.getStringForUser(cr, SYSTEM_LOCALES, userHandle))); } /** @@ -2079,6 +2082,9 @@ public final class Settings { */ public static void clearConfiguration(Configuration inoutConfig) { inoutConfig.fontScale = 0; + if (!inoutConfig.userSetLocale) { + inoutConfig.setLocales(LocaleList.getEmptyLocaleList()); + } } /** @@ -2096,12 +2102,15 @@ public final class Settings { /** @hide */ public static boolean putConfigurationForUser(ContentResolver cr, Configuration config, int userHandle) { - return Settings.System.putFloatForUser(cr, FONT_SCALE, config.fontScale, userHandle); + return Settings.System.putFloatForUser(cr, FONT_SCALE, config.fontScale, userHandle) && + Settings.System.putStringForUser( + cr, SYSTEM_LOCALES, config.getLocales().toLanguageTags(), userHandle); } /** @hide */ public static boolean hasInterestingConfigurationChanges(int changes) { - return (changes&ActivityInfo.CONFIG_FONT_SCALE) != 0; + return (changes & ActivityInfo.CONFIG_FONT_SCALE) != 0 || + (changes & ActivityInfo.CONFIG_LOCALE) != 0; } /** @deprecated - Do not use */ @@ -2480,6 +2489,18 @@ public final class Settings { }; /** + * The serialized system locale value. + * + * Do not use this value directory. + * To get system locale, use {@link android.util.LocaleList#getDefault} instead. + * To update system locale, use {@link com.android.internal.app.LocalePicker#updateLocales} + * instead. + * @hide + */ + public static final String SYSTEM_LOCALES = "system_locales"; + + + /** * Name of an application package to be debugged. * * @deprecated Use {@link Global#DEBUG_APP} instead diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java index 367c9fb65770..e79dfcacac29 100644 --- a/core/java/android/text/method/BaseKeyListener.java +++ b/core/java/android/text/method/BaseKeyListener.java @@ -437,6 +437,7 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener if (handled) { adjustMetaAfterKeypress(content); + return true; } return super.onKeyDown(view, content, keyCode, event); @@ -470,4 +471,3 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener return true; } } - diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java index a75e8a73c145..ad78b686b8de 100644 --- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java +++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java @@ -64,6 +64,12 @@ public final class AccessibilityWindowInfo implements Parcelable { */ public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; + /** + * Window type: A system window used to divide the screen in split-screen mode. + * This type of window is present only in split-screen mode. + */ + public static final int TYPE_SPLIT_SCREEN_DIVIDER = 5; + private static final int UNDEFINED = -1; private static final int BOOLEAN_PROPERTY_ACTIVE = 1 << 0; @@ -551,6 +557,9 @@ public final class AccessibilityWindowInfo implements Parcelable { case TYPE_ACCESSIBILITY_OVERLAY: { return "TYPE_ACCESSIBILITY_OVERLAY"; } + case TYPE_SPLIT_SCREEN_DIVIDER: { + return "TYPE_SPLIT_SCREEN_DIVIDER"; + } default: return "<UNKNOWN>"; } diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 4c81d1ac316b..54b3932dfeb2 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -1632,7 +1632,6 @@ public class PopupWindow { final PopupDecorView decorView = mDecorView; final View contentView = mContentView; - final OnDismissListener dismissListener = mOnDismissListener; final ViewGroup contentHolder; final ViewParent contentParent = contentView.getParent(); @@ -1676,16 +1675,19 @@ public class PopupWindow { new TransitionListenerAdapter() { @Override public void onTransitionEnd(Transition transition) { - dismissImmediate(decorView, contentHolder, - contentView, dismissListener); + dismissImmediate(decorView, contentHolder, contentView); } }); } else { - dismissImmediate(decorView, contentHolder, contentView, dismissListener); + dismissImmediate(decorView, contentHolder, contentView); } // Clears the anchor view. unregisterForViewTreeChanges(); + + if (mOnDismissListener != null) { + mOnDismissListener.onDismiss(); + } } /** @@ -1727,8 +1729,7 @@ public class PopupWindow { * Removes the popup from the window manager and tears down the supporting * view hierarchy, if necessary. */ - private void dismissImmediate(View decorView, ViewGroup contentHolder, - View contentView, OnDismissListener listener) { + private void dismissImmediate(View decorView, ViewGroup contentHolder, View contentView) { // If this method gets called and the decor view doesn't have a parent, // then it was either never added or was already removed. That should // never happen, but it's worth checking to avoid potential crashes. @@ -1745,10 +1746,6 @@ public class PopupWindow { mDecorView = null; mBackgroundView = null; mIsTransitioningToDismiss = false; - - if (mOnDismissListener != null) { - mOnDismissListener.onDismiss(); - } } /** diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java index 6a365e0a6927..b1b019cce869 100644 --- a/core/java/com/android/internal/app/LocalePicker.java +++ b/core/java/com/android/internal/app/LocalePicker.java @@ -275,7 +275,7 @@ public class LocalePicker extends ListFragment { config.setLocales(locales); config.userSetLocale = true; - am.updateConfiguration(config); + am.updatePersistentConfiguration(config); // Trigger the dirty bit for the Settings Provider. BackupManager.dataChanged("com.android.providers.settings"); } catch (RemoteException e) { diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index 08d4fba8b1b8..64c5b8de46a9 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -60,6 +60,7 @@ oneway interface IStatusBar void showRecentApps(boolean triggeredFromAltTab); void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey); void toggleRecentApps(); + void toggleSplitScreen(); void preloadRecentApps(); void cancelPreloadRecentApps(); void showScreenPinningRequest(); diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 8b686b70041d..4be365944982 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -7,7 +7,7 @@ LOCAL_CFLAGS += -U__APPLE__ LOCAL_CFLAGS += -Wno-unused-parameter LOCAL_CFLAGS += -Wno-non-virtual-dtor LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses -LOCAL_CFLAGS += -DHWUI_NEW_OPS +#LOCAL_CFLAGS += -DHWUI_NEW_OPS LOCAL_CPPFLAGS += -Wno-conversion-null ifeq ($(TARGET_ARCH), arm) diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml index a3a311295ca1..ae19150de3c0 100644 --- a/core/res/res/values-television/config.xml +++ b/core/res/res/values-television/config.xml @@ -25,7 +25,7 @@ <bool name="config_defaultWindowFeatureOptionsPanel">false</bool> <!-- Default bounds [left top right bottom] on screen for picture-in-picture windows. --> - <string translatable="false" name="config_defaultPictureInPictureBounds">"1328 54 1808 324"</string> + <string translatable="false" name="config_defaultPictureInPictureBounds">"1420 100 1820 325"</string> <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows, when the PIP is located in center. --> @@ -34,5 +34,4 @@ <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows, when the PIP is shown with Recents. --> <string translatable="false" name="config_pictureInPictureBoundsInRecents">"1480 123 1760 303"</string> - </resources> diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index d05c66a8437c..3b0e7e8c704e 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -898,19 +898,19 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { * @param res the resources used to inflate density-dependent values */ final void updateDensity(Resources res) { - if (mSourceRes != null) { + if (res != null) { mSourceRes = res; - } - // The density may have changed since the last update (if any). Any - // dimension-type attributes will need their default values scaled. - final int targetDensity = Drawable.resolveDensity(res, mDensity); - final int sourceDensity = mDensity; - mDensity = targetDensity; + // The density may have changed since the last update (if any). Any + // dimension-type attributes will need their default values scaled. + final int targetDensity = Drawable.resolveDensity(res, mDensity); + final int sourceDensity = mDensity; + mDensity = targetDensity; - if (sourceDensity != targetDensity) { - mCheckedConstantSize = false; - mCheckedPadding = false; + if (sourceDensity != targetDensity) { + mCheckedConstantSize = false; + mCheckedPadding = false; + } } } diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk index da7b7fb55330..8831bafd43d7 100644 --- a/libs/hwui/Android.mk +++ b/libs/hwui/Android.mk @@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -HWUI_NEW_OPS := true +HWUI_NEW_OPS := false # Enables fine-grained GLES error checking # If set to true, every GLES call is wrapped & error checked diff --git a/location/java/android/location/GnssClock.java b/location/java/android/location/GnssClock.java index 5ba3f2c27a13..3c8a78d4d18d 100644 --- a/location/java/android/location/GnssClock.java +++ b/location/java/android/location/GnssClock.java @@ -16,42 +16,16 @@ package android.location; -import android.annotation.IntDef; import android.os.Parcel; import android.os.Parcelable; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - /** * A class containing a GPS clock timestamp. * It represents a measurement of the GPS receiver's clock. */ public final class GnssClock implements Parcelable { - // The following enumerations must be in sync with the values declared in gps.h - /** The type of the GPS Clock. */ - @Retention(RetentionPolicy.SOURCE) - @IntDef({CLOCK_TYPE_UNKNOWN, CLOCK_TYPE_LOCAL_HW_TIME, CLOCK_TYPE_GPS_TIME}) - public @interface GnssClockType {} - - /** - * The type of the time stored is not available or it is unknown. - */ - public static final byte CLOCK_TYPE_UNKNOWN = 0; - - /** - * The source of the time value reported by this class is the 'Local Hardware Clock'. - */ - public static final byte CLOCK_TYPE_LOCAL_HW_TIME = 1; - - /** - * The source of the time value reported by this class is the 'GPS time' derived from - * satellites (epoch = Jan 6, 1980). - */ - public static final byte CLOCK_TYPE_GPS_TIME = 2; - private static final short HAS_NO_FLAGS = 0; private static final short HAS_LEAP_SECOND = (1<<0); private static final short HAS_TIME_UNCERTAINTY = (1<<1); @@ -65,7 +39,6 @@ public final class GnssClock implements Parcelable { private short mFlags; private short mLeapSecond; - private byte mType; private long mTimeInNs; private double mTimeUncertaintyInNs; private long mFullBiasInNs; @@ -85,7 +58,6 @@ public final class GnssClock implements Parcelable { public void set(GnssClock clock) { mFlags = clock.mFlags; mLeapSecond = clock.mLeapSecond; - mType = clock.mType; mTimeInNs = clock.mTimeInNs; mTimeUncertaintyInNs = clock.mTimeUncertaintyInNs; mFullBiasInNs = clock.mFullBiasInNs; @@ -104,38 +76,6 @@ public final class GnssClock implements Parcelable { } /** - * Gets the type of time reported by {@link #getTimeInNs()}. - */ - @GnssClockType - public byte getType() { - return mType; - } - - /** - * Sets the type of time reported. - */ - public void setType(@GnssClockType byte value) { - mType = value; - } - - /** - * Gets a string representation of the 'type'. - * For internal and logging use only. - */ - private String getTypeString() { - switch (mType) { - case CLOCK_TYPE_UNKNOWN: - return "Unknown"; - case CLOCK_TYPE_GPS_TIME: - return "GpsTime"; - case CLOCK_TYPE_LOCAL_HW_TIME: - return "LocalHwClock"; - default: - return "<Invalid:" + mType + ">"; - } - } - - /** * Returns true if {@link #getLeapSecond()} is available, false otherwise. */ public boolean hasLeapSecond() { @@ -170,10 +110,7 @@ public final class GnssClock implements Parcelable { } /** - * Gets the GPS receiver internal clock value in nanoseconds. - * This can be either the 'local hardware clock' value ({@link #CLOCK_TYPE_LOCAL_HW_TIME}), or the - * current GPS time derived inside GPS receiver ({@link #CLOCK_TYPE_GPS_TIME}). - * {@link #getType()} defines the time reported. + * Gets the GNSS receiver internal clock value in nanoseconds. * * For 'local hardware clock' this value is expected to be monotonically increasing during the * reporting session. The real GPS time can be derived by compensating @@ -241,15 +178,14 @@ public final class GnssClock implements Parcelable { * Gets the difference between hardware clock ({@link #getTimeInNs()}) inside GPS receiver and * the true GPS time since 0000Z, January 6, 1980, in nanoseconds. * - * This value is available if {@link #CLOCK_TYPE_LOCAL_HW_TIME} is set, and GPS receiver has solved - * the clock for GPS time. - * {@link #getBiasUncertaintyInNs()} should be used for quality check. + * This value is available if the receiver has estimated GPS time. If the computed time is for a + * non-GPS constellation, the time offset of that constellation to GPS has to be applied to fill + * this value. The value contains the 'bias uncertainty' {@link #getBiasUncertaintyInNs()} in + * it, and it should be used for quality check. The value is only available if + * {@link #hasFullBiasInNs()} is true. * * The sign of the value is defined by the following equation: - * true time (GPS time) = time_ns + (full_bias_ns + bias_ns) - * - * The reported full bias includes {@link #getBiasUncertaintyInNs()}. - * The value is onl available if {@link #hasFullBiasInNs()} is true. + * local estimate of GPS time = time_ns + (full_bias_ns + bias_ns) */ public long getFullBiasInNs() { return mFullBiasInNs; @@ -423,7 +359,6 @@ public final class GnssClock implements Parcelable { gpsClock.mFlags = (short) parcel.readInt(); gpsClock.mLeapSecond = (short) parcel.readInt(); - gpsClock.mType = parcel.readByte(); gpsClock.mTimeInNs = parcel.readLong(); gpsClock.mTimeUncertaintyInNs = parcel.readDouble(); gpsClock.mFullBiasInNs = parcel.readLong(); @@ -446,7 +381,6 @@ public final class GnssClock implements Parcelable { public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(mFlags); parcel.writeInt(mLeapSecond); - parcel.writeByte(mType); parcel.writeLong(mTimeInNs); parcel.writeDouble(mTimeUncertaintyInNs); parcel.writeLong(mFullBiasInNs); @@ -468,8 +402,6 @@ public final class GnssClock implements Parcelable { final String formatWithUncertainty = " %-15s = %-25s %-26s = %s\n"; StringBuilder builder = new StringBuilder("GnssClock:\n"); - builder.append(String.format(format, "Type", getTypeString())); - builder.append(String.format(format, "LeapSecond", hasLeapSecond() ? mLeapSecond : null)); builder.append(String.format( @@ -498,17 +430,12 @@ public final class GnssClock implements Parcelable { "DriftUncertaintyInNsPerSec", hasDriftUncertaintyInNsPerSec() ? mDriftUncertaintyInNsPerSec : null)); - builder.append(String.format(format, "HardwareClockDiscontinuityCount", - getType() == CLOCK_TYPE_LOCAL_HW_TIME - ? mHardwareClockDiscontinuityCount : null)); - return builder.toString(); } private void initialize() { mFlags = HAS_NO_FLAGS; resetLeapSecond(); - setType(CLOCK_TYPE_UNKNOWN); setTimeInNs(Long.MIN_VALUE); resetTimeUncertaintyInNs(); resetFullBiasInNs(); diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java index a619ab293ded..abdc13c1dfb7 100644 --- a/location/java/android/location/GnssMeasurement.java +++ b/location/java/android/location/GnssMeasurement.java @@ -272,8 +272,9 @@ public final class GnssMeasurement implements Parcelable { /** * Gets the time offset at which the measurement was taken in nanoseconds. - * The reference receiver's time is specified by {@link GnssClock#getTimeInNs()} and should be - * interpreted in the same way as indicated by {@link GnssClock#getType()}. + * + * The reference receiver's time from which this is offset is specified by + * {@link GnssClock#getTimeInNs()}. * * The sign of this value is given by the following equation: * measurement time = time_ns + time_offset_ns diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java index 1c032fac00de..a57805512a7e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java @@ -18,6 +18,7 @@ package com.android.settingslib.drawer; import android.annotation.LayoutRes; import android.annotation.Nullable; import android.app.Activity; +import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -235,20 +236,24 @@ public class SettingsDrawerActivity extends Activity { Intent.FLAG_ACTIVITY_CLEAR_TASK)); return true; } - int numUserHandles = tile.userHandle.size(); - if (numUserHandles > 1) { - ProfileSelectDialog.show(getFragmentManager(), tile); - return false; - } else if (numUserHandles == 1) { - // Show menu on top level items. - tile.intent.putExtra(EXTRA_SHOW_MENU, true); - tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); - startActivityAsUser(tile.intent, tile.userHandle.get(0)); - } else { - // Show menu on top level items. - tile.intent.putExtra(EXTRA_SHOW_MENU, true); - tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); - startActivity(tile.intent); + try { + int numUserHandles = tile.userHandle.size(); + if (numUserHandles > 1) { + ProfileSelectDialog.show(getFragmentManager(), tile); + return false; + } else if (numUserHandles == 1) { + // Show menu on top level items. + tile.intent.putExtra(EXTRA_SHOW_MENU, true); + tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + startActivityAsUser(tile.intent, tile.userHandle.get(0)); + } else { + // Show menu on top level items. + tile.intent.putExtra(EXTRA_SHOW_MENU, true); + tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + startActivity(tile.intent); + } + } catch (ActivityNotFoundException e) { + Log.w(TAG, "Couldn't find tile " + tile.intent, e); } return true; } diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index 20aca0efc6ad..85d127c833bf 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -302,8 +302,7 @@ public class BugreportProgressService extends Service { } final String action = intent.getAction(); final int pid = intent.getIntExtra(EXTRA_PID, 0); - // TODO: temporarily using pid as id until test cases and dumpstate are changed. - final int id = intent.getIntExtra(EXTRA_ID, pid); + final int id = intent.getIntExtra(EXTRA_ID, 0); final int max = intent.getIntExtra(EXTRA_MAX, -1); final String name = intent.getStringExtra(EXTRA_NAME); @@ -474,7 +473,10 @@ public class BugreportProgressService extends Service { + info + ")"); return; } - Log.v(TAG, "Sending 'Progress' notification for id " + info.id + ": " + percentText); + if (DEBUG) { + Log.d(TAG, "Sending 'Progress' notification for id " + info.id + "(pid " + info.pid + + "): " + percentText); + } NotificationManager.from(mContext).notify(TAG, info.id, notification); } @@ -541,7 +543,7 @@ public class BugreportProgressService extends Service { final int pid = info.pid; final int id = info.id; if (info.finished) { - if (DEBUG) Log.v(TAG, "Skipping finished process " + pid + "(id: " + id + ")"); + if (DEBUG) Log.v(TAG, "Skipping finished process " + pid + " (id: " + id + ")"); continue; } activeProcesses++; @@ -708,7 +710,7 @@ public class BugreportProgressService extends Service { } final File screenshotFile = new File((String) resultMsg.obj); - final int msgId; + final String msg; if (taken) { info.addScreenshot(screenshotFile); if (info.finished) { @@ -716,14 +718,13 @@ public class BugreportProgressService extends Service { info.renameScreenshots(mScreenshotsDir); sendBugreportNotification(mContext, info); } - msgId = R.string.bugreport_screenshot_taken; + msg = mContext.getString(R.string.bugreport_screenshot_taken); } else { // TODO: try again using Framework APIs instead of relying on screencap. - msgId = R.string.bugreport_screenshot_failed; + msg = mContext.getString(R.string.bugreport_screenshot_failed); + Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show(); } - final String msg = mContext.getString(msgId); Log.d(TAG, msg); - Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show(); } /** @@ -1125,7 +1126,7 @@ public class BugreportProgressService extends Service { private static boolean setSystemProperty(String key, String value) { try { - if (DEBUG) Log.v(TAG, "Setting system property" + key + " to " + value); + if (DEBUG) Log.v(TAG, "Setting system property " + key + " to " + value); SystemProperties.set(key, value); } catch (IllegalArgumentException e) { Log.e(TAG, "Could not set property " + key + " to " + value, e); @@ -1249,6 +1250,8 @@ public class BugreportProgressService extends Service { * Sets its internal state and displays the dialog. */ private void initialize(final Context context, BugreportInfo info) { + final String dialogTitle = + context.getString(R.string.bugreport_info_dialog_title, info.id); // First initializes singleton. if (mDialog == null) { @SuppressLint("InflateParams") @@ -1272,7 +1275,7 @@ public class BugreportProgressService extends Service { mDialog = new AlertDialog.Builder(context) .setView(view) - .setTitle(context.getString(R.string.bugreport_info_dialog_title, info.id)) + .setTitle(dialogTitle) .setCancelable(false) .setPositiveButton(context.getString(com.android.internal.R.string.ok), null) @@ -1297,6 +1300,12 @@ public class BugreportProgressService extends Service { new WindowManager.LayoutParams( WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG)); + } else { + // Re-use view, but reset fields first. + mDialog.setTitle(dialogTitle); + mInfoName.setText(null); + mInfoTitle.setText(null); + mInfoDescription.setText(null); } // Then set fields. @@ -1372,7 +1381,7 @@ public class BugreportProgressService extends Service { // Must update system property for the cases where dumpstate finishes // while the user is still entering other fields (like title or // description) - setBugreportNameProperty(mId, name); + setBugreportNameProperty(mPid, name); } /** @@ -1517,7 +1526,7 @@ public class BugreportProgressService extends Service { final List<File> renamedFiles = new ArrayList<>(screenshotFiles.size()); for (File oldFile : screenshotFiles) { final String oldName = oldFile.getName(); - final String newName = oldName.replace(Integer.toString(pid), name); + final String newName = oldName.replaceFirst(Integer.toString(pid), name); final File newFile; if (!newName.equals(oldName)) { final File renamedFile = new File(screenshotDir, newName); diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java index 8c62670dfa7c..3cef3bb21a7f 100644 --- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java +++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java @@ -19,6 +19,7 @@ package com.android.shell; import static android.test.MoreAsserts.assertContainsRegex; import static com.android.shell.ActionSendMultipleConsumerActivity.UI_NAME; import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT; +import static com.android.shell.BugreportProgressService.EXTRA_ID; import static com.android.shell.BugreportProgressService.EXTRA_MAX; import static com.android.shell.BugreportProgressService.EXTRA_NAME; import static com.android.shell.BugreportProgressService.EXTRA_PID; @@ -60,6 +61,7 @@ import android.service.notification.StatusBarNotification; import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; import android.support.test.uiautomator.UiObjectNotFoundException; +import android.support.test.uiautomator.UiSelector; import android.test.InstrumentationTestCase; import android.test.suitebuilder.annotation.LargeTest; import android.text.TextUtils; @@ -98,24 +100,33 @@ public class BugreportReceiverTest extends InstrumentationTestCase { private static final String BUGREPORTS_DIR = "bugreports"; private static final String BUGREPORT_FILE = "test_bugreport.txt"; private static final String ZIP_FILE = "test_bugreport.zip"; + private static final String ZIP_FILE2 = "test_bugreport2.zip"; private static final String SCREENSHOT_FILE = "test_screenshot.png"; private static final String BUGREPORT_CONTENT = "Dump, might as well dump!\n"; private static final String SCREENSHOT_CONTENT = "A picture is worth a thousand words!\n"; private static final int PID = 42; - private static final String PROGRESS_PROPERTY = "dumpstate.42.progress"; - private static final String MAX_PROPERTY = "dumpstate.42.max"; - private static final String NAME_PROPERTY = "dumpstate.42.name"; + private static final int PID2 = 24; + private static final int ID = 108; + private static final int ID2 = 801; + private static final String PROGRESS_PROPERTY = "dumpstate." + PID + ".progress"; + private static final String MAX_PROPERTY = "dumpstate." + PID + ".max"; + private static final String NAME_PROPERTY = "dumpstate." + PID + ".name"; private static final String NAME = "BUG, Y U NO REPORT?"; + private static final String NAME2 = "A bugreport's life"; private static final String NEW_NAME = "Bug_Forrest_Bug"; + private static final String NEW_NAME2 = "BugsyReportsy"; private static final String TITLE = "Wimbugdom Champion 2015"; + private static final String TITLE2 = "Master of the Universe"; + private static final String DESCRIPTION = "One's description..."; + private static final String DESCRIPTION2 = "...is another's treasure."; private static final String NO_DESCRIPTION = null; private static final String NO_NAME = null; private static final String NO_SCREENSHOT = null; private static final String NO_TITLE = null; - private static final int NO_PID = 0; + private static final int NO_ID = 0; private static final boolean RENAMED_SCREENSHOTS = true; private static final boolean DIDNT_RENAME_SCREENSHOTS = false; @@ -123,6 +134,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase { private String mPlainTextPath; private String mZipPath; + private String mZipPath2; private String mScreenshotPath; private Context mContext; @@ -141,10 +153,12 @@ public class BugreportReceiverTest extends InstrumentationTestCase { mPlainTextPath = getPath(BUGREPORT_FILE); mZipPath = getPath(ZIP_FILE); + mZipPath2 = getPath(ZIP_FILE2); mScreenshotPath = getPath(SCREENSHOT_FILE); createTextFile(mPlainTextPath, BUGREPORT_CONTENT); createTextFile(mScreenshotPath, SCREENSHOT_CONTENT); createZipFile(mZipPath, BUGREPORT_FILE, BUGREPORT_CONTENT); + createZipFile(mZipPath2, BUGREPORT_FILE, BUGREPORT_CONTENT); // Creates a multi-line description. StringBuilder sb = new StringBuilder(); @@ -177,8 +191,8 @@ public class BugreportReceiverTest extends InstrumentationTestCase { assertProgressNotification(NAME, nf.format(0.25)); Bundle extras = - sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, ZIP_FILE, + sendBugreportFinishedAndGetSharedIntent(ID, mPlainTextPath, mScreenshotPath); + assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE, NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS); assertServiceNotRunning(); @@ -201,15 +215,15 @@ public class BugreportReceiverTest extends InstrumentationTestCase { assertScreenshotButtonEnabled(false); waitForScreenshotButtonEnabled(true); - sendBugreportFinished(PID, mPlainTextPath, mScreenshotPath); + sendBugreportFinished(ID, mPlainTextPath, mScreenshotPath); if (serviceDies) { - waitShareNotification(PID); + waitShareNotification(ID); killService(); } - Bundle extras = acceptBugreportAndGetSharedIntent(PID); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, ZIP_FILE, + Bundle extras = acceptBugreportAndGetSharedIntent(ID); + assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE, NAME, NO_TITLE, NO_DESCRIPTION, 2, RENAMED_SCREENSHOTS); assertServiceNotRunning(); @@ -227,8 +241,8 @@ public class BugreportReceiverTest extends InstrumentationTestCase { resetProperties(); sendBugreportStarted(1000); - sendBugreportFinished(PID, mPlainTextPath, NO_SCREENSHOT); - waitShareNotification(PID); + sendBugreportFinished(ID, mPlainTextPath, NO_SCREENSHOT); + waitShareNotification(ID); // There's no indication in the UI about the screenshot finish, so just sleep like a baby... Thread.sleep(SAFE_SCREENSHOT_DELAY * DateUtils.SECOND_IN_MILLIS); @@ -237,8 +251,8 @@ public class BugreportReceiverTest extends InstrumentationTestCase { killService(); } - Bundle extras = acceptBugreportAndGetSharedIntent(PID); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, PID, ZIP_FILE, + Bundle extras = acceptBugreportAndGetSharedIntent(ID); + assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, ID, PID, ZIP_FILE, NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS); assertServiceNotRunning(); @@ -249,11 +263,10 @@ public class BugreportReceiverTest extends InstrumentationTestCase { sendBugreportStarted(1000); waitForScreenshotButtonEnabled(true); - DetailsUi detailsUi = new DetailsUi(mUiBot, PID); + DetailsUi detailsUi = new DetailsUi(mUiBot, ID); // Check initial name. - String actualName = detailsUi.nameField.getText().toString(); - assertEquals("Wrong value on field 'name'", NAME, actualName); + detailsUi.assertName(NAME); // Change name - it should have changed system property once focus is changed. detailsUi.nameField.setText(NEW_NAME); @@ -281,9 +294,9 @@ public class BugreportReceiverTest extends InstrumentationTestCase { assertPropertyValue(NAME_PROPERTY, NEW_NAME); assertProgressNotification(NEW_NAME, "0.00%"); - Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, + Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, mPlainTextPath, mScreenshotPath); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, TITLE, + assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE, NEW_NAME, TITLE, mDescription, 1, RENAMED_SCREENSHOTS); assertServiceNotRunning(); @@ -302,11 +315,10 @@ public class BugreportReceiverTest extends InstrumentationTestCase { sendBugreportStarted(1000); waitForScreenshotButtonEnabled(true); - DetailsUi detailsUi = new DetailsUi(mUiBot, PID); + DetailsUi detailsUi = new DetailsUi(mUiBot, ID); // Check initial name. - String actualName = detailsUi.nameField.getText().toString(); - assertEquals("Wrong value on field 'name'", NAME, actualName); + detailsUi.assertName(NAME); // Change fields. detailsUi.reOpen(); @@ -319,9 +331,9 @@ public class BugreportReceiverTest extends InstrumentationTestCase { assertPropertyValue(NAME_PROPERTY, NEW_NAME); assertProgressNotification(NEW_NAME, "0.00%"); - Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, + Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, plainText? mPlainTextPath : mZipPath, mScreenshotPath); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, TITLE, + assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE, NEW_NAME, TITLE, mDescription, 1, RENAMED_SCREENSHOTS); assertServiceNotRunning(); @@ -332,20 +344,66 @@ public class BugreportReceiverTest extends InstrumentationTestCase { sendBugreportStarted(1000); waitForScreenshotButtonEnabled(true); - DetailsUi detailsUi = new DetailsUi(mUiBot, PID); + DetailsUi detailsUi = new DetailsUi(mUiBot, ID); detailsUi.nameField.setText(""); detailsUi.titleField.setText(""); detailsUi.descField.setText(mDescription); detailsUi.clickOk(); - Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mZipPath, mScreenshotPath); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, ZIP_FILE, + Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, mZipPath, mScreenshotPath); + assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE, NO_NAME, NO_TITLE, mDescription, 1, DIDNT_RENAME_SCREENSHOTS); assertServiceNotRunning(); } + /* + * TODO: this test can be flanky because it relies in the order the notifications are displayed, + * since mUiBot gets the first notification. + * Ideally, openProgressNotification() should return the whole notification, so DetailsUi + * could use it and find children instead, but unfortunately the notification object hierarchy + * is too complex and getting it from the notification text object would be to fragile + * (for instance, it could require navigating many parents up in the hierarchy). + */ + public void testProgress_changeJustDetailsIsClearedOnSecondBugreport() throws Exception { + resetProperties(); + sendBugreportStarted(ID, PID, NAME, 1000); + waitForScreenshotButtonEnabled(true); + + DetailsUi detailsUi = new DetailsUi(mUiBot, ID); + detailsUi.assertName(NAME); + detailsUi.assertTitle(mContext.getString(R.string.bugreport_info_title)); + detailsUi.assertDescription(mContext.getString(R.string.bugreport_info_description)); + detailsUi.nameField.setText(NEW_NAME); + detailsUi.titleField.setText(TITLE); + detailsUi.descField.setText(DESCRIPTION); + detailsUi.clickOk(); + + sendBugreportStarted(ID2, PID2, NAME2, 1000); + + Bundle extras = sendBugreportFinishedAndGetSharedIntent(ID, mZipPath, mScreenshotPath); + assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE, + NEW_NAME, TITLE, DESCRIPTION, 1, RENAMED_SCREENSHOTS); + + detailsUi = new DetailsUi(mUiBot, ID2); + detailsUi.assertName(NAME2); + detailsUi.assertTitle(mContext.getString(R.string.bugreport_info_title)); + detailsUi.assertDescription(mContext.getString(R.string.bugreport_info_description)); + detailsUi.nameField.setText(NEW_NAME2); + detailsUi.titleField.setText(TITLE2); + detailsUi.descField.setText(DESCRIPTION2); + detailsUi.clickOk(); + + // Must use a different zip file otherwise it will fail because zip already contains + // title.txt and description.txt entries. + extras = sendBugreportFinishedAndGetSharedIntent(ID2, mZipPath2, NO_SCREENSHOT); + assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, ID2, PID2, TITLE2, + NEW_NAME2, TITLE2, DESCRIPTION2, 1, RENAMED_SCREENSHOTS); + + assertServiceNotRunning(); + } + /** * Tests the scenario where the initial screenshot and dumpstate are finished while the user * is changing the info in the details screen. @@ -369,14 +427,14 @@ public class BugreportReceiverTest extends InstrumentationTestCase { waitForScreenshotButtonEnabled(true); } - DetailsUi detailsUi = new DetailsUi(mUiBot, PID); + DetailsUi detailsUi = new DetailsUi(mUiBot, ID); // Finish the bugreport while user's still typing the name. detailsUi.nameField.setText(NEW_NAME); - sendBugreportFinished(PID, mPlainTextPath, mScreenshotPath); + sendBugreportFinished(ID, mPlainTextPath, mScreenshotPath); // Wait until the share notification is received... - waitShareNotification(PID); + waitShareNotification(ID); // ...then close notification bar. mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); @@ -390,8 +448,8 @@ public class BugreportReceiverTest extends InstrumentationTestCase { detailsUi.clickOk(); // Finally, share bugreport. - Bundle extras = acceptBugreportAndGetSharedIntent(PID); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, PID, TITLE, + Bundle extras = acceptBugreportAndGetSharedIntent(ID); + assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, TITLE, NAME, TITLE, mDescription, 1, RENAMED_SCREENSHOTS); assertServiceNotRunning(); @@ -402,8 +460,8 @@ public class BugreportReceiverTest extends InstrumentationTestCase { BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_SHOW); // Send notification and click on share. - sendBugreportFinished(NO_PID, mPlainTextPath, null); - acceptBugreport(NO_PID); + sendBugreportFinished(NO_ID, mPlainTextPath, null); + acceptBugreport(NO_ID); // Handle the warning mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm)); @@ -425,9 +483,9 @@ public class BugreportReceiverTest extends InstrumentationTestCase { } public void testShareBugreportAfterServiceDies() throws Exception { - sendBugreportFinished(NO_PID, mPlainTextPath, NO_SCREENSHOT); + sendBugreportFinished(NO_ID, mPlainTextPath, NO_SCREENSHOT); killService(); - Bundle extras = acceptBugreportAndGetSharedIntent(NO_PID); + Bundle extras = acceptBugreportAndGetSharedIntent(NO_ID); assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT); } @@ -463,32 +521,38 @@ public class BugreportReceiverTest extends InstrumentationTestCase { private void assertProgressNotification(String name, String percent) { // TODO: it currently looks for 3 distinct objects, without taking advantage of their // relationship. - openProgressNotification(PID); + openProgressNotification(ID); Log.v(TAG, "Looking for progress notification details: '" + name + "-" + percent + "'"); mUiBot.getObject(name); mUiBot.getObject(percent); } - private void openProgressNotification(int pid) { - String title = mContext.getString(R.string.bugreport_in_progress_title, pid); + private void openProgressNotification(int id) { + String title = mContext.getString(R.string.bugreport_in_progress_title, id); Log.v(TAG, "Looking for progress notification title: '" + title + "'"); mUiBot.getNotification(title); } void resetProperties() { // TODO: call method to remove property instead - SystemProperties.set(PROGRESS_PROPERTY, "0"); - SystemProperties.set(MAX_PROPERTY, "0"); + SystemProperties.set(PROGRESS_PROPERTY, "Reset"); + SystemProperties.set(MAX_PROPERTY, "Reset"); + SystemProperties.set(NAME_PROPERTY, "Reset"); } /** * Sends a "bugreport started" intent with the default values. */ private void sendBugreportStarted(int max) throws Exception { + sendBugreportStarted(ID, PID, NAME, max); + } + + private void sendBugreportStarted(int id, int pid, String name, int max) throws Exception { Intent intent = new Intent(INTENT_BUGREPORT_STARTED); intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); - intent.putExtra(EXTRA_PID, PID); - intent.putExtra(EXTRA_NAME, NAME); + intent.putExtra(EXTRA_ID, id); + intent.putExtra(EXTRA_PID, pid); + intent.putExtra(EXTRA_NAME, name); intent.putExtra(EXTRA_MAX, max); mContext.sendBroadcast(intent); } @@ -500,7 +564,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase { */ private Bundle sendBugreportFinishedAndGetSharedIntent(String bugreportPath, String screenshotPath) { - return sendBugreportFinishedAndGetSharedIntent(NO_PID, bugreportPath, screenshotPath); + return sendBugreportFinishedAndGetSharedIntent(NO_ID, bugreportPath, screenshotPath); } /** @@ -508,10 +572,10 @@ public class BugreportReceiverTest extends InstrumentationTestCase { * * @return extras sent in the shared intent. */ - private Bundle sendBugreportFinishedAndGetSharedIntent(int pid, String bugreportPath, + private Bundle sendBugreportFinishedAndGetSharedIntent(int id, String bugreportPath, String screenshotPath) { - sendBugreportFinished(pid, bugreportPath, screenshotPath); - return acceptBugreportAndGetSharedIntent(pid); + sendBugreportFinished(id, bugreportPath, screenshotPath); + return acceptBugreportAndGetSharedIntent(id); } /** @@ -519,8 +583,8 @@ public class BugreportReceiverTest extends InstrumentationTestCase { * * @return extras sent in the shared intent. */ - private Bundle acceptBugreportAndGetSharedIntent(int pid) { - acceptBugreport(pid); + private Bundle acceptBugreportAndGetSharedIntent(int id) { + acceptBugreport(id); mUiBot.chooseActivity(UI_NAME); return mListener.getExtras(); } @@ -528,25 +592,25 @@ public class BugreportReceiverTest extends InstrumentationTestCase { /** * Waits for the notification to share the finished bugreport. */ - private void waitShareNotification(int pid) { - mUiBot.getNotification(mContext.getString(R.string.bugreport_finished_title, pid)); + private void waitShareNotification(int id) { + mUiBot.getNotification(mContext.getString(R.string.bugreport_finished_title, id)); } /** * Accepts the notification to share the finished bugreport. */ - private void acceptBugreport(int pid) { - mUiBot.clickOnNotification(mContext.getString(R.string.bugreport_finished_title, pid)); + private void acceptBugreport(int id) { + mUiBot.clickOnNotification(mContext.getString(R.string.bugreport_finished_title, id)); } /** * Sends a "bugreport finished" intent. */ - private void sendBugreportFinished(int pid, String bugreportPath, String screenshotPath) { + private void sendBugreportFinished(int id, String bugreportPath, String screenshotPath) { Intent intent = new Intent(INTENT_BUGREPORT_FINISHED); intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND); - if (pid != NO_PID) { - intent.putExtra(EXTRA_PID, pid); + if (id != NO_ID) { + intent.putExtra(EXTRA_ID, id); } if (bugreportPath != null) { intent.putExtra(EXTRA_BUGREPORT, bugreportPath); @@ -563,7 +627,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase { */ private void assertActionSendMultiple(Bundle extras, String bugreportContent, String screenshotContent) throws IOException { - assertActionSendMultiple(extras, bugreportContent, screenshotContent, PID, ZIP_FILE, + assertActionSendMultiple(extras, bugreportContent, screenshotContent, ID, PID, ZIP_FILE, NO_NAME, NO_TITLE, NO_DESCRIPTION, 0, DIDNT_RENAME_SCREENSHOTS); } @@ -573,6 +637,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase { * @param extras extras received in the intent * @param bugreportContent expected content in the bugreport file * @param screenshotContent expected content in the screenshot file (sent by dumpstate), if any + * @param id emulated dumpstate id * @param pid emulated dumpstate pid * @param name expected subject * @param name bugreport name as provided by the user (or received by dumpstate) @@ -582,7 +647,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase { * @param renamedScreenshots whether the screenshots are expected to be renamed */ private void assertActionSendMultiple(Bundle extras, String bugreportContent, - String screenshotContent, int pid, String subject, + String screenshotContent, int id, int pid, String subject, String name, String title, String description, int numberScreenshots, boolean renamedScreenshots) throws IOException { String body = extras.getString(Intent.EXTRA_TEXT); @@ -745,7 +810,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase { fail("Service status didn't change to " + expectRunning); } - private static void createTextFile(String path, String content) throws IOException { + private void createTextFile(String path, String content) throws IOException { Log.v(TAG, "createFile(" + path + ")"); try (Writer writer = new BufferedWriter(new OutputStreamWriter( new FileOutputStream(path)))) { @@ -781,7 +846,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase { * Gets the notification button used to take a screenshot. */ private UiObject getScreenshotButton() { - openProgressNotification(PID); + openProgressNotification(ID); return mUiBot.getVisibleObject( mContext.getString(R.string.bugreport_screenshot_action).toUpperCase()); } @@ -833,15 +898,16 @@ public class BugreportReceiverTest extends InstrumentationTestCase { /** * Gets the UI objects by opening the progress notification and clicking DETAILS. */ - DetailsUi(UiBot uiBot, int pid) throws UiObjectNotFoundException { - openProgressNotification(pid); - detailsButton = mUiBot.getVisibleObject( - mContext.getString(R.string.bugreport_info_action).toUpperCase()); + DetailsUi(UiBot uiBot, int id) throws UiObjectNotFoundException { + openProgressNotification(id); + detailsButton = mUiBot.getVisibleObject(mContext.getString( + R.string.bugreport_info_action).toUpperCase()); + mUiBot.click(detailsButton, "details_button"); // TODO: unhardcode resource ids UiObject dialogTitle = mUiBot.getVisibleObjectById("android:id/alertTitle"); assertEquals("Wrong title", mContext.getString(R.string.bugreport_info_dialog_title, - pid), dialogTitle.getText().toString()); + id), dialogTitle.getText().toString()); nameField = mUiBot.getVisibleObjectById("com.android.shell:id/name"); titleField = mUiBot.getVisibleObjectById("com.android.shell:id/title"); descField = mUiBot.getVisibleObjectById("com.android.shell:id/description"); @@ -849,6 +915,28 @@ public class BugreportReceiverTest extends InstrumentationTestCase { cancelButton = mUiBot.getObjectById("android:id/button2"); } + private void assertField(String name, UiObject field, String expected) { + try { + String actual = field.getText().toString(); + assertEquals("Wrong value on field '" + name + "'", expected, actual); + } catch (UiObjectNotFoundException e) { + // Should not happen... + throw new IllegalStateException("field not found: " + name, e); + } + } + + void assertName(String expected) { + assertField("name", nameField, expected); + } + + void assertTitle(String expected) { + assertField("title", titleField, expected); + } + + void assertDescription(String expected) { + assertField("description", descField, expected); + } + /** * Takes focus away from the name field so it can be validated. */ @@ -858,7 +946,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase { } void reOpen() { - openProgressNotification(PID); + openProgressNotification(ID); mUiBot.click(detailsButton, "details_button"); } diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk index 88313bb50378..ad3c26b29c59 100644 --- a/packages/SystemUI/Android.mk +++ b/packages/SystemUI/Android.mk @@ -1,11 +1,25 @@ LOCAL_PATH:= $(call my-dir) + include $(CLEAR_VARS) -LOCAL_MODULE_TAGS := optional +LOCAL_MODULE := SystemUI-proto-tags -LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-proto-files-under,src) $(call all-Iaidl-files-under, src) \ +LOCAL_SRC_FILES := $(call all-proto-files-under,src) \ src/com/android/systemui/EventLogTags.logtags +LOCAL_PROTOC_OPTIMIZE_TYPE := nano +LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors + +include $(BUILD_STATIC_JAVA_LIBRARY) + +# ------------------ + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src) + LOCAL_STATIC_JAVA_LIBRARIES := \ Keyguard \ android-support-v7-recyclerview \ @@ -13,13 +27,12 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ android-support-v7-appcompat \ android-support-v14-preference \ android-support-v17-leanback \ - framework-protos + framework-protos \ + SystemUI-proto-tags LOCAL_JAVA_LIBRARIES := telephony-common LOCAL_PACKAGE_NAME := SystemUI -LOCAL_PROTOC_OPTIMIZE_TYPE := nano -LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/SystemUI/res/drawable/tv_pip_button_focused.xml b/packages/SystemUI/res/drawable/tv_pip_button_focused.xml new file mode 100644 index 000000000000..5cabb77a6971 --- /dev/null +++ b/packages/SystemUI/res/drawable/tv_pip_button_focused.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 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. +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="oval"> + <size + android:width="36dp" + android:height="36dp" /> + <solid + android:color="#4DFFFFFF" /> +</shape> diff --git a/packages/SystemUI/res/drawable/tv_pip_close_button.xml b/packages/SystemUI/res/drawable/tv_pip_close_button.xml new file mode 100644 index 000000000000..86fda0d31346 --- /dev/null +++ b/packages/SystemUI/res/drawable/tv_pip_close_button.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android" + android:constantSize="true"> + <item android:state_focused="true"> + <layer-list> + <item android:drawable="@drawable/tv_pip_button_focused" /> + <item android:drawable="@drawable/ic_close_white" /> + </layer-list> + </item> + <item android:drawable="@drawable/ic_close_white" /> +</selector> diff --git a/packages/SystemUI/res/drawable/tv_pip_full_button.xml b/packages/SystemUI/res/drawable/tv_pip_full_button.xml new file mode 100644 index 000000000000..332c669de154 --- /dev/null +++ b/packages/SystemUI/res/drawable/tv_pip_full_button.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android" + android:constantSize="true"> + <item android:state_focused="true"> + <layer-list> + <item android:drawable="@drawable/tv_pip_button_focused" /> + <item android:drawable="@drawable/ic_fullscreen_white_24dp" /> + </layer-list> + </item> + <item android:drawable="@drawable/ic_fullscreen_white_24dp" /> +</selector> diff --git a/packages/SystemUI/res/drawable/tv_pip_outline.xml b/packages/SystemUI/res/drawable/tv_pip_outline.xml new file mode 100644 index 000000000000..c84438c2e55e --- /dev/null +++ b/packages/SystemUI/res/drawable/tv_pip_outline.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 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. +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <stroke android:width="2dp" android:color="#EEEEEE" /> +</shape> diff --git a/packages/SystemUI/res/drawable/tv_pip_pause_button.xml b/packages/SystemUI/res/drawable/tv_pip_pause_button.xml new file mode 100644 index 000000000000..d277b07c199e --- /dev/null +++ b/packages/SystemUI/res/drawable/tv_pip_pause_button.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 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. +--> + +<selector xmlns:android="http://schemas.android.com/apk/res/android" + android:constantSize="true"> + <item android:state_focused="true"> + <layer-list> + <item android:drawable="@drawable/tv_pip_button_focused" /> + <item android:drawable="@drawable/ic_pause_white_24dp" /> + </layer-list> + </item> + <item android:drawable="@drawable/ic_pause_white_24dp" /> +</selector> diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml index 3ee2475ec94a..994d3c943671 100644 --- a/packages/SystemUI/res/layout/qs_panel.xml +++ b/packages/SystemUI/res/layout/qs_panel.xml @@ -28,9 +28,7 @@ android:layout_marginTop="@dimen/status_bar_header_height" android:layout_width="match_parent" android:layout_height="wrap_content" - android:paddingBottom="8dp" - android:clipToPadding="false" - android:clipChildren="false" /> + android:paddingBottom="8dp" /> <include layout="@layout/quick_status_bar_expanded_header" /> diff --git a/packages/SystemUI/res/layout/recents_task_view_header.xml b/packages/SystemUI/res/layout/recents_task_view_header.xml index 2e415612c19a..fa6575824552 100644 --- a/packages/SystemUI/res/layout/recents_task_view_header.xml +++ b/packages/SystemUI/res/layout/recents_task_view_header.xml @@ -30,21 +30,41 @@ android:paddingBottom="8dp" android:paddingStart="12dp" android:paddingEnd="16dp" /> - <TextView - android:id="@+id/title" + <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical|start" android:layout_marginStart="56dp" - android:layout_marginEnd="112dp" - android:textSize="16sp" - android:textColor="#ffffffff" - android:text="@string/recents_empty_message" - android:fontFamily="sans-serif-medium" - android:singleLine="true" - android:maxLines="2" - android:ellipsize="marquee" - android:fadingEdge="horizontal" /> + android:layout_marginEnd="56dp" + android:orientation="vertical"> + <TextView + android:id="@+id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="start" + android:textSize="16sp" + android:textColor="#ffffffff" + android:text="@string/recents_empty_message" + android:fontFamily="sans-serif-medium" + android:singleLine="true" + android:maxLines="1" + android:ellipsize="marquee" + android:fadingEdge="horizontal" /> + <TextView + android:id="@+id/sub_title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="start" + android:textSize="11sp" + android:textColor="#ffffffff" + android:text="@string/recents_launch_non_dockable_task_label" + android:fontFamily="sans-serif-medium" + android:singleLine="true" + android:maxLines="1" + android:ellipsize="marquee" + android:fadingEdge="horizontal" + android:visibility="gone" /> + </LinearLayout> <com.android.systemui.recents.views.FixedSizeImageView android:id="@+id/move_task" android:layout_width="@dimen/recents_task_view_header_button_width" diff --git a/packages/SystemUI/res/layout/tv_pip_menu.xml b/packages/SystemUI/res/layout/tv_pip_menu.xml index 3562c644e61e..0b98d0ea71f5 100644 --- a/packages/SystemUI/res/layout/tv_pip_menu.xml +++ b/packages/SystemUI/res/layout/tv_pip_menu.xml @@ -18,36 +18,94 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="wrap_content" + android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_gravity="end" - android:paddingStart="10dp" - android:paddingEnd="10dp" - android:background="#88FFFFFF" - android:gravity="center_vertical" > - - <Button android:id="@+id/full" - android:layout_width="match_parent" + android:orientation="horizontal" + android:paddingTop="350dp" + android:background="#CC000000" + android:gravity="top|center_horizontal" + android:clipChildren="false"> + + <LinearLayout + android:layout_width="34dp" android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:text="@string/pip_fullscreen" - android:textSize="10sp" - android:focusable="true" /> + android:layout_marginEnd="3dp" + android:orientation="vertical" + android:gravity="center" + android:clipChildren="false"> + + <ImageView android:id="@+id/full" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:focusable="true" + android:src="@drawable/tv_pip_full_button" /> - <Button android:id="@+id/exit" - android:layout_width="match_parent" + <TextView android:id="@+id/full_desc" + android:layout_width="100dp" + android:layout_height="wrap_content" + android:layout_marginTop="3dp" + android:gravity="center" + android:visibility="invisible" + android:text="@string/pip_fullscreen" + android:fontFamily="sans-serif" + android:textSize="12sp" + android:textColor="#EEEEEE" + android:clipChildren="false" /> + </LinearLayout> + + <LinearLayout + android:layout_width="34dp" android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:text="@string/pip_exit" - android:textSize="10sp" - android:focusable="true" /> + android:layout_marginStart="3dp" + android:layout_marginEnd="3dp" + android:orientation="vertical" + android:gravity="center" + android:visibility="gone" + android:clipChildren="false"> + + <ImageView android:id="@+id/play_pause" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:focusable="true" + android:src="@drawable/tv_pip_pause_button" /> - <Button android:id="@+id/cancel" - android:layout_width="match_parent" + <TextView android:id="@+id/play_pause_desc" + android:layout_width="100dp" + android:layout_height="wrap_content" + android:layout_marginTop="3dp" + android:gravity="center" + android:visibility="invisible" + android:text="@string/pip_pause" + android:fontFamily="sans-serif" + android:textSize="12sp" + android:textColor="#EEEEEE" + android:clipChildren="false" /> + </LinearLayout> + + <LinearLayout + android:layout_width="34dp" android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:text="@string/pip_cancel" - android:textSize="10sp" - android:focusable="true" /> + android:layout_marginStart="3dp" + android:orientation="vertical" + android:gravity="center" + android:clipChildren="false"> + + <ImageView android:id="@+id/close" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:focusable="true" + android:src="@drawable/tv_pip_close_button" /> + + <TextView android:id="@+id/close_desc" + android:layout_width="100dp" + android:layout_height="wrap_content" + android:layout_marginTop="3dp" + android:gravity="center" + android:visibility="invisible" + android:text="@string/pip_close" + android:fontFamily="sans-serif" + android:textSize="12sp" + android:textColor="#EEEEEE" + android:clipChildren="false" /> + </LinearLayout> </LinearLayout> diff --git a/packages/SystemUI/res/layout/tv_pip_onboarding.xml b/packages/SystemUI/res/layout/tv_pip_onboarding.xml index ef395558af64..f031bb466bd7 100644 --- a/packages/SystemUI/res/layout/tv_pip_onboarding.xml +++ b/packages/SystemUI/res/layout/tv_pip_onboarding.xml @@ -18,34 +18,43 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/pip_onboarding" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#C00288D1" - android:gravity="center" - android:orientation="vertical" > + android:gravity="top|center_horizontal" + android:orientation="vertical"> - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textSize="30sp" - android:textColor="@android:color/white" - android:text="@string/pip_onboarding_title" /> + <!-- A rectangle arounds the PIP. + Size and positions will be programatically set up + to comply with config_defaultPictureInPictureBounds. --> <ImageView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:src="@drawable/ic_sysbar_home" /> + android:id="@+id/pip_outline" + android:layout_width="0dp" + android:layout_height="0dp" + android:src="@drawable/tv_pip_outline" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" - android:padding="30dp" - android:textSize="13sp" - android:textColor="@android:color/white" + android:layout_marginTop="24dp" + android:fontFamily="sans-serif" + android:textSize="16sp" + android:textColor="#EEEEEE" + android:lineSpacingMultiplier="1.28" android:text="@string/pip_onboarding_description" /> <Button android:id="@+id/close" android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textSize="15sp" + android:layout_height="36dp" + android:layout_marginTop="24dp" + android:gravity="center" + android:paddingStart="24dp" + android:paddingEnd="24dp" + android:fontFamily="sans-serif-condensed" + android:textSize="16sp" + android:textColor="#026089" android:textAllCaps="true" - android:text="@string/pip_onboarding_button" /> + android:text="@string/pip_onboarding_button" + android:background="#EEEEEE" + android:elevation="4dp" /> </LinearLayout> diff --git a/packages/SystemUI/res/values-sw600dp/styles.xml b/packages/SystemUI/res/values-sw600dp/styles.xml index 4d7d6b5c9f77..791d7615eb80 100644 --- a/packages/SystemUI/res/values-sw600dp/styles.xml +++ b/packages/SystemUI/res/values-sw600dp/styles.xml @@ -16,7 +16,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android"> <style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer"> - <item name="android:layout_width">480dp</item> + <item name="android:layout_width">@dimen/standard_notification_panel_width</item> </style> <style name="UserDetailView"> diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml index 77605bd3133e..bf32cc7505b7 100644 --- a/packages/SystemUI/res/values/dimens_tv.xml +++ b/packages/SystemUI/res/values/dimens_tv.xml @@ -31,4 +31,7 @@ <!-- Values for focus animation --> <dimen name="recents_tv_unselected_item_z">6dp</dimen> <dimen name="recents_tv_selected_item_z_delta">10dp</dimen> -</resources>
\ No newline at end of file + + <!-- Extra space around the PIP and its outline in PIP onboarding activity --> + <dimen name="tv_pip_bounds_space">3dp</dimen> +</resources> diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml index 54d271a4ff15..b9eee2e5d913 100644 --- a/packages/SystemUI/res/values/ids.xml +++ b/packages/SystemUI/res/values/ids.xml @@ -44,6 +44,10 @@ <item type="id" name="notification_screenshot"/> <item type="id" name="notification_hidden"/> <item type="id" name="notification_volumeui"/> + <item type="id" name="transformation_start_x_tag"/> + <item type="id" name="transformation_start_y_tag"/> + <item type="id" name="transformation_start_scale_x_tag"/> + <item type="id" name="transformation_start_scale_y_tag"/> <!-- Whether the icon is from a notification for which targetSdk < L --> <item type="id" name="icon_is_pre_L"/> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 30c0be882416..ac6e3ac7aae4 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -722,6 +722,10 @@ <string name="recents_history_button_label">History</string> <!-- Recents: History clear all string. [CHAR LIMIT=NONE] --> <string name="recents_history_clear_all_button_label">Clear</string> + <!-- Recents: Non-dockable task drag message. [CHAR LIMIT=NONE] --> + <string name="recents_drag_non_dockable_task_message">This app does not support multi-window</string> + <!-- Recents: Non-dockable task launch sub header. [CHAR LIMIT=NONE] --> + <string name="recents_launch_non_dockable_task_label">App does not support multi-window</string> <!-- Recents: MultiStack add stack split horizontal radio button. [CHAR LIMIT=NONE] --> <string name="recents_multistack_add_stack_dialog_split_horizontal">Split Horizontal</string> diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml index 7c4768d29cfe..4f382eae9398 100644 --- a/packages/SystemUI/res/values/strings_tv.xml +++ b/packages/SystemUI/res/values/strings_tv.xml @@ -20,7 +20,7 @@ <!-- Picture-in-Picture menu --> <eat-comment /> <!-- Button to close PIP on PIP UI --> - <string name="pip_exit" translatable="false">Close PIP</string> + <string name="pip_close" translatable="false">Close PIP</string> <!-- Button to move PIP screen to the fullscreen on PIP UI --> <string name="pip_fullscreen" translatable="false">Full screen</string> <!-- Button to play the current media on PIP UI --> @@ -34,8 +34,6 @@ <!-- Picture-in-Picture onboarding screen --> <eat-comment /> - <!-- Title for onboarding screen. --> - <string name="pip_onboarding_title" translatable="false">Picture-in-picture</string> <!-- Description for onboarding screen. --> <string name="pip_onboarding_description" translatable="false">Press and hold the HOME\nbutton to close or control it</string> <!-- Button to close onboarding screen. --> diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java index 0915ee1c1745..2c5cb89b3531 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java @@ -38,7 +38,7 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { if (mPageIndicator == null) return; mPageIndicator.setLocation(position); if (mPageListener != null) { - mPageListener.onPageChanged(position); + mPageListener.onPageChanged(position == 0); } } @@ -47,6 +47,9 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { int positionOffsetPixels) { if (mPageIndicator == null) return; mPageIndicator.setLocation(position + positionOffset); + if (mPageListener != null) { + mPageListener.onPageChanged(position == 0 && positionOffsetPixels == 0); + } } @Override @@ -57,6 +60,11 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { } @Override + public boolean hasOverlappingRendering() { + return false; + } + + @Override protected void onFinishInflate() { super.onFinishInflate(); mPageIndicator = (PageIndicator) findViewById(R.id.page_indicator); @@ -209,6 +217,6 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { }; public interface PageListener { - void onPageChanged(int page); + void onPageChanged(boolean isFirst); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java index dc645914e183..c31bb33d6a41 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java @@ -69,11 +69,13 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha } @Override - public void onPageChanged(int page) { - mOnFirstPage = page == 0; - if (!mOnFirstPage) { + public void onPageChanged(boolean isFirst) { + if (mOnFirstPage == isFirst) return; + if (!isFirst) { + setPosition(1); clearAnimationState(); } + mOnFirstPage = isFirst; } private void updateAnimators() { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java index abe4c7798a01..4408dbf236bf 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java @@ -183,5 +183,10 @@ public class QuickQSPanel extends QSPanel { // No resources here. return false; } + + @Override + public boolean hasOverlappingRendering() { + return false; + } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java index 94d8524188ee..026dd0e74a0a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java @@ -58,7 +58,7 @@ public class TouchAnimator { } if (mListener != null) { if (mLastT == 0 || mLastT == 1) { - if (t != 0) { + if (t != mLastT) { mListener.onAnimationStarted(); } } else if (t == 1) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index c2a6108d931d..c41098f3c0ee 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -528,17 +528,16 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD @Override public void onMultiWindowChanged(boolean inMultiWindow) { super.onMultiWindowChanged(inMultiWindow); - if (!inMultiWindow) { - RecentsTaskLoader loader = Recents.getTaskLoader(); - RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options(); - launchOpts.loadIcons = false; - launchOpts.loadThumbnails = false; - launchOpts.onlyLoadForCache = true; - RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this); - loader.preloadTasks(loadPlan, -1, false); - loader.loadTasks(this, loadPlan, launchOpts); - EventBus.getDefault().send(new TaskStackUpdatedEvent(loadPlan.getTaskStack())); - } + RecentsTaskLoader loader = Recents.getTaskLoader(); + RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options(); + launchOpts.loadIcons = false; + launchOpts.loadThumbnails = false; + launchOpts.onlyLoadForCache = true; + RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this); + loader.preloadTasks(loadPlan, -1, false); + loader.loadTasks(this, loadPlan, launchOpts); + EventBus.getDefault().send(new TaskStackUpdatedEvent(loadPlan.getTaskStack(), + inMultiWindow)); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index 8de964b77f66..28b2faed58fb 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -161,10 +161,8 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener Handler mHandler; TaskStackListenerImpl mTaskStackListener; RecentsAppWidgetHost mAppWidgetHost; - boolean mBootCompleted; boolean mCanReuseTaskStackViews = true; boolean mDraggingInRecents; - boolean mReloadTasks; boolean mLaunchedWhileDocking; // Task launching @@ -236,7 +234,6 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener } public void onBootCompleted() { - mBootCompleted = true; updateHeaderBarLayout(true /* tryAndBindSearchWidget */, null /* stack */); } @@ -317,23 +314,21 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener } public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { - if (mBootCompleted) { - if (triggeredFromAltTab && mFastAltTabTrigger.isDozing()) { - // The user has released alt-tab before the trigger has run, so just show the next - // task immediately - showNextTask(); - - // Cancel the fast alt-tab trigger - mFastAltTabTrigger.stopDozing(); - mFastAltTabTrigger.resetTrigger(); - return; - } + if (triggeredFromAltTab && mFastAltTabTrigger.isDozing()) { + // The user has released alt-tab before the trigger has run, so just show the next + // task immediately + showNextTask(); - // Defer to the activity to handle hiding recents, if it handles it, then it must still - // be visible - EventBus.getDefault().post(new HideRecentsEvent(triggeredFromAltTab, - triggeredFromHomeKey)); + // Cancel the fast alt-tab trigger + mFastAltTabTrigger.stopDozing(); + mFastAltTabTrigger.resetTrigger(); + return; } + + // Defer to the activity to handle hiding recents, if it handles it, then it must still + // be visible + EventBus.getDefault().post(new HideRecentsEvent(triggeredFromAltTab, + triggeredFromHomeKey)); } public void toggleRecents() { @@ -347,7 +342,6 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener mTriggeredFromAltTab = false; try { - ViewConfiguration viewConfig = ViewConfiguration.get(mContext); SystemServicesProxy ssp = Recents.getSystemServices(); ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask(); MutableBoolean isTopTaskHome = new MutableBoolean(true); diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java index f87f6de3be7c..0d614e8c675c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java @@ -28,8 +28,10 @@ public class TaskStackUpdatedEvent extends EventBus.AnimatedEvent { * A new TaskStack instance representing the latest stack state. */ public final TaskStack stack; + public final boolean inMultiWindow; - public TaskStackUpdatedEvent(TaskStack stack) { + public TaskStackUpdatedEvent(TaskStack stack, boolean inMultiWindow) { this.stack = stack; + this.inMultiWindow = inMultiWindow; } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java index 824231ae2fc1..6fef8a24fff3 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java @@ -198,8 +198,8 @@ public class RecentsTaskLoadPlan { // Add the task to the stack Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, icon, thumbnail, title, contentDescription, dismissDescription, activityColor, - backgroundColor, !isStackTask, isLaunchTarget, isSystemApp, t.bounds, - t.taskDescription); + backgroundColor, !isStackTask, isLaunchTarget, isSystemApp, t.isDockable, + t.bounds, t.taskDescription); allTasks.add(task); affiliatedTaskCounts.put(taskKey.id, affiliatedTaskCounts.get(taskKey.id, 0) + 1); diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java index 8ed6dd78a357..e5d4f1bf50bc 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java @@ -168,6 +168,8 @@ public class Task { public boolean isHistorical; @ViewDebug.ExportedProperty(category="recents") public boolean isSystemApp; + @ViewDebug.ExportedProperty(category="recents") + public boolean isDockable; private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>(); @@ -178,8 +180,8 @@ public class Task { public Task(TaskKey key, int affiliationTaskId, int affiliationColor, Drawable icon, Bitmap thumbnail, String title, String contentDescription, String dismissDescription, int colorPrimary, int colorBackground, - boolean isHistorical, boolean isLaunchTarget, boolean isSystemApp, Rect bounds, - ActivityManager.TaskDescription taskDescription) { + boolean isHistorical, boolean isLaunchTarget, boolean isSystemApp, + boolean isDockable, Rect bounds, ActivityManager.TaskDescription taskDescription) { boolean isInAffiliationGroup = (affiliationTaskId != key.id); boolean hasAffiliationGroupColor = isInAffiliationGroup && (affiliationColor != 0); this.key = key; @@ -199,6 +201,7 @@ public class Task { this.isLaunchTarget = isLaunchTarget; this.isHistorical = isHistorical; this.isSystemApp = isSystemApp; + this.isDockable = isDockable; } /** Copies the other task. */ @@ -219,6 +222,7 @@ public class Task { this.isLaunchTarget = o.isLaunchTarget; this.isHistorical = o.isHistorical; this.isSystemApp = o.isSystemApp; + this.isDockable = o.isDockable; } /** diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index 2e456277406a..5dde92698f78 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -663,8 +663,10 @@ public class RecentsView extends FrameLayout { } public final void onBusEvent(TaskStackUpdatedEvent event) { - mStack.setTasks(event.stack.computeAllTasksList(), true /* notifyStackChanges */); - mStack.createAffiliatedGroupings(getContext()); + if (!event.inMultiWindow) { + mStack.setTasks(event.stack.computeAllTasksList(), true /* notifyStackChanges */); + mStack.createAffiliatedGroupings(getContext()); + } } public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java index 016d9370364d..079d7b9148f0 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java @@ -21,7 +21,9 @@ import android.graphics.Point; import android.view.MotionEvent; import android.view.ViewConfiguration; import android.view.ViewDebug; +import android.widget.Toast; +import com.android.systemui.R; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.events.EventBus; @@ -148,11 +150,16 @@ public class RecentsViewTouchHandler { mVisibleDockStates.clear(); if (!ssp.hasDockedTask() && mRv.getTaskStack().getTaskCount() > 1) { - // Add the dock state drop targets (these take priority) - TaskStack.DockState[] dockStates = getDockStatesForCurrentOrientation(); - for (TaskStack.DockState dockState : dockStates) { - registerDropTargetForCurrentDrag(dockState); - mVisibleDockStates.add(dockState); + if (!event.task.isDockable) { + Toast.makeText(mRv.getContext(), R.string.recents_drag_non_dockable_task_message, + Toast.LENGTH_SHORT).show(); + } else { + // Add the dock state drop targets (these take priority) + TaskStack.DockState[] dockStates = getDockStatesForCurrentOrientation(); + for (TaskStack.DockState dockState : dockStates) { + registerDropTargetForCurrentDrag(dockState); + mVisibleDockStates.add(dockState); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index d71d70f3819b..e1a81c8c15f2 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -1573,6 +1573,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal Task launchTask = mStack.getStackTasks().get(launchTaskIndex); EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(launchTask), launchTask, null, INVALID_STACK_ID, false /* screenPinningRequested */)); + + MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_LAUNCH_PREVIOUS_TASK, + launchTask.key.getComponent().toString()); } } @@ -1830,12 +1833,28 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } public final void onBusEvent(TaskStackUpdatedEvent event) { - // Scroll the stack to the front after it has been updated + if (!event.inMultiWindow) { + // Scroll the stack to the front after it has been updated + event.addPostAnimationCallback(new Runnable() { + @Override + public void run() { + mStackScroller.animateScroll(mLayoutAlgorithm.mMaxScrollP, + null /* postScrollRunnable */); + } + }); + } + // When the multi-window state changes, rebind all task view headers again to update their + // dockable state event.addPostAnimationCallback(new Runnable() { @Override public void run() { - mStackScroller.animateScroll(mLayoutAlgorithm.mMaxScrollP, - null /* postScrollRunnable */); + List<TaskView> taskViews = getTaskViews(); + int taskViewCount = taskViews.size(); + for (int i = 0; i < taskViewCount; i++) { + TaskView tv = taskViews.get(i); + tv.getHeaderView().rebindToTask(tv.getTask(), tv.mTouchExplorationEnabled, + tv.mIsDisabledInSafeMode); + } } }); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java index 0543dd5db379..05a85278db16 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java @@ -139,6 +139,7 @@ public class TaskViewHeader extends FrameLayout // Header views ImageView mIconView; TextView mTitleView; + TextView mSubTitleView; ImageView mMoveTaskButton; ImageView mDismissButton; ViewStub mAppOverlayViewStub; @@ -237,6 +238,7 @@ public class TaskViewHeader extends FrameLayout mIconView.setClickable(false); mIconView.setOnLongClickListener(this); mTitleView = (TextView) findViewById(R.id.title); + mSubTitleView = (TextView) findViewById(R.id.sub_title); mDismissButton = (ImageView) findViewById(R.id.dismiss_task); if (ssp.hasFreeformWorkspaceSupport()) { mMoveTaskButton = (ImageView) findViewById(R.id.move_task); @@ -367,6 +369,7 @@ public class TaskViewHeader extends FrameLayout /** Binds the bar view to the task */ public void rebindToTask(Task t, boolean touchExplorationEnabled, boolean disabledInSafeMode) { + SystemServicesProxy ssp = Recents.getSystemServices(); mTask = t; // If an activity icon is defined, then we use that as the primary icon to show in the bar, @@ -384,6 +387,13 @@ public class TaskViewHeader extends FrameLayout mTitleView.setContentDescription(t.contentDescription); mTitleView.setTextColor(t.useLightOnPrimaryColor ? mTaskBarViewLightTextColor : mTaskBarViewDarkTextColor); + if (!t.isDockable && ssp.hasDockedTask()) { + mSubTitleView.setVisibility(View.VISIBLE); + mSubTitleView.setTextColor(t.useLightOnPrimaryColor ? + mTaskBarViewLightTextColor : mTaskBarViewDarkTextColor); + } else { + mSubTitleView.setVisibility(View.GONE); + } mDismissButton.setImageDrawable(t.useLightOnPrimaryColor ? mLightDismissDrawable : mDarkDismissDrawable); mDismissButton.setContentDescription(t.dismissDescription); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index a0c63be9cfba..6be95124ffa6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -1142,6 +1142,11 @@ public abstract class BaseStatusBar extends SystemUI implements } @Override + public void toggleSplitScreen() { + toggleSplitScreenMode(); + } + + @Override public void preloadRecentApps() { int msg = MSG_PRELOAD_RECENT_APPS; mHandler.removeMessages(msg); @@ -1211,6 +1216,13 @@ public abstract class BaseStatusBar extends SystemUI implements } }; + /** + * Toggle docking the app window + * + * @return {@code true} if the app window is docked after the toggle, {@code false} otherwise. + */ + protected abstract boolean toggleSplitScreenMode(); + /** Proxy for RecentsComponent */ protected void showRecents(boolean triggeredFromAltTab) { @@ -1872,7 +1884,7 @@ public abstract class BaseStatusBar extends SystemUI implements return entry; } - protected StatusBarIconView createIcon(StatusBarNotification sbn) { + public StatusBarIconView createIcon(StatusBarNotification sbn) { // Construct the icon. Notification n = sbn.getNotification(); final StatusBarIconView iconView = new StatusBarIconView(mContext, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index 3b960eef84c9..6a984887931d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -72,6 +72,7 @@ public class CommandQueue extends IStatusBar.Stub { private static final int MSG_ADD_QS_TILE = 27 << MSG_SHIFT; private static final int MSG_REMOVE_QS_TILE = 28 << MSG_SHIFT; private static final int MSG_CLICK_QS_TILE = 29 << MSG_SHIFT; + private static final int MSG_TOGGLE_APP_SPLIT_SCREEN = 30 << MSG_SHIFT; public static final int FLAG_EXCLUDE_NONE = 0; public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0; @@ -104,6 +105,7 @@ public class CommandQueue extends IStatusBar.Stub { public void showRecentApps(boolean triggeredFromAltTab); public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey); public void toggleRecentApps(); + public void toggleSplitScreen(); public void preloadRecentApps(); public void toggleKeyboardShortcutsMenu(); public void cancelPreloadRecentApps(); @@ -223,6 +225,13 @@ public class CommandQueue extends IStatusBar.Stub { } } + public void toggleSplitScreen() { + synchronized (mLock) { + mHandler.removeMessages(MSG_TOGGLE_APP_SPLIT_SCREEN); + mHandler.obtainMessage(MSG_TOGGLE_APP_SPLIT_SCREEN, 0, 0, null).sendToTarget(); + } + } + public void toggleRecentApps() { synchronized (mLock) { mHandler.removeMessages(MSG_TOGGLE_RECENT_APPS); @@ -464,6 +473,9 @@ public class CommandQueue extends IStatusBar.Stub { case MSG_CLICK_QS_TILE: mCallbacks.clickTile((ComponentName) msg.obj); break; + case MSG_TOGGLE_APP_SPLIT_SCREEN: + mCallbacks.toggleSplitScreen(); + break; } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java index 212d290a3cf4..123dc699e593 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java @@ -19,6 +19,7 @@ package com.android.systemui.statusbar; import android.view.View; import com.android.systemui.Interpolators; +import com.android.systemui.statusbar.stack.StackStateAnimator; /** * A helper to fade views in and out. @@ -44,7 +45,34 @@ public class CrossFadeHelper { if (view.hasOverlappingRendering()) { view.animate().withLayer(); } + } + + public static void fadeOut(View view, float fadeOutAmount) { + view.animate().cancel(); + if (fadeOutAmount == 1.0f) { + view.setVisibility(View.INVISIBLE); + } else if (view.getVisibility() == View.INVISIBLE) { + view.setVisibility(View.VISIBLE); + } + fadeOutAmount = mapToFadeDuration(fadeOutAmount); + float alpha = Interpolators.ALPHA_OUT.getInterpolation(1.0f - fadeOutAmount); + view.setAlpha(alpha); + updateLayerType(view, alpha); + } + private static float mapToFadeDuration(float fadeOutAmount) { + // Assuming a linear interpolator, we can easily map it to our new duration + float endPoint = (float) ANIMATION_DURATION_LENGTH + / (float) StackStateAnimator.ANIMATION_DURATION_STANDARD; + return Math.min(fadeOutAmount / endPoint, 1.0f); + } + + private static void updateLayerType(View view, float alpha) { + if (view.hasOverlappingRendering() && alpha > 0.0f && alpha < 1.0f) { + view.setLayerType(View.LAYER_TYPE_HARDWARE, null); + } else if (view.getLayerType() == View.LAYER_TYPE_HARDWARE) { + view.setLayerType(View.LAYER_TYPE_NONE, null); + } } public static void fadeIn(final View view) { @@ -62,4 +90,15 @@ public class CrossFadeHelper { view.animate().withLayer(); } } + + public static void fadeIn(View view, float fadeInAmount) { + view.animate().cancel(); + if (view.getVisibility() == View.INVISIBLE) { + view.setVisibility(View.VISIBLE); + } + fadeInAmount = mapToFadeDuration(fadeInAmount); + float alpha = Interpolators.ALPHA_IN.getInterpolation(fadeInAmount); + view.setAlpha(alpha); + updateLayerType(view, alpha); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index c72cec36a024..da125d8f77a6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -868,6 +868,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { public void setUserLocked(boolean userLocked) { mUserLocked = userLocked; + mPrivateLayout.setUserExpanding(userLocked); + if (mIsSummaryWithChildren) { + mChildrenContainer.setUserLocked(userLocked); + } } /** @@ -1174,6 +1178,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { int contentHeight = Math.max(getMinHeight(), height); mPrivateLayout.setContentHeight(contentHeight); mPublicLayout.setContentHeight(contentHeight); + if (mIsSummaryWithChildren) { + mChildrenContainer.setActualHeight(height); + } if (mGuts != null) { mGuts.setActualHeight(height); } @@ -1259,7 +1266,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { return mMaxExpandHeight != 0; } - private NotificationContentView getShowingLayout() { + public NotificationContentView getShowingLayout() { return mShowingPublic ? mPublicLayout : mPrivateLayout; } @@ -1295,8 +1302,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { } @Override - public boolean needsIncreasedPadding() { - return mIsSummaryWithChildren && isGroupExpanded(); + public float getIncreasedPaddingAmount() { + if (mIsSummaryWithChildren) { + if (isGroupExpanded()) { + return 1.0f; + } else if (isUserLocked()) { + return mChildrenContainer.getChildExpandFraction(); + } + } + return 0.0f; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java index c9e1cff9c865..1ff87f551186 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java @@ -391,8 +391,11 @@ public abstract class ExpandableView extends FrameLayout { public void setShadowAlpha(float shadowAlpha) { } - public boolean needsIncreasedPadding() { - return false; + /** + * @return an amount between 0 and 1 of increased padding that this child needs + */ + public float getIncreasedPaddingAmount() { + return 0.0f; } public boolean mustStayOnScreen() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java index bc859229b451..977b37ea13ea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java @@ -48,6 +48,7 @@ public class NotificationContentView extends FrameLayout { private static final int VISIBLE_TYPE_EXPANDED = 1; private static final int VISIBLE_TYPE_HEADSUP = 2; private static final int VISIBLE_TYPE_SINGLELINE = 3; + private static final int UNDEFINED = -1; private final Rect mClipBounds = new Rect(); private final int mMinContractedHeight; @@ -102,6 +103,8 @@ public class NotificationContentView extends FrameLayout { private boolean mExpandable; private boolean mClipToActualHeight = true; private ExpandableNotificationRow mContainingNotification; + private int mTransformationStartVisibleType; + private boolean mUserExpanding; public NotificationContentView(Context context, AttributeSet attrs) { super(context, attrs); @@ -349,6 +352,41 @@ public class NotificationContentView extends FrameLayout { invalidateOutline(); } + private void updateContentTransformation() { + int visibleType = calculateVisibleType(); + if (visibleType != mVisibleType) { + // A new transformation starts + mTransformationStartVisibleType = mVisibleType; + final TransformableView shownView = getTransformableViewForVisibleType(visibleType); + final TransformableView hiddenView = getTransformableViewForVisibleType( + mTransformationStartVisibleType); + shownView.transformFrom(hiddenView, 0.0f); + getViewForVisibleType(visibleType).setVisibility(View.VISIBLE); + hiddenView.transformTo(shownView, 0.0f); + mVisibleType = visibleType; + } + if (mTransformationStartVisibleType != UNDEFINED + && mVisibleType != mTransformationStartVisibleType) { + final TransformableView shownView = getTransformableViewForVisibleType(mVisibleType); + final TransformableView hiddenView = getTransformableViewForVisibleType( + mTransformationStartVisibleType); + float transformationAmount = calculateTransformationAmount(); + shownView.transformFrom(hiddenView, transformationAmount); + hiddenView.transformTo(shownView, transformationAmount); + } else { + updateViewVisibilities(visibleType); + } + } + + private float calculateTransformationAmount() { + int startHeight = getViewForVisibleType(mTransformationStartVisibleType).getHeight(); + int endHeight = getViewForVisibleType(mVisibleType).getHeight(); + int progress = Math.abs(mContentHeight - startHeight); + int totalDistance = Math.abs(endHeight - startHeight); + float amount = (float) progress / (float) totalDistance; + return Math.min(1.0f, amount); + } + public int getContentHeight() { return mContentHeight; } @@ -363,10 +401,14 @@ public class NotificationContentView extends FrameLayout { } public int getMinHeight() { - if (mIsChildInGroup && !isGroupExpanded()) { - return mSingleLineView.getHeight(); - } else { + return getMinHeight(false /* likeGroupExpanded */); + } + + public int getMinHeight(boolean likeGroupExpanded) { + if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded()) { return mContractedChild.getHeight(); + } else { + return mSingleLineView.getHeight(); } } @@ -397,6 +439,10 @@ public class NotificationContentView extends FrameLayout { if (mContractedChild == null) { return; } + if (mUserExpanding) { + updateContentTransformation(); + return; + } int visibleType = calculateVisibleType(); if (visibleType != mVisibleType || force) { if (animate && ((visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null) @@ -492,13 +538,28 @@ public class NotificationContentView extends FrameLayout { * @return one of the static enum types in this view, calculated form the current state */ private int calculateVisibleType() { - boolean noExpandedChild = mExpandedChild == null; - + if (mUserExpanding) { + int height = !mIsChildInGroup || isGroupExpanded() + || mContainingNotification.isExpanded() + ? mContainingNotification.getMaxContentHeight() + : mContainingNotification.getShowingLayout().getMinHeight(); + int expandedVisualType = getVisualTypeForHeight(height); + int collapsedVisualType = getVisualTypeForHeight( + mContainingNotification.getMinExpandHeight()); + return mTransformationStartVisibleType == collapsedVisualType + ? expandedVisualType + : collapsedVisualType; + } int viewHeight = Math.min(mContentHeight, mContainingNotification.getIntrinsicHeight()); + return getVisualTypeForHeight(viewHeight); + } + + private int getVisualTypeForHeight(float viewHeight) { + boolean noExpandedChild = mExpandedChild == null; if (!noExpandedChild && viewHeight == mExpandedChild.getHeight()) { return VISIBLE_TYPE_EXPANDED; } - if (mIsChildInGroup && !isGroupExpanded()) { + if (!mUserExpanding && mIsChildInGroup && !isGroupExpanded()) { return VISIBLE_TYPE_SINGLELINE; } @@ -723,4 +784,15 @@ public class NotificationContentView extends FrameLayout { updateSingleLineView(); } } + + public void setUserExpanding(boolean userExpanding) { + mUserExpanding = userExpanding; + if (userExpanding) { + mTransformationStartVisibleType = mVisibleType; + } else { + mTransformationStartVisibleType = UNDEFINED; + mVisibleType = calculateVisibleType(); + updateViewVisibilities(mVisibleType); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java index 38b649746c6d..009eed79c48a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/TransformableView.java @@ -30,6 +30,7 @@ public interface TransformableView { /** * Get the current state of a view in a transform animation + * * @param fadingView which view we are interested in * @return the current transform state of this viewtype */ @@ -37,18 +38,37 @@ public interface TransformableView { /** * Transform to the given view + * * @param notification the view to transform to */ void transformTo(TransformableView notification, Runnable endRunnable); /** + * Transform to the given view by a specified amount. + * + * @param notification the view to transform to + * @param transformationAmount how much transformation should be done + */ + void transformTo(TransformableView notification, float transformationAmount); + + /** * Transform to this view from the given view + * * @param notification the view to transform from */ void transformFrom(TransformableView notification); /** + * Transform to this view from the given view by a specified amount. + * + * @param notification the view to transform from + * @param transformationAmount how much transformation should be done + */ + void transformFrom(TransformableView notification, float transformationAmount); + + /** * Set this view to be fully visible or gone + * * @param visible */ void setVisible(boolean visible); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java index 63ff5aa06a1a..bf05d1d7d882 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java @@ -16,13 +16,17 @@ package com.android.systemui.statusbar; -import android.os.Handler; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; import android.util.ArrayMap; import android.view.View; import android.view.ViewGroup; +import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.statusbar.notification.TransformState; +import com.android.systemui.statusbar.stack.StackStateAnimator; import java.util.Stack; @@ -33,9 +37,9 @@ public class ViewTransformationHelper implements TransformableView { private static final int TAG_CONTAINS_TRANSFORMED_VIEW = R.id.contains_transformed_view; - private final Handler mHandler = new Handler(); private ArrayMap<Integer, View> mTransformedViews = new ArrayMap<>(); private ArrayMap<Integer, CustomTransformation> mCustomTransformations = new ArrayMap<>(); + private ValueAnimator mViewTransformationAnimation; public void addTransformedView(int key, View transformedView) { mTransformedViews.put(key, transformedView); @@ -59,61 +63,123 @@ public class ViewTransformationHelper implements TransformableView { } @Override - public void transformTo(TransformableView notification, Runnable endRunnable) { - Runnable runnable = endRunnable; + public void transformTo(final TransformableView notification, final Runnable endRunnable) { + if (mViewTransformationAnimation != null) { + mViewTransformationAnimation.cancel(); + } + mViewTransformationAnimation = ValueAnimator.ofFloat(0.0f, 1.0f); + mViewTransformationAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + transformTo(notification, animation.getAnimatedFraction()); + } + }); + mViewTransformationAnimation.setInterpolator(Interpolators.LINEAR); + mViewTransformationAnimation.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); + if (endRunnable != null) { + mViewTransformationAnimation.addListener(new AnimatorListenerAdapter() { + public boolean mCancelled; + + @Override + public void onAnimationEnd(Animator animation) { + endRunnable.run(); + if (!mCancelled) { + setVisible(false); + } else { + abortTransformations(); + } + } + + @Override + public void onAnimationCancel(Animator animation) { + mCancelled = true; + } + }); + } + mViewTransformationAnimation.start(); + } + + @Override + public void transformTo(TransformableView notification, float transformationAmount) { for (Integer viewType : mTransformedViews.keySet()) { TransformState ownState = getCurrentState(viewType); if (ownState != null) { CustomTransformation customTransformation = mCustomTransformations.get(viewType); if (customTransformation != null && customTransformation.transformTo( - ownState, notification, runnable)) { + ownState, notification, transformationAmount)) { ownState.recycle(); - runnable = null; continue; } TransformState otherState = notification.getCurrentState(viewType); if (otherState != null) { - boolean run = ownState.transformViewTo(otherState, runnable); + ownState.transformViewTo(otherState, transformationAmount); otherState.recycle(); - if (run) { - runnable = null; - } } else { // there's no other view available - CrossFadeHelper.fadeOut(mTransformedViews.get(viewType), runnable); - runnable = null; + CrossFadeHelper.fadeOut(mTransformedViews.get(viewType), transformationAmount); } ownState.recycle(); } } - if (runnable != null) { - // We need to post, since the visible type is only set after the transformation is - // started - mHandler.post(runnable); + } + + @Override + public void transformFrom(final TransformableView notification) { + if (mViewTransformationAnimation != null) { + mViewTransformationAnimation.cancel(); } + mViewTransformationAnimation = ValueAnimator.ofFloat(0.0f, 1.0f); + mViewTransformationAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + transformFrom(notification, animation.getAnimatedFraction()); + } + }); + mViewTransformationAnimation.addListener(new AnimatorListenerAdapter() { + public boolean mCancelled; + + @Override + public void onAnimationEnd(Animator animation) { + if (!mCancelled) { + setVisible(true); + } else { + abortTransformations(); + } + } + + @Override + public void onAnimationCancel(Animator animation) { + mCancelled = true; + } + }); + mViewTransformationAnimation.setInterpolator(Interpolators.LINEAR); + mViewTransformationAnimation.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD); + mViewTransformationAnimation.start(); } @Override - public void transformFrom(TransformableView notification) { + public void transformFrom(TransformableView notification, float transformationAmount) { for (Integer viewType : mTransformedViews.keySet()) { TransformState ownState = getCurrentState(viewType); if (ownState != null) { CustomTransformation customTransformation = mCustomTransformations.get(viewType); if (customTransformation != null && customTransformation.transformFrom( - ownState, notification)) { + ownState, notification, transformationAmount)) { ownState.recycle(); continue; } TransformState otherState = notification.getCurrentState(viewType); if (otherState != null) { - ownState.transformViewFrom(otherState); + ownState.transformViewFrom(otherState, transformationAmount); otherState.recycle(); } else { // There's no other view, lets fade us in // Certain views need to prepare the fade in and make sure its children are // completely visible. An example is the notification header. - ownState.prepareFadeIn(); - CrossFadeHelper.fadeIn(mTransformedViews.get(viewType)); + if (transformationAmount == 0.0f) { + ownState.prepareFadeIn(); + } + CrossFadeHelper.fadeIn(mTransformedViews.get(viewType), transformationAmount); } ownState.recycle(); } @@ -131,6 +197,16 @@ public class ViewTransformationHelper implements TransformableView { } } + private void abortTransformations() { + for (Integer viewType : mTransformedViews.keySet()) { + TransformState ownState = getCurrentState(viewType); + if (ownState != null) { + ownState.abortTransformation(); + ownState.recycle(); + } + } + } + /** * Add the remaining transformation views such that all views are being transformed correctly * @param viewRoot the root below which all elements need to be transformed @@ -173,22 +249,44 @@ public class ViewTransformationHelper implements TransformableView { } } - public interface CustomTransformation { + public static abstract class CustomTransformation { /** * Transform a state to the given view * @param ownState the state to transform * @param notification the view to transform to + * @param transformationAmount how much transformation should be done * @return whether a custom transformation is performed */ - boolean transformTo(TransformState ownState, TransformableView notification, - Runnable endRunnable); + public abstract boolean transformTo(TransformState ownState, + TransformableView notification, + float transformationAmount); /** * Transform to this state from the given view * @param ownState the state to transform to * @param notification the view to transform from + * @param transformationAmount how much transformation should be done * @return whether a custom transformation is performed */ - boolean transformFrom(TransformState ownState, TransformableView notification); + public abstract boolean transformFrom(TransformState ownState, + TransformableView notification, + float transformationAmount); + + /** + * Perform a custom initialisation before transforming. + * + * @param ownState our own state + * @param otherState the other state + * @return whether a custom initialization is done + */ + public boolean initTransformation(TransformState ownState, + TransformState otherState) { + return false; + } + + public boolean customTransformTarget(TransformState ownState, + TransformState otherState) { + return false; + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java index 81483c67fd8a..b66e9f313e9a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java @@ -46,7 +46,7 @@ public class HeaderTransformState extends TransformState { } @Override - public boolean transformViewTo(TransformState otherState, Runnable endRunnable) { + public boolean transformViewTo(TransformState otherState, float transformationAmount) { // if the transforming notification has a header, we have ensured that it looks the same // but the expand button, so lets fade just that one and transform the work profile icon. if (!(mTransformedView instanceof NotificationHeaderView)) { @@ -62,14 +62,14 @@ public class HeaderTransformState extends TransformState { if (headerChild != mExpandButton) { headerChild.setVisibility(View.INVISIBLE); } else { - CrossFadeHelper.fadeOut(mExpandButton, endRunnable); + CrossFadeHelper.fadeOut(mExpandButton, transformationAmount); } } return true; } @Override - public void transformViewFrom(TransformState otherState) { + public void transformViewFrom(TransformState otherState, float transformationAmount) { // if the transforming notification has a header, we have ensured that it looks the same // but the expand button, so lets fade just that one and transform the work profile icon. if (!(mTransformedView instanceof NotificationHeaderView)) { @@ -85,12 +85,13 @@ public class HeaderTransformState extends TransformState { continue; } if (headerChild == mExpandButton) { - CrossFadeHelper.fadeIn(mExpandButton); + CrossFadeHelper.fadeIn(mExpandButton, transformationAmount); } else { headerChild.setVisibility(View.VISIBLE); if (headerChild == mWorkProfileIcon) { - mWorkProfileState.animateViewFrom( - ((HeaderTransformState) otherState).mWorkProfileState); + mWorkProfileState.transformViewFullyFrom( + ((HeaderTransformState) otherState).mWorkProfileState, + transformationAmount); } } } 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 81144d553685..c80cad836f48 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java @@ -71,13 +71,13 @@ public class HybridNotificationView extends AlphaOptimizedLinearLayout new ViewTransformationHelper.CustomTransformation() { @Override public boolean transformTo(TransformState ownState, TransformableView notification, - Runnable endRunnable) { + float transformationAmount) { // We want to transform to the same y location as the title TransformState otherState = notification.getCurrentState( TRANSFORMING_VIEW_TITLE); - CrossFadeHelper.fadeOut(mTextView, endRunnable); + CrossFadeHelper.fadeOut(mTextView, transformationAmount); if (otherState != null) { - ownState.animateViewVerticalTo(otherState, endRunnable); + ownState.transformViewVerticalTo(otherState, transformationAmount); otherState.recycle(); } return true; @@ -85,13 +85,13 @@ public class HybridNotificationView extends AlphaOptimizedLinearLayout @Override public boolean transformFrom(TransformState ownState, - TransformableView notification) { + TransformableView notification, float transformationAmount) { // We want to transform from the same y location as the title TransformState otherState = notification.getCurrentState( TRANSFORMING_VIEW_TITLE); - CrossFadeHelper.fadeIn(mTextView); + CrossFadeHelper.fadeIn(mTextView, transformationAmount); if (otherState != null) { - ownState.animateViewVerticalFrom(otherState); + ownState.transformViewVerticalFrom(otherState, transformationAmount); otherState.recycle(); } return true; @@ -133,11 +133,21 @@ public class HybridNotificationView extends AlphaOptimizedLinearLayout } @Override + public void transformTo(TransformableView notification, float transformationAmount) { + mTransformationHelper.transformTo(notification, transformationAmount); + } + + @Override public void transformFrom(TransformableView notification) { mTransformationHelper.transformFrom(notification); } @Override + public void transformFrom(TransformableView notification, float transformationAmount) { + mTransformationHelper.transformFrom(notification, transformationAmount); + } + + @Override public void setVisible(boolean visible) { setVisibility(visible ? View.VISIBLE : View.INVISIBLE); mTransformationHelper.setVisible(visible); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java index e891a977abce..45027c0dba7e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java @@ -62,7 +62,7 @@ public class ImageTransformState extends TransformState { } @Override - protected boolean animateScale() { + protected boolean transformScale() { return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java index 5a71cafb1dd1..000f957f49bb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java @@ -142,7 +142,8 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { protected void updateTransformedTypes() { mTransformationHelper.reset(); - mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_HEADER, mNotificationHeader); + mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_HEADER, + mNotificationHeader); } @Override @@ -299,11 +300,21 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { } @Override + public void transformTo(TransformableView notification, float transformationAmount) { + mTransformationHelper.transformTo(notification, transformationAmount); + } + + @Override public void transformFrom(TransformableView notification) { mTransformationHelper.transformFrom(notification); } @Override + public void transformFrom(TransformableView notification, float transformationAmount) { + mTransformationHelper.transformFrom(notification, transformationAmount); + } + + @Override public void setVisible(boolean visible) { super.setVisible(visible); mTransformationHelper.setVisible(visible); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java index 0c21f0b2c962..fd4eca8cad91 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java @@ -49,76 +49,65 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp new ViewTransformationHelper.CustomTransformation() { @Override public boolean transformTo(TransformState ownState, - TransformableView notification, final Runnable endRunnable) { + TransformableView notification, final float transformationAmount) { if (!(notification instanceof HybridNotificationView)) { return false; } TransformState otherState = notification.getCurrentState( TRANSFORMING_VIEW_TITLE); final View text = ownState.getTransformedView(); - CrossFadeHelper.fadeOut(text, endRunnable); + CrossFadeHelper.fadeOut(text, transformationAmount); if (otherState != null) { - int[] otherStablePosition = otherState.getLaidOutLocationOnScreen(); - int[] ownPosition = ownState.getLaidOutLocationOnScreen(); - text.animate() - .translationY((otherStablePosition[1] - + otherState.getTransformedView().getHeight() - - ownPosition[1]) * 0.33f) - .setDuration( - StackStateAnimator.ANIMATION_DURATION_STANDARD) - .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) - .withEndAction(new Runnable() { - @Override - public void run() { - if (endRunnable != null) { - endRunnable.run(); - } - TransformState.setClippingDeactivated(text, - false); - } - }); - TransformState.setClippingDeactivated(text, true); + ownState.transformViewVerticalTo(otherState, this, + transformationAmount); otherState.recycle(); } return true; } @Override + public boolean customTransformTarget(TransformState ownState, + TransformState otherState) { + float endY = getTransformationY(ownState, otherState); + ownState.setTransformationEndY(endY); + return true; + } + + @Override public boolean transformFrom(TransformState ownState, - TransformableView notification) { + TransformableView notification, float transformationAmount) { if (!(notification instanceof HybridNotificationView)) { return false; } TransformState otherState = notification.getCurrentState( TRANSFORMING_VIEW_TITLE); final View text = ownState.getTransformedView(); - boolean isVisible = text.getVisibility() == View.VISIBLE; - CrossFadeHelper.fadeIn(text); + CrossFadeHelper.fadeIn(text, transformationAmount); if (otherState != null) { - int[] otherStablePosition = otherState.getLaidOutLocationOnScreen(); - int[] ownStablePosition = ownState.getLaidOutLocationOnScreen(); - if (!isVisible) { - text.setTranslationY((otherStablePosition[1] - + otherState.getTransformedView().getHeight() - - ownStablePosition[1]) * 0.33f); - } - text.animate() - .translationY(0) - .setDuration( - StackStateAnimator.ANIMATION_DURATION_STANDARD) - .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) - .withEndAction(new Runnable() { - @Override - public void run() { - TransformState.setClippingDeactivated(text, - false); - } - }); - TransformState.setClippingDeactivated(text, true); + ownState.transformViewVerticalFrom(otherState, this, + transformationAmount); otherState.recycle(); } return true; } + + @Override + public boolean initTransformation(TransformState ownState, + TransformState otherState) { + float startY = getTransformationY(ownState, otherState); + ownState.setTransformationStartY(startY); + return true; + } + + private float getTransformationY(TransformState ownState, + TransformState otherState) { + int[] otherStablePosition = otherState.getLaidOutLocationOnScreen(); + int[] ownStablePosition = ownState.getLaidOutLocationOnScreen(); + return (otherStablePosition[1] + + otherState.getTransformedView().getHeight() + - ownStablePosition[1]) * 0.33f; + } + }, TRANSFORMING_VIEW_TEXT); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java index 7089b7811e88..47386575de4f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java @@ -34,4 +34,8 @@ public class NotificationUtils { v.setTag(R.id.icon_is_grayscale, grayscale); return grayscale; } + + public static float interpolate(float start, float end, float amount) { + return start * (1.0f - amount) + end * amount; + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java index 328f8b55b0ef..d3503e7516df 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java @@ -98,12 +98,22 @@ public abstract class NotificationViewWrapper implements TransformableView { } @Override + public void transformTo(TransformableView notification, float transformationAmount) { + CrossFadeHelper.fadeOut(mView, transformationAmount); + } + + @Override public void transformFrom(TransformableView notification) { // By default we are fading in completely CrossFadeHelper.fadeIn(mView); } @Override + public void transformFrom(TransformableView notification, float transformationAmount) { + CrossFadeHelper.fadeIn(mView, transformationAmount); + } + + @Override public void setVisible(boolean visible) { mView.animate().cancel(); mView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java index 67d31be7f511..f04fe5e11231 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java @@ -30,23 +30,30 @@ import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.ExpandableNotificationRow; -import com.android.systemui.statusbar.stack.StackStateAnimator; +import com.android.systemui.statusbar.ViewTransformationHelper; /** * A transform state of a view. */ public class TransformState { - private static final int ANIMATE_X = 0x1; - private static final int ANIMATE_Y = 0x10; - private static final int ANIMATE_ALL = ANIMATE_X | ANIMATE_Y; + private static final float UNDEFINED = -1f; + private static final int TRANSOFORM_X = 0x1; + private static final int TRANSOFORM_Y = 0x10; + private static final int TRANSOFORM_ALL = TRANSOFORM_X | TRANSOFORM_Y; private static final int CLIP_CLIPPING_SET = R.id.clip_children_set_tag; private static final int CLIP_CHILDREN_TAG = R.id.clip_children_tag; private static final int CLIP_TO_PADDING = R.id.clip_to_padding_tag; + private static final int TRANSFORMATION_START_X = R.id.transformation_start_x_tag; + private static final int TRANSFORMATION_START_Y = R.id.transformation_start_y_tag; + private static final int TRANSFORMATION_START_SCLALE_X = R.id.transformation_start_scale_x_tag; + private static final int TRANSFORMATION_START_SCLALE_Y = R.id.transformation_start_scale_y_tag; private static Pools.SimplePool<TransformState> sInstancePool = new Pools.SimplePool<>(40); protected View mTransformedView; private int[] mOwnPosition = new int[2]; + private float mTransformationEndY = UNDEFINED; + private float mTransformationEndX = UNDEFINED; public void initFrom(View view) { mTransformedView = view; @@ -55,129 +62,233 @@ public class TransformState { /** * Transforms the {@link #mTransformedView} from the given transformviewstate * @param otherState the state to transform from + * @param transformationAmount how much to transform */ - public void transformViewFrom(TransformState otherState) { + public void transformViewFrom(TransformState otherState, float transformationAmount) { mTransformedView.animate().cancel(); if (sameAs(otherState)) { - // We have the same content, lets show ourselves - mTransformedView.setAlpha(1.0f); - mTransformedView.setVisibility(View.VISIBLE); + if (mTransformedView.getVisibility() == View.INVISIBLE) { + // We have the same content, lets show ourselves + mTransformedView.setAlpha(1.0f); + mTransformedView.setVisibility(View.VISIBLE); + } } else { - CrossFadeHelper.fadeIn(mTransformedView); + CrossFadeHelper.fadeIn(mTransformedView, transformationAmount); } - animateViewFrom(otherState); + transformViewFullyFrom(otherState, transformationAmount); + } + + public void transformViewFullyFrom(TransformState otherState, float transformationAmount) { + transformViewFrom(otherState, TRANSOFORM_ALL, null, transformationAmount); } - public void animateViewFrom(TransformState otherState) { - animateViewFrom(otherState, ANIMATE_ALL); + public void transformViewVerticalFrom(TransformState otherState, + ViewTransformationHelper.CustomTransformation customTransformation, + float transformationAmount) { + transformViewFrom(otherState, TRANSOFORM_Y, customTransformation, transformationAmount); } - public void animateViewVerticalFrom(TransformState otherState) { - animateViewFrom(otherState, ANIMATE_Y); + public void transformViewVerticalFrom(TransformState otherState, float transformationAmount) { + transformViewFrom(otherState, TRANSOFORM_Y, null, transformationAmount); } - private void animateViewFrom(TransformState otherState, int animationFlags) { + private void transformViewFrom(TransformState otherState, int transformationFlags, + ViewTransformationHelper.CustomTransformation customTransformation, + float transformationAmount) { final View transformedView = mTransformedView; + boolean transformX = (transformationFlags & TRANSOFORM_X) != 0; + boolean transformY = (transformationFlags & TRANSOFORM_Y) != 0; + boolean transformScale = transformScale(); // lets animate the positions correctly - int[] otherPosition = otherState.getLocationOnScreen(); - int[] ownStablePosition = getLaidOutLocationOnScreen(); - if ((animationFlags & ANIMATE_X) != 0) { - transformedView.setTranslationX(otherPosition[0] - ownStablePosition[0]); - transformedView.animate().translationX(0); + if (transformationAmount == 0.0f) { + int[] otherPosition = otherState.getLocationOnScreen(); + int[] ownStablePosition = getLaidOutLocationOnScreen(); + if (customTransformation == null + || !customTransformation.initTransformation(this, otherState)) { + if (transformX) { + setTransformationStartX(otherPosition[0] - ownStablePosition[0]); + } + if (transformY) { + setTransformationStartY(otherPosition[1] - ownStablePosition[1]); + } + // we also want to animate the scale if we're the same + View otherView = otherState.getTransformedView(); + if (transformScale && otherView.getWidth() != transformedView.getWidth()) { + setTransformationStartScaleX(otherView.getWidth() * otherView.getScaleX() + / (float) transformedView.getWidth()); + transformedView.setPivotX(0); + } else { + setTransformationStartScaleX(UNDEFINED); + } + if (transformScale && otherView.getHeight() != transformedView.getHeight()) { + setTransformationStartScaleY(otherView.getHeight() * otherView.getScaleY() + / (float) transformedView.getHeight()); + transformedView.setPivotY(0); + } else { + setTransformationStartScaleY(UNDEFINED); + } + } + if (!transformX) { + setTransformationStartX(UNDEFINED); + } + if (!transformY) { + setTransformationStartY(UNDEFINED); + } + if (!transformScale) { + setTransformationStartScaleX(UNDEFINED); + setTransformationStartScaleY(UNDEFINED); + } + setClippingDeactivated(transformedView, true); } - if ((animationFlags & ANIMATE_Y) != 0) { - transformedView.setTranslationY(otherPosition[1] - ownStablePosition[1]); - transformedView.animate().translationY(0); + float interpolatedValue = Interpolators.FAST_OUT_SLOW_IN.getInterpolation( + transformationAmount); + if (transformX) { + transformedView.setTranslationX(NotificationUtils.interpolate(getTransformationStartX(), + 0.0f, + interpolatedValue)); } - if (animateScale()) { - // we also want to animate the scale if we're the same - View otherView = otherState.getTransformedView(); - if (otherView.getWidth() != transformedView.getWidth()) { - float scaleX = (otherView.getWidth() * otherView.getScaleX() - / (float) transformedView.getWidth()); - transformedView.setScaleX(scaleX); - transformedView.setPivotX(0); - transformedView.animate().scaleX(1.0f); + if (transformY) { + transformedView.setTranslationY(NotificationUtils.interpolate(getTransformationStartY(), + 0.0f, + interpolatedValue)); + } + if (transformScale) { + float transformationStartScaleX = getTransformationStartScaleX(); + if (transformationStartScaleX != UNDEFINED) { + transformedView.setScaleX( + NotificationUtils.interpolate(transformationStartScaleX, + 1.0f, + interpolatedValue)); } - if (otherView.getHeight() != transformedView.getHeight()) { - float scaleY = (otherView.getHeight() * otherView.getScaleY() - / (float) transformedView.getHeight()); - transformedView.setScaleY(scaleY); - transformedView.setPivotY(0); - transformedView.animate().scaleY(1.0f); + float transformationStartScaleY = getTransformationStartScaleY(); + if (transformationStartScaleY != UNDEFINED) { + transformedView.setScaleY( + NotificationUtils.interpolate(transformationStartScaleY, + 1.0f, + interpolatedValue)); } } - transformedView.animate() - .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) - .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD) - .withEndAction(new Runnable() { - @Override - public void run() { - setClippingDeactivated(transformedView, false); - } - }); - setClippingDeactivated(transformedView, true); } - protected boolean animateScale() { + protected boolean transformScale() { return false; } /** * Transforms the {@link #mTransformedView} to the given transformviewstate * @param otherState the state to transform from - * @param endRunnable a runnable to run at the end of the animation + * @param transformationAmount how much to transform * @return whether an animation was started */ - public boolean transformViewTo(TransformState otherState, final Runnable endRunnable) { + public boolean transformViewTo(TransformState otherState, float transformationAmount) { mTransformedView.animate().cancel(); if (sameAs(otherState)) { // We have the same text, lets show ourselfs - mTransformedView.setAlpha(0.0f); - mTransformedView.setVisibility(View.INVISIBLE); + if (mTransformedView.getVisibility() == View.VISIBLE) { + mTransformedView.setAlpha(0.0f); + mTransformedView.setVisibility(View.INVISIBLE); + } return false; } else { - CrossFadeHelper.fadeOut(mTransformedView, endRunnable); + CrossFadeHelper.fadeOut(mTransformedView, transformationAmount); } - animateViewTo(otherState, endRunnable); + transformViewFullyTo(otherState, transformationAmount); return true; } - public void animateViewTo(TransformState otherState, Runnable endRunnable) { - animateViewTo(otherState, endRunnable, ANIMATE_ALL); + public void transformViewFullyTo(TransformState otherState, float transformationAmount) { + transformViewTo(otherState, TRANSOFORM_ALL, null, transformationAmount); + } + + public void transformViewVerticalTo(TransformState otherState, + ViewTransformationHelper.CustomTransformation customTransformation, + float transformationAmount) { + transformViewTo(otherState, TRANSOFORM_Y, customTransformation, transformationAmount); } - public void animateViewVerticalTo(TransformState otherState, Runnable endRunnable) { - animateViewTo(otherState, endRunnable, ANIMATE_Y); + public void transformViewVerticalTo(TransformState otherState, float transformationAmount) { + transformViewTo(otherState, TRANSOFORM_Y, null, transformationAmount); } - private void animateViewTo(TransformState otherState, final Runnable endRunnable, - int animationFlags) { + private void transformViewTo(TransformState otherState, int transformationFlags, + ViewTransformationHelper.CustomTransformation customTransformation, + float transformationAmount) { + // lets animate the positions correctly + + final View transformedView = mTransformedView; + boolean transformX = (transformationFlags & TRANSOFORM_X) != 0; + boolean transformY = (transformationFlags & TRANSOFORM_Y) != 0; + boolean transformScale = transformScale(); // lets animate the positions correctly + if (transformationAmount == 0.0f) { + if (transformX) { + float transformationStartX = getTransformationStartX(); + float start = transformationStartX != UNDEFINED ? transformationStartX + : transformedView.getTranslationX(); + setTransformationStartX(start); + } + if (transformY) { + float transformationStartY = getTransformationStartY(); + float start = transformationStartY != UNDEFINED ? transformationStartY + : transformedView.getTranslationY(); + setTransformationStartY(start); + } + View otherView = otherState.getTransformedView(); + if (transformScale && otherView.getWidth() != transformedView.getWidth()) { + setTransformationStartScaleX(transformedView.getScaleX()); + transformedView.setPivotX(0); + } else { + setTransformationStartScaleX(UNDEFINED); + } + if (transformScale && otherView.getHeight() != transformedView.getHeight()) { + setTransformationStartScaleY(transformedView.getScaleY()); + transformedView.setPivotY(0); + } else { + setTransformationStartScaleY(UNDEFINED); + } + setClippingDeactivated(transformedView, true); + } + float interpolatedValue = Interpolators.FAST_OUT_SLOW_IN.getInterpolation( + transformationAmount); int[] otherStablePosition = otherState.getLaidOutLocationOnScreen(); int[] ownPosition = getLaidOutLocationOnScreen(); - final View transformedView = mTransformedView; - if ((animationFlags & ANIMATE_X) != 0) { - transformedView.animate() - .translationX(otherStablePosition[0] - ownPosition[0]); + if (transformX) { + float endX = otherStablePosition[0] - ownPosition[0]; + if (customTransformation != null + && customTransformation.customTransformTarget(this, otherState)) { + endX = mTransformationEndX; + } + transformedView.setTranslationX(NotificationUtils.interpolate(getTransformationStartX(), + endX, + interpolatedValue)); } - if ((animationFlags & ANIMATE_Y) != 0) { - transformedView.animate() - .translationY(otherStablePosition[1] - ownPosition[1]); + if (transformY) { + float endY = otherStablePosition[1] - ownPosition[1]; + if (customTransformation != null + && customTransformation.customTransformTarget(this, otherState)) { + endY = mTransformationEndY; + } + transformedView.setTranslationY(NotificationUtils.interpolate(getTransformationStartY(), + endY, + interpolatedValue)); + } + if (transformScale) { + View otherView = otherState.getTransformedView(); + float transformationStartScaleX = getTransformationStartScaleX(); + if (transformationStartScaleX != UNDEFINED) { + transformedView.setScaleX( + NotificationUtils.interpolate(transformationStartScaleX, + (otherView.getWidth() / (float) transformedView.getWidth()), + interpolatedValue)); + } + float transformationStartScaleY = getTransformationStartScaleY(); + if (transformationStartScaleY != UNDEFINED) { + transformedView.setScaleY( + NotificationUtils.interpolate(transformationStartScaleY, + (otherView.getHeight() / (float) transformedView.getHeight()), + interpolatedValue)); + } } - transformedView.animate() - .setInterpolator(Interpolators.FAST_OUT_SLOW_IN) - .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD) - .withEndAction(new Runnable() { - @Override - public void run() { - if (endRunnable != null) { - endRunnable.run(); - } - setClippingDeactivated(transformedView, false); - } - }); - setClippingDeactivated(transformedView, true); } public static void setClippingDeactivated(final View transformedView, boolean deactivated) { @@ -281,8 +392,54 @@ public class TransformState { } } + public void setTransformationEndY(float transformationEndY) { + mTransformationEndY = transformationEndY; + } + + public void setTransformationEndX(float transformationEndX) { + mTransformationEndX = transformationEndX; + } + + public float getTransformationStartX() { + Object tag = mTransformedView.getTag(TRANSFORMATION_START_X); + return tag == null ? UNDEFINED : (float) tag; + } + + public float getTransformationStartY() { + Object tag = mTransformedView.getTag(TRANSFORMATION_START_Y); + return tag == null ? UNDEFINED : (float) tag; + } + + public float getTransformationStartScaleX() { + Object tag = mTransformedView.getTag(TRANSFORMATION_START_SCLALE_X); + return tag == null ? UNDEFINED : (float) tag; + } + + public float getTransformationStartScaleY() { + Object tag = mTransformedView.getTag(TRANSFORMATION_START_SCLALE_Y); + return tag == null ? UNDEFINED : (float) tag; + } + + public void setTransformationStartX(float transformationStartX) { + mTransformedView.setTag(TRANSFORMATION_START_X, transformationStartX); + } + + public void setTransformationStartY(float transformationStartY) { + mTransformedView.setTag(TRANSFORMATION_START_Y, transformationStartY); + } + + private void setTransformationStartScaleX(float startScaleX) { + mTransformedView.setTag(TRANSFORMATION_START_SCLALE_X, startScaleX); + } + + private void setTransformationStartScaleY(float startScaleY) { + mTransformedView.setTag(TRANSFORMATION_START_SCLALE_Y, startScaleY); + } + protected void reset() { mTransformedView = null; + mTransformationEndX = UNDEFINED; + mTransformationEndY = UNDEFINED; } public void setVisible(boolean visible) { @@ -306,6 +463,15 @@ public class TransformState { mTransformedView.setTranslationY(0); mTransformedView.setScaleX(1.0f); mTransformedView.setScaleY(1.0f); + setClippingDeactivated(mTransformedView, false); + abortTransformation(); + } + + public void abortTransformation() { + mTransformedView.setTag(TRANSFORMATION_START_X, UNDEFINED); + mTransformedView.setTag(TRANSFORMATION_START_Y, UNDEFINED); + mTransformedView.setTag(TRANSFORMATION_START_SCLALE_X, UNDEFINED); + mTransformedView.setTag(TRANSFORMATION_START_SCLALE_Y, UNDEFINED); } public static TransformState obtain() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index d25e99baf0c9..ac714e737210 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -1144,31 +1144,42 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, @Override public boolean onLongClick(View v) { - if (mRecents != null) { - int dockSide = WindowManagerProxy.getInstance().getDockSide(); - if (dockSide == WindowManager.DOCKED_INVALID) { - Point realSize = new Point(); - mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY) - .getRealSize(realSize); - Rect initialBounds= new Rect(0, 0, realSize.x, realSize.y); - boolean docked = mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE, - ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, - initialBounds); - if (docked) { - MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS); - return true; - } - } else { - EventBus.getDefault().send(new UndockingTaskEvent()); - MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS); - return true; - } - + if (mRecents == null) { + return false; + } + boolean initiallyDocked = WindowManagerProxy.getInstance().getDockSide() + == WindowManager.DOCKED_INVALID; + boolean dockedAtEnd = toggleSplitScreenMode(); + if (dockedAtEnd != initiallyDocked) { + int logAction = dockedAtEnd ? MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS + : MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS; + MetricsLogger.action(mContext, logAction); + return true; } return false; } }; + @Override + protected boolean toggleSplitScreenMode() { + if (mRecents == null) { + return false; + } + int dockSide = WindowManagerProxy.getInstance().getDockSide(); + if (dockSide == WindowManager.DOCKED_INVALID) { + Point realSize = new Point(); + mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY) + .getRealSize(realSize); + Rect initialBounds= new Rect(0, 0, realSize.x, realSize.y); + return mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE, + ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, + initialBounds); + } else { + EventBus.getDefault().send(new UndockingTaskEvent()); + return false; + } + } + private final View.OnLongClickListener mLongPressHomeListener = new View.OnLongClickListener() { @Override @@ -4089,7 +4100,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, ExpandableNotificationRow row = null; if (expandView instanceof ExpandableNotificationRow) { row = (ExpandableNotificationRow) expandView; - row.setUserExpanded(true); + row.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */); } boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId) || !mShowLockscreenNotifications || mFalsingManager.shouldEnforceBouncer(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java index 3bd68a945592..ab347686be81 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java @@ -80,13 +80,13 @@ public class BrightnessMirrorController { // Original is slightly larger than the mirror, so make sure to use the center for the // positioning. - int originalX = mInt2Cache[0] + original.getWidth()/2; - int originalY = mInt2Cache[1]; + int originalX = mInt2Cache[0] + original.getWidth() / 2; + int originalY = mInt2Cache[1] + original.getHeight() / 2; mBrightnessMirror.setTranslationX(0); mBrightnessMirror.setTranslationY(0); mBrightnessMirror.getLocationInWindow(mInt2Cache); - int mirrorX = mInt2Cache[0] + mBrightnessMirror.getWidth()/2; - int mirrorY = mInt2Cache[1]; + int mirrorX = mInt2Cache[0] + mBrightnessMirror.getWidth() / 2; + int mirrorY = mInt2Cache[1] + mBrightnessMirror.getHeight() / 2; mBrightnessMirror.setTranslationX(originalX - mirrorX); mBrightnessMirror.setTranslationY(originalY - mirrorY); } 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 49aec423db1c..030c8b737e84 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java @@ -29,6 +29,7 @@ import com.android.systemui.statusbar.CrossFadeHelper; 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.notification.NotificationUtils; import com.android.systemui.statusbar.phone.NotificationPanelView; import java.util.ArrayList; @@ -60,6 +61,8 @@ public class NotificationChildrenContainer extends ViewGroup { private ViewState mGroupOverFlowState; private int mRealHeight; private int mLayoutDirection = LAYOUT_DIRECTION_UNDEFINED; + private boolean mUserLocked; + private int mActualHeight; public NotificationChildrenContainer(Context context) { this(context, null); @@ -281,27 +284,45 @@ public class NotificationChildrenContainer extends ViewGroup { */ private int getIntrinsicHeight(float maxAllowedVisibleChildren) { int intrinsicHeight = mNotificationHeaderHeight; - if (mChildrenExpanded) { - intrinsicHeight += mNotificatonTopPadding; - } int visibleChildren = 0; int childCount = mChildren.size(); + boolean firstChild = true; + float expandFactor = 0; + if (mUserLocked) { + expandFactor = getChildExpandFraction(); + } for (int i = 0; i < childCount; i++) { if (visibleChildren >= maxAllowedVisibleChildren) { break; } + if (!firstChild) { + if (mUserLocked) { + intrinsicHeight += NotificationUtils.interpolate(mChildPadding, mDividerHeight, + expandFactor); + } else { + intrinsicHeight += mChildrenExpanded ? mDividerHeight : mChildPadding; + } + } else { + if (mUserLocked) { + intrinsicHeight += NotificationUtils.interpolate( + 0, + mNotificatonTopPadding + mDividerHeight, + expandFactor); + } else { + intrinsicHeight += mChildrenExpanded + ? mNotificatonTopPadding + mDividerHeight + : 0; + } + firstChild = false; + } ExpandableNotificationRow child = mChildren.get(i); intrinsicHeight += child.getIntrinsicHeight(); visibleChildren++; } - if (visibleChildren > 0) { - if (mChildrenExpanded) { - intrinsicHeight += visibleChildren * mDividerHeight; - } else { - intrinsicHeight += (visibleChildren - 1) * mChildPadding; - } - } - if (!mChildrenExpanded) { + if (mUserLocked) { + intrinsicHeight += NotificationUtils.interpolate(mCollapsedBottompadding, 0.0f, + expandFactor); + } else if (!mChildrenExpanded) { intrinsicHeight += mCollapsedBottompadding; } return intrinsicHeight; @@ -323,12 +344,28 @@ public class NotificationChildrenContainer extends ViewGroup { int lastVisibleIndex = hasOverflow ? maxAllowedVisibleChildren - 2 : maxAllowedVisibleChildren - 1; + float expandFactor = 0; + if (mUserLocked) { + expandFactor = getChildExpandFraction(); + } for (int i = 0; i < childCount; i++) { ExpandableNotificationRow child = mChildren.get(i); if (!firstChild) { - yPosition += mChildrenExpanded ? mDividerHeight : mChildPadding; + if (mUserLocked) { + yPosition += NotificationUtils.interpolate(mChildPadding, mDividerHeight, + expandFactor); + } else { + yPosition += mChildrenExpanded ? mDividerHeight : mChildPadding; + } } else { - yPosition += mChildrenExpanded ? mNotificatonTopPadding + mDividerHeight : 0; + if (mUserLocked) { + yPosition += NotificationUtils.interpolate( + 0, + mNotificatonTopPadding + mDividerHeight, + expandFactor); + } else { + yPosition += mChildrenExpanded ? mNotificatonTopPadding + mDividerHeight : 0; + } firstChild = false; } StackViewState childState = resultState.getViewStateForView(child); @@ -375,6 +412,7 @@ public class NotificationChildrenContainer extends ViewGroup { public void applyState(StackScrollState state) { int childCount = mChildren.size(); ViewState tmpState = new ViewState(); + float expandFraction = getChildExpandFraction(); for (int i = 0; i < childCount; i++) { ExpandableNotificationRow child = mChildren.get(i); StackViewState viewState = state.getViewStateForView(child); @@ -384,7 +422,11 @@ public class NotificationChildrenContainer extends ViewGroup { View divider = mDividers.get(i); tmpState.initFrom(divider); tmpState.yTranslation = viewState.yTranslation - mDividerHeight; - tmpState.alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0; + float alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0; + if (mUserLocked && viewState.alpha != 0) { + alpha = NotificationUtils.interpolate(0, 0.5f, expandFraction); + } + tmpState.alpha = alpha; state.applyViewState(divider, tmpState); } if (mGroupOverflowContainer != null) { @@ -407,6 +449,7 @@ public class NotificationChildrenContainer extends ViewGroup { long baseDelay, long duration) { int childCount = mChildren.size(); ViewState tmpState = new ViewState(); + float expandFraction = getChildExpandFraction(); for (int i = childCount - 1; i >= 0; i--) { ExpandableNotificationRow child = mChildren.get(i); StackViewState viewState = state.getViewStateForView(child); @@ -416,7 +459,11 @@ public class NotificationChildrenContainer extends ViewGroup { View divider = mDividers.get(i); tmpState.initFrom(divider); tmpState.yTranslation = viewState.yTranslation - mDividerHeight; - tmpState.alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0; + float alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0; + if (mUserLocked && viewState.alpha != 0) { + alpha = NotificationUtils.interpolate(0, 0.5f, expandFraction); + } + tmpState.alpha = alpha; stateAnimator.startViewAnimations(divider, tmpState, baseDelay, duration); } if (mGroupOverflowContainer != null) { @@ -449,7 +496,70 @@ public class NotificationChildrenContainer extends ViewGroup { } public int getMaxContentHeight() { - return getIntrinsicHeight(NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED); + int maxContentHeight = mNotificationHeaderHeight + mNotificatonTopPadding; + int visibleChildren = 0; + int childCount = mChildren.size(); + for (int i = 0; i < childCount; i++) { + if (visibleChildren >= NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED) { + break; + } + ExpandableNotificationRow child = mChildren.get(i); + float childHeight = child.isExpanded() + ? child.getMaxExpandHeight() + : child.getShowingLayout().getMinHeight(true /* likeGroupExpanded */); + maxContentHeight += childHeight; + visibleChildren++; + } + if (visibleChildren > 0) { + maxContentHeight += visibleChildren * mDividerHeight; + } + return maxContentHeight; + } + + public void setActualHeight(int actualHeight) { + if (!mUserLocked) { + return; + } + mActualHeight = actualHeight; + float fraction = getChildExpandFraction(); + int childCount = mChildren.size(); + for (int i = 0; i < childCount; i++) { + ExpandableNotificationRow child = mChildren.get(i); + float childHeight = child.isExpanded() + ? child.getMaxExpandHeight() + : child.getShowingLayout().getMinHeight(true /* likeGroupExpanded */); + float singleLineHeight = child.getShowingLayout().getMinHeight( + false /* likeGroupExpanded */); + child.setActualHeight((int) NotificationUtils.interpolate(singleLineHeight, childHeight, + fraction), false); + } + } + + public float getChildExpandFraction() { + int allChildrenVisibleHeight = getChildrenExpandStartHeight(); + int maxContentHeight = getMaxContentHeight(); + float factor = (mActualHeight - allChildrenVisibleHeight) + / (float) (maxContentHeight - allChildrenVisibleHeight); + return Math.max(0.0f, Math.min(1.0f, factor)); + } + + private int getChildrenExpandStartHeight() { + int intrinsicHeight = mNotificationHeaderHeight; + int visibleChildren = 0; + int childCount = mChildren.size(); + for (int i = 0; i < childCount; i++) { + if (visibleChildren >= NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED) { + break; + } + ExpandableNotificationRow child = mChildren.get(i); + intrinsicHeight += child.getMinHeight(); + visibleChildren++; + } + if (visibleChildren > 0) { + intrinsicHeight += (visibleChildren - 1) * mChildPadding; + } + intrinsicHeight += mCollapsedBottompadding; + return intrinsicHeight; } public int getMinHeight() { @@ -477,4 +587,13 @@ public class NotificationChildrenContainer extends ViewGroup { mDividers.set(i, divider); } } + + public void setUserLocked(boolean userLocked) { + mUserLocked = userLocked; + int childCount = mChildren.size(); + for (int i = 0; i < childCount; i++) { + ExpandableNotificationRow child = mChildren.get(i); + child.setUserLocked(userLocked); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index fe06c3affa12..340ebb444a86 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -64,6 +64,7 @@ import com.android.systemui.statusbar.NotificationSettingsIconRow.SettingsIconRo import com.android.systemui.statusbar.StackScrollerDecorView; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.FakeShadowView; +import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.PhoneStatusBar; import com.android.systemui.statusbar.phone.ScrimController; @@ -538,7 +539,7 @@ public class NotificationStackScrollLayout extends ViewGroup ExpandableView child = (ExpandableView) getChildAt(i); if (mChildrenToAddAnimated.contains(child)) { int startingPosition = getPositionInLinearLayout(child); - int padding = child.needsIncreasedPadding() + int padding = child.getIncreasedPaddingAmount() == 1.0f ? mIncreasedPaddingBetweenElements : mPaddingBetweenElements; int childHeight = getIntrinsicHeight(child) + padding; @@ -1531,18 +1532,18 @@ public class NotificationStackScrollLayout extends ViewGroup private void updateContentHeight() { int height = 0; - boolean previousNeedsIncreasedPaddings = false; + float previousIncreasedAmount = 0.0f; for (int i = 0; i < getChildCount(); i++) { ExpandableView expandableView = (ExpandableView) getChildAt(i); if (expandableView.getVisibility() != View.GONE) { - boolean needsIncreasedPaddings = expandableView.needsIncreasedPadding(); + float increasedPaddingAmount = expandableView.getIncreasedPaddingAmount(); if (height != 0) { - int padding = needsIncreasedPaddings || previousNeedsIncreasedPaddings - ? mIncreasedPaddingBetweenElements - : mPaddingBetweenElements; - height += padding; + height += (int) NotificationUtils.interpolate( + mPaddingBetweenElements, + mIncreasedPaddingBetweenElements, + Math.max(previousIncreasedAmount, increasedPaddingAmount)); } - previousNeedsIncreasedPaddings = needsIncreasedPaddings; + previousIncreasedAmount = increasedPaddingAmount; height += expandableView.getIntrinsicHeight(); } } @@ -1813,8 +1814,12 @@ public class NotificationStackScrollLayout extends ViewGroup // it will be set once we reach the boundary mMaxOverScroll = 0.0f; } + int minScrollY = Math.max(0, scrollRange); + if (mExpandedInThisMotion) { + minScrollY = Math.min(minScrollY, mMaxScrollAfterExpand); + } mScroller.fling(mScrollX, mOwnScrollY, 1, velocityY, 0, 0, 0, - Math.max(0, scrollRange), 0, Integer.MAX_VALUE / 2); + minScrollY, 0, mExpandedInThisMotion && mOwnScrollY >= 0 ? 0 : Integer.MAX_VALUE / 2); postInvalidateOnAnimation(); } @@ -2097,9 +2102,10 @@ public class NotificationStackScrollLayout extends ViewGroup */ private void updateScrollStateForRemovedChild(ExpandableView removedChild) { int startingPosition = getPositionInLinearLayout(removedChild); - int padding = removedChild.needsIncreasedPadding() - ? mIncreasedPaddingBetweenElements : - mPaddingBetweenElements; + int padding = (int) NotificationUtils.interpolate( + mPaddingBetweenElements, + mIncreasedPaddingBetweenElements, + removedChild.getIncreasedPaddingAmount()); int childHeight = getIntrinsicHeight(removedChild) + padding; int endPosition = startingPosition + childHeight; if (endPosition <= mOwnScrollY) { @@ -2123,19 +2129,19 @@ public class NotificationStackScrollLayout extends ViewGroup private int getPositionInLinearLayout(View requestedChild) { int position = 0; - boolean previousNeedsIncreasedPaddings = false; + float previousIncreasedAmount = 0.0f; for (int i = 0; i < getChildCount(); i++) { ExpandableView child = (ExpandableView) getChildAt(i); boolean notGone = child.getVisibility() != View.GONE; if (notGone) { - boolean needsIncreasedPaddings = child.needsIncreasedPadding(); + float increasedPaddingAmount = child.getIncreasedPaddingAmount(); if (position != 0) { - int padding = needsIncreasedPaddings || previousNeedsIncreasedPaddings - ? mIncreasedPaddingBetweenElements : - mPaddingBetweenElements; - position += padding; + position += (int) NotificationUtils.interpolate( + mPaddingBetweenElements, + mIncreasedPaddingBetweenElements, + Math.max(previousIncreasedAmount, increasedPaddingAmount)); } - previousNeedsIncreasedPaddings = needsIncreasedPaddings; + previousIncreasedAmount = increasedPaddingAmount; } if (child == requestedChild) { return position; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java index d78d62680860..eea923f68b20 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java @@ -25,9 +25,10 @@ import com.android.systemui.R; import com.android.systemui.statusbar.ExpandableNotificationRow; import com.android.systemui.statusbar.ExpandableView; import com.android.systemui.statusbar.notification.FakeShadowView; +import com.android.systemui.statusbar.notification.NotificationUtils; import java.util.ArrayList; -import java.util.HashSet; +import java.util.HashMap; import java.util.List; /** @@ -297,18 +298,22 @@ public class StackScrollAlgorithm { int childCount = hostView.getChildCount(); state.visibleChildren.clear(); state.visibleChildren.ensureCapacity(childCount); - state.increasedPaddingSet.clear(); + state.increasedPaddingMap.clear(); int notGoneIndex = 0; ExpandableView lastView = null; for (int i = 0; i < childCount; i++) { ExpandableView v = (ExpandableView) hostView.getChildAt(i); if (v.getVisibility() != View.GONE) { notGoneIndex = updateNotGoneIndex(resultState, state, notGoneIndex, v); - boolean needsIncreasedPadding = v.needsIncreasedPadding(); - if (needsIncreasedPadding) { - state.increasedPaddingSet.add(v); + float increasedPadding = v.getIncreasedPaddingAmount(); + if (increasedPadding != 0.0f) { + state.increasedPaddingMap.put(v, increasedPadding); if (lastView != null) { - state.increasedPaddingSet.add(lastView); + Float prevValue = state.increasedPaddingMap.get(lastView); + float newValue = prevValue != null + ? Math.max(prevValue, increasedPadding) + : increasedPadding; + state.increasedPaddingMap.put(lastView, newValue); } } if (v instanceof ExpandableNotificationRow) { @@ -423,9 +428,12 @@ public class StackScrollAlgorithm { private int getPaddingAfterChild(StackScrollAlgorithmState algorithmState, ExpandableView child) { - return algorithmState.increasedPaddingSet.contains(child) - ? mIncreasedPaddingBetweenElements - : mPaddingBetweenElements; + Float paddingValue = algorithmState.increasedPaddingMap.get(child); + return paddingValue == null + ? mPaddingBetweenElements + : (int) NotificationUtils.interpolate(mPaddingBetweenElements, + mIncreasedPaddingBetweenElements, + paddingValue); } private void updateHeadsUpStates(StackScrollState resultState, @@ -765,9 +773,10 @@ public class StackScrollAlgorithm { public final ArrayList<ExpandableView> visibleChildren = new ArrayList<ExpandableView>(); /** - * The children from the host that need an increased padding after them. + * The children from the host that need an increased padding after them. A value of 0 means + * no increased padding, a value of 1 means full padding. */ - public final HashSet<ExpandableView> increasedPaddingSet = new HashSet<>(); + public final HashMap<ExpandableView, Float> increasedPaddingMap = new HashMap<>(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java index 110258c360dc..0ed6ef899d1f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java @@ -116,6 +116,11 @@ public class TvStatusBar extends BaseStatusBar { } @Override + protected boolean toggleSplitScreenMode() { + return false; + } + + @Override public void maybeEscalateHeadsUp() { } diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java index ec49256abb23..0925638ad8cc 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java @@ -424,9 +424,7 @@ public class PipManager { } Intent intent = new Intent(mContext, PipMenuActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - final ActivityOptions options = ActivityOptions.makeBasic(); - options.setLaunchStackId(PINNED_STACK_ID); - mContext.startActivity(intent, options.toBundle()); + mContext.startActivity(intent); } public void addListener(Listener listener) { diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java index 7e229d4b90f4..4171dbcc4372 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java @@ -33,31 +33,64 @@ public class PipMenuActivity extends Activity implements PipManager.Listener { private final PipManager mPipManager = PipManager.getInstance(); private MediaController mMediaController; + private View mFullButtonView; + private View mFullDescriptionView; + private View mPlayPauseButtonView; + private View mPlayPauseDescriptionView; + private View mCloseButtonView; + private View mCloseDescriptionView; + @Override protected void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView(R.layout.tv_pip_menu); mPipManager.addListener(this); - findViewById(R.id.full).setOnClickListener(new View.OnClickListener() { + mFullButtonView = findViewById(R.id.full); + mFullDescriptionView = findViewById(R.id.full_desc); + mFullButtonView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mPipManager.movePipToFullscreen(); + finish(); + } + }); + mFullButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) { + mFullDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE); } }); - findViewById(R.id.exit).setOnClickListener(new View.OnClickListener() { + + mPlayPauseButtonView = findViewById(R.id.play_pause); + mPlayPauseDescriptionView = findViewById(R.id.play_pause_desc); + mPlayPauseButtonView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - mPipManager.closePip(); - finish(); + // TODO: Implement play/pause. } }); - findViewById(R.id.cancel).setOnClickListener(new View.OnClickListener() { + mPlayPauseButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) { + mPlayPauseDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE); + } + }); + + mCloseButtonView = findViewById(R.id.close); + mCloseDescriptionView = findViewById(R.id.close_desc); + mCloseButtonView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - mPipManager.resizePinnedStack(PipManager.STATE_PIP_OVERLAY); + mPipManager.closePip(); finish(); } }); + mCloseButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) { + mCloseDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE); + } + }); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java index 6f71c92f89db..e5c07d2367c5 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java +++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java @@ -17,9 +17,11 @@ package com.android.systemui.tv.pip; import android.app.Activity; +import android.graphics.Rect; import android.os.Bundle; import android.util.Log; import android.view.View; +import android.view.ViewGroup.LayoutParams; import com.android.systemui.R; @@ -33,6 +35,8 @@ public class PipOnboardingActivity extends Activity implements PipManager.Listen protected void onCreate(Bundle bundle) { super.onCreate(bundle); setContentView(R.layout.tv_pip_onboarding); + View pipOnboardingView = findViewById(R.id.pip_onboarding); + View pipOutlineView = findViewById(R.id.pip_outline); mPipManager.addListener(this); findViewById(R.id.close).setOnClickListener(new View.OnClickListener() { @Override @@ -40,6 +44,20 @@ public class PipOnboardingActivity extends Activity implements PipManager.Listen finish(); } }); + + int pipOutlineSpace = getResources().getDimensionPixelSize(R.dimen.tv_pip_bounds_space); + int screenWidth = getResources().getDisplayMetrics().widthPixels; + Rect pipBounds = mPipManager.getPipBounds(); + pipOnboardingView.setPadding( + pipBounds.left - pipOutlineSpace, + pipBounds.top - pipOutlineSpace, + screenWidth - pipBounds.right - pipOutlineSpace, 0); + + // Set width and height for outline view to enclose the PIP. + LayoutParams lp = pipOutlineView.getLayoutParams(); + lp.width = pipBounds.width() + pipOutlineSpace * 2; + lp.height = pipBounds.height() + pipOutlineSpace * 2; + pipOutlineView.setLayoutParams(lp); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java index 6f246918fde0..cfeab6d24a95 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java +++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java @@ -19,8 +19,8 @@ package com.android.systemui.tv.pip; import android.app.Activity; import android.os.Bundle; import android.os.Handler; - import android.view.View; + import com.android.systemui.R; /** diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk index 964688b509c8..c9c58050f367 100644 --- a/packages/SystemUI/tests/Android.mk +++ b/packages/SystemUI/tests/Android.mk @@ -29,9 +29,7 @@ LOCAL_AAPT_FLAGS := --auto-add-overlay \ LOCAL_SRC_FILES := $(call all-java-files-under, src) \ $(call all-Iaidl-files-under, src) \ - $(call all-java-files-under, ../src) \ - $(call all-proto-files-under, ../src) \ - src/com/android/systemui/EventLogTags.logtags + $(call all-java-files-under, ../src) LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \ frameworks/support/v7/preference/res \ @@ -53,7 +51,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ android-support-v7-preference \ android-support-v7-appcompat \ android-support-v14-preference \ - android-support-v17-leanback + android-support-v17-leanback \ + SystemUI-proto-tags # sign this with platform cert, so this test is allowed to inject key events into # UI it doesn't own. This is necessary to allow screenshots to be taken diff --git a/packages/SystemUI/tests/src/com/android/systemui/EventLogTags.logtags b/packages/SystemUI/tests/src/com/android/systemui/EventLogTags.logtags deleted file mode 120000 index 2f243d70449d..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/EventLogTags.logtags +++ /dev/null @@ -1 +0,0 @@ -../../../../../src/com/android/systemui/EventLogTags.logtags
\ No newline at end of file diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 49972d6541f8..568edab1764f 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -447,5 +447,8 @@ message MetricsEvent { // Logs the action the user takes when an app ANR'd. ACTION_APP_ANR = 317; + + // Logged when a user double taps the overview button to launch the previous task + OVERVIEW_LAUNCH_PREVIOUS_TASK = 318; } } diff --git a/services/accessibility/Android.mk b/services/accessibility/Android.mk index d98fc281dfb7..ce89aa7697ae 100644 --- a/services/accessibility/Android.mk +++ b/services/accessibility/Android.mk @@ -7,4 +7,6 @@ LOCAL_MODULE := services.accessibility LOCAL_SRC_FILES += \ $(call all-java-files-under,java) +LOCAL_JAVA_LIBRARIES := services.core + include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 0dbc5be51d75..2b682c5e3748 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -94,6 +94,7 @@ import com.android.internal.os.SomeArgs; import com.android.internal.statusbar.IStatusBarService; import com.android.server.LocalServices; +import com.android.server.statusbar.StatusBarManagerInternal; import org.xmlpull.v1.XmlPullParserException; import java.io.FileDescriptor; @@ -2778,6 +2779,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { case AccessibilityService.GLOBAL_ACTION_POWER_DIALOG: { showGlobalActions(); } return true; + case AccessibilityService.GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN: { + toggleSplitScreen(); + } return true; } return false; } finally { @@ -3249,6 +3253,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { mWindowManagerService.showGlobalActions(); } + private void toggleSplitScreen() { + LocalServices.getService(StatusBarManagerInternal.class).toggleSplitScreen(); + } + private IAccessibilityInteractionConnection getConnectionLocked(int windowId) { if (DEBUG) { Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId); @@ -3465,11 +3473,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT: case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG: case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR: - case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: - case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: { + case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: { return AccessibilityWindowInfo.TYPE_SYSTEM; } + case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: { + return AccessibilityWindowInfo.TYPE_SPLIT_SCREEN_DIVIDER; + } + case WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY: { return AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY; } diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index d14364d25ea6..caeb0c6380d5 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -660,12 +660,7 @@ public class AccountManagerService long identityToken = clearCallingIdentity(); try { UserAccounts accounts = getUserAccounts(userId); - synchronized (accounts.cacheLock) { - if (!accountExistsCacheLocked(accounts, account)) { - return null; - } - return readUserDataInternalLocked(accounts, account, key); - } + return readUserDataInternal(accounts, account, key); } finally { restoreCallingIdentity(identityToken); } @@ -1717,58 +1712,44 @@ public class AccountManagerService long identityToken = clearCallingIdentity(); try { UserAccounts accounts = getUserAccounts(userId); - synchronized (accounts.cacheLock) { - if (!accountExistsCacheLocked(accounts, account)) { - return; - } - setUserdataInternalLocked(accounts, account, key, value); - } + setUserdataInternal(accounts, account, key, value); } finally { restoreCallingIdentity(identityToken); } } - private boolean accountExistsCacheLocked(UserAccounts accounts, Account account) { - if (accounts.accountCache.containsKey(account.type)) { - for (Account acc : accounts.accountCache.get(account.type)) { - if (acc.name.equals(account.name)) { - return true; - } - } - } - return false; - } - - private void setUserdataInternalLocked(UserAccounts accounts, Account account, String key, + private void setUserdataInternal(UserAccounts accounts, Account account, String key, String value) { if (account == null || key == null) { return; } - final SQLiteDatabase db = accounts.openHelper.getWritableDatabase(); - db.beginTransaction(); - try { - long accountId = getAccountIdLocked(db, account); - if (accountId < 0) { - return; - } - long extrasId = getExtrasIdLocked(db, accountId, key); - if (extrasId < 0) { - extrasId = insertExtraLocked(db, accountId, key, value); - if (extrasId < 0) { - return; - } - } else { - ContentValues values = new ContentValues(); - values.put(EXTRAS_VALUE, value); - if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) { + synchronized (accounts.cacheLock) { + final SQLiteDatabase db = accounts.openHelper.getWritableDatabase(); + db.beginTransaction(); + try { + long accountId = getAccountIdLocked(db, account); + if (accountId < 0) { return; } + long extrasId = getExtrasIdLocked(db, accountId, key); + if (extrasId < 0 ) { + extrasId = insertExtraLocked(db, accountId, key, value); + if (extrasId < 0) { + return; + } + } else { + ContentValues values = new ContentValues(); + values.put(EXTRAS_VALUE, value); + if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) { + return; + } + } + writeUserDataIntoCacheLocked(accounts, db, account, key, value); + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); } - writeUserDataIntoCacheLocked(accounts, db, account, key, value); - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); } } @@ -4803,16 +4784,17 @@ public class AccountManagerService } } - protected String readUserDataInternalLocked( - UserAccounts accounts, Account account, String key) { - HashMap<String, String> userDataForAccount = accounts.userDataCache.get(account); - if (userDataForAccount == null) { - // need to populate the cache for this account - final SQLiteDatabase db = accounts.openHelper.getReadableDatabase(); - userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account); - accounts.userDataCache.put(account, userDataForAccount); + protected String readUserDataInternal(UserAccounts accounts, Account account, String key) { + synchronized (accounts.cacheLock) { + HashMap<String, String> userDataForAccount = accounts.userDataCache.get(account); + if (userDataForAccount == null) { + // need to populate the cache for this account + final SQLiteDatabase db = accounts.openHelper.getReadableDatabase(); + userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account); + accounts.userDataCache.put(account, userDataForAccount); + } + return userDataForAccount.get(key); } - return userDataForAccount.get(key); } protected HashMap<String, String> readUserDataForAccountFromDatabaseLocked( diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java index cbbcdae91488..6bda4edf273b 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java @@ -33,4 +33,5 @@ public interface StatusBarManagerInternal { void topAppWindowChanged(boolean menuVisible); void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask, Rect fullscreenBounds, Rect dockedBounds, String cause); + void toggleSplitScreen(); } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 6eab8d4e1f19..d24e1af3f382 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -204,6 +204,16 @@ public class StatusBarManagerService extends IStatusBarService.Stub { StatusBarManagerService.this.setSystemUiVisibility(vis, fullscreenStackVis, dockedStackVis, mask, fullscreenBounds, dockedBounds, cause); } + + @Override + public void toggleSplitScreen() { + enforceStatusBarService(); + if (mBar != null) { + try { + mBar.toggleSplitScreen(); + } catch (RemoteException ex) {} + } + } }; // ================================================================================ diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index e39445af78d3..c97323c60e70 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -29,10 +29,11 @@ #include "android_runtime/Log.h" #include <arpa/inet.h> -#include <string.h> -#include <pthread.h> +#include <limits> #include <linux/in.h> #include <linux/in6.h> +#include <pthread.h> +#include <string.h> static jobject mCallbacksObj = NULL; @@ -1090,11 +1091,37 @@ const char *const JavaMethodHelper<bool>::signature_ = "(Z)V"; if (flags & (flag)) object.callSetter("set" # setter, (value)) static jobject translate_gps_clock(JNIEnv* env, GpsClock* clock) { + static uint32_t discontinuity_count_to_handle_old_lock_type = 0; JavaObject object(env, "android/location/GnssClock"); GpsClockFlags flags = clock->flags; SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND, LeapSecond, clock->leap_second); - SET(Type, clock->type); + + // GnssClock only supports the more effective HW_CLOCK type, so type + // handling and documentation complexity has been removed. To convert the + // old GPS_CLOCK types (active only in a limited number of older devices), + // the GPS time information is handled as an always discontinuous HW clock, + // with the GPS time information put into the full_bias_ns instead - so that + // time_ns + full_bias_ns = local estimate of GPS time (as remains true, in + // the new GnssClock struct.) + switch (clock->type) { + case GPS_CLOCK_TYPE_UNKNOWN: + // Clock type unsupported. + ALOGE("Unknown clock type provided."); + break; + case GPS_CLOCK_TYPE_LOCAL_HW_TIME: + // Already local hardware time. No need to do anything. + break; + case GPS_CLOCK_TYPE_GPS_TIME: + // GPS time, need to convert. + flags |= GNSS_CLOCK_HAS_FULL_BIAS; + clock->full_bias_ns = clock->time_ns; + clock->time_ns = 0; + SET(HardwareClockDiscontinuityCount, + discontinuity_count_to_handle_old_lock_type++); + break; + } + SET(TimeInNs, clock->time_ns); SET_IF(GNSS_CLOCK_HAS_TIME_UNCERTAINTY, TimeUncertaintyInNs, diff --git a/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl b/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl index 69259d078baf..04cb1f278792 100644 --- a/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl +++ b/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl @@ -18,6 +18,8 @@ package com.android.ims.internal; import com.android.ims.ImsReasonInfo; +import android.net.Uri; + /** * A listener type for receiving notifications about the changes to * the IMS connection(registration). @@ -100,4 +102,9 @@ interface IImsRegistrationListener { * @param count The number of waiting voice messages. */ void voiceMessageCountUpdate(int count); + + /** + * Notifies the application when the list of URIs associated with IMS client is updated. + */ + void registrationAssociatedUriChanged(in Uri[] uris); } diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java index 8b8d604b4fc9..4bed94148599 100644 --- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java +++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java @@ -60,6 +60,8 @@ public class AppLaunch extends InstrumentationTestCase { // optional parameter: comma separated list of required account types before proceeding // with the app launch private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts"; + private static final String WEARABLE_ACTION_GOOGLE = + "com.google.android.wearable.action.GOOGLE"; private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 7500; //7.5s to allow app to idle private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; //750ms idle for non initial launches private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 2000; //2s between launching apps @@ -183,6 +185,13 @@ public class AppLaunch extends InstrumentationTestCase { Intent intentToResolve = new Intent(Intent.ACTION_MAIN); intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER); List<ResolveInfo> ris = pm.queryIntentActivities(intentToResolve, 0); + resolveLoop(ris, intentToResolve, pm); + intentToResolve = new Intent(WEARABLE_ACTION_GOOGLE); + ris = pm.queryIntentActivities(intentToResolve, 0); + resolveLoop(ris, intentToResolve, pm); + } + + private void resolveLoop(List<ResolveInfo> ris, Intent intentToResolve, PackageManager pm) { if (ris == null || ris.isEmpty()) { Log.i(TAG, "Could not find any apps"); } else { diff --git a/tests/UiBench/res/layout/activity_transition.xml b/tests/UiBench/res/layout/activity_transition.xml index d4c661027a35..4556b0263b6e 100644 --- a/tests/UiBench/res/layout/activity_transition.xml +++ b/tests/UiBench/res/layout/activity_transition.xml @@ -15,6 +15,7 @@ ~ limitations under the License --> <GridLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/transition_grid_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:clipChildren="true" @@ -25,8 +26,6 @@ android:layout_height="wrap_content" android:layout_width="wrap_content" android:scaleType="centerCrop" - android:layout_column="0" - android:layout_row="0" android:src="@drawable/ducky" android:onClick="clicked" android:transitionName="ducky"/> @@ -36,8 +35,6 @@ android:layout_width="wrap_content" android:scaleType="centerCrop" android:src="@drawable/woot" - android:layout_column="1" - android:layout_row="0" android:onClick="clicked" android:transitionName="woot"/> <ImageView @@ -46,8 +43,6 @@ android:layout_width="wrap_content" android:scaleType="centerCrop" android:src="@drawable/ball" - android:layout_column="0" - android:layout_row="1" android:onClick="clicked" android:transitionName="ball"/> <ImageView @@ -56,8 +51,6 @@ android:layout_width="wrap_content" android:scaleType="centerCrop" android:src="@drawable/block" - android:layout_column="1" - android:layout_row="1" android:onClick="clicked" android:transitionName="block"/> <ImageView @@ -66,8 +59,6 @@ android:layout_width="wrap_content" android:scaleType="centerCrop" android:src="@drawable/jellies" - android:layout_column="0" - android:layout_row="2" android:onClick="clicked" android:transitionName="jellies"/> <ImageView @@ -76,8 +67,6 @@ android:layout_width="wrap_content" android:scaleType="centerCrop" android:src="@drawable/mug" - android:layout_column="1" - android:layout_row="2" android:onClick="clicked" android:transitionName="mug"/> <ImageView @@ -86,8 +75,6 @@ android:layout_width="wrap_content" android:scaleType="centerCrop" android:src="@drawable/pencil" - android:layout_column="0" - android:layout_row="3" android:onClick="clicked" android:transitionName="pencil"/> <ImageView @@ -96,8 +83,6 @@ android:layout_width="wrap_content" android:scaleType="centerCrop" android:src="@drawable/scissors" - android:layout_column="1" - android:layout_row="3" android:onClick="clicked" android:transitionName="scissors"/> </GridLayout>
\ No newline at end of file diff --git a/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java b/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java index 1106a13bfc2a..0a069c269697 100644 --- a/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java +++ b/tests/UiBench/src/com/android/test/uibench/ActivityTransition.java @@ -18,11 +18,13 @@ package com.android.test.uibench; import android.app.ActivityOptions; import android.app.SharedElementCallback; import android.content.Intent; +import android.content.res.Configuration; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; +import android.widget.GridLayout; import android.widget.ImageView; import java.util.List; @@ -90,6 +92,13 @@ public class ActivityTransition extends AppCompatActivity { getWindow().setBackgroundDrawable(new ColorDrawable(Color.BLACK)); setContentView(R.layout.activity_transition); setupHero(); + + // Ensure that all images are visible regardless of orientation. + GridLayout gridLayout = (GridLayout) findViewById(R.id.transition_grid_layout); + boolean isPortrait = + getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; + gridLayout.setRowCount(isPortrait ? 4 : 2); + gridLayout.setColumnCount(isPortrait ? 2 : 4); } private void setupHero() { diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java index ed12bdf7b56d..a46aaec984ac 100644 --- a/wifi/java/android/net/wifi/ScanResult.java +++ b/wifi/java/android/net/wifi/ScanResult.java @@ -160,21 +160,6 @@ public class ScanResult implements Parcelable { } } - /** @hide */ - public static final int ENABLED = 0; - /** @hide */ - public static final int AUTO_ROAM_DISABLED = 16; - /** @hide */ - public static final int AUTO_JOIN_DISABLED = 32; - /** @hide */ - public static final int AUTHENTICATION_ERROR = 128; - - /** - * Status: indicating join status - * @hide - */ - public int autoJoinStatus; - /** * num IP configuration failures * @hide @@ -187,17 +172,6 @@ public class ScanResult implements Parcelable { */ public long blackListTimestamp; - /** @hide **/ - public void setAutoJoinStatus(int status) { - if (status < 0) status = 0; - if (status == 0) { - blackListTimestamp = 0; - } else if (status > autoJoinStatus) { - blackListTimestamp = System.currentTimeMillis(); - } - autoJoinStatus = status; - } - /** * Status: indicating the scan result is not a result * that is part of user's saved configurations @@ -462,7 +436,6 @@ public class ScanResult implements Parcelable { distanceCm = source.distanceCm; distanceSdCm = source.distanceSdCm; seen = source.seen; - autoJoinStatus = source.autoJoinStatus; untrusted = source.untrusted; numConnection = source.numConnection; numUsage = source.numUsage; @@ -506,9 +479,6 @@ public class ScanResult implements Parcelable { sb.append(", passpoint: "); sb.append(((flags & FLAG_PASSPOINT_NETWORK) != 0) ? "yes" : "no"); - if (autoJoinStatus != 0) { - sb.append(", status: ").append(autoJoinStatus); - } sb.append(", ChannelBandwidth: ").append(channelWidth); sb.append(", centerFreq0: ").append(centerFreq0); sb.append(", centerFreq1: ").append(centerFreq1); @@ -544,7 +514,6 @@ public class ScanResult implements Parcelable { dest.writeInt(centerFreq0); dest.writeInt(centerFreq1); dest.writeLong(seen); - dest.writeInt(autoJoinStatus); dest.writeInt(untrusted ? 1 : 0); dest.writeInt(numConnection); dest.writeInt(numUsage); @@ -615,7 +584,6 @@ public class ScanResult implements Parcelable { ); sr.seen = in.readLong(); - sr.autoJoinStatus = in.readInt(); sr.untrusted = in.readInt() != 0; sr.numConnection = in.readInt(); sr.numUsage = in.readInt(); |