diff options
170 files changed, 1788 insertions, 2217 deletions
diff --git a/api/current.txt b/api/current.txt index cca8293486e3..620864060898 100644 --- a/api/current.txt +++ b/api/current.txt @@ -4795,7 +4795,7 @@ package android.app { method public android.graphics.drawable.Icon getLargeIcon(); method public android.graphics.drawable.Icon getSmallIcon(); method public java.lang.String getSortKey(); - method public android.app.Notification.Topic[] getTopics(); + method public android.app.Notification.Topic getTopic(); method public void writeToParcel(android.os.Parcel, int); field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT; field public static final java.lang.String CATEGORY_ALARM = "alarm"; @@ -4960,7 +4960,6 @@ package android.app { method public android.app.Notification.Builder addAction(android.app.Notification.Action); method public android.app.Notification.Builder addExtras(android.os.Bundle); method public android.app.Notification.Builder addPerson(java.lang.String); - method public android.app.Notification.Builder addTopic(android.app.Notification.Topic); method public android.app.Notification build(); method public android.app.Notification.Builder extend(android.app.Notification.Extender); method public android.os.Bundle getExtras(); @@ -5009,6 +5008,7 @@ package android.app { method public android.app.Notification.Builder setSubText(java.lang.CharSequence); method public android.app.Notification.Builder setTicker(java.lang.CharSequence); method public deprecated android.app.Notification.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews); + method public android.app.Notification.Builder setTopic(android.app.Notification.Topic); method public android.app.Notification.Builder setUsesChronometer(boolean); method public android.app.Notification.Builder setVibrate(long[]); method public android.app.Notification.Builder setVisibility(int); @@ -5166,10 +5166,12 @@ package android.app { } public static class NotificationManager.Policy implements android.os.Parcelable { - ctor public NotificationManager.Policy(int, int, int); + ctor public deprecated NotificationManager.Policy(int, int, int); + ctor public NotificationManager.Policy(int, int, int, int); method public int describeContents(); method public static java.lang.String priorityCategoriesToString(int); method public static java.lang.String prioritySendersToString(int); + method public static java.lang.String suppressedEffectsToString(int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.NotificationManager.Policy> CREATOR; field public static final int PRIORITY_CATEGORY_CALLS = 8; // 0x8 @@ -5180,9 +5182,13 @@ package android.app { field public static final int PRIORITY_SENDERS_ANY = 0; // 0x0 field public static final int PRIORITY_SENDERS_CONTACTS = 1; // 0x1 field public static final int PRIORITY_SENDERS_STARRED = 2; // 0x2 + field public static final int SUPPRESSED_EFFECTS_UNSET = -1; // 0xffffffff + field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1 + field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2 field public final int priorityCallSenders; field public final int priorityCategories; field public final int priorityMessageSenders; + field public final int suppressedVisualEffects; } public final class PendingIntent implements android.os.Parcelable { @@ -28994,12 +29000,15 @@ package android.service.notification { field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2 field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0 field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService"; + field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1 + field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2 } public static class NotificationListenerService.Ranking { ctor public NotificationListenerService.Ranking(); method public java.lang.String getKey(); method public int getRank(); + method public int getSuppressedVisualEffects(); method public boolean isAmbient(); method public boolean matchesInterruptionFilter(); } diff --git a/api/system-current.txt b/api/system-current.txt index 3946d4abeae3..fc11f34314b5 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4913,7 +4913,7 @@ package android.app { method public android.graphics.drawable.Icon getLargeIcon(); method public android.graphics.drawable.Icon getSmallIcon(); method public java.lang.String getSortKey(); - method public android.app.Notification.Topic[] getTopics(); + method public android.app.Notification.Topic getTopic(); method public void writeToParcel(android.os.Parcel, int); field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT; field public static final java.lang.String CATEGORY_ALARM = "alarm"; @@ -5078,7 +5078,6 @@ package android.app { method public android.app.Notification.Builder addAction(android.app.Notification.Action); method public android.app.Notification.Builder addExtras(android.os.Bundle); method public android.app.Notification.Builder addPerson(java.lang.String); - method public android.app.Notification.Builder addTopic(android.app.Notification.Topic); method public android.app.Notification build(); method public android.app.Notification.Builder extend(android.app.Notification.Extender); method public android.os.Bundle getExtras(); @@ -5127,6 +5126,7 @@ package android.app { method public android.app.Notification.Builder setSubText(java.lang.CharSequence); method public android.app.Notification.Builder setTicker(java.lang.CharSequence); method public deprecated android.app.Notification.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews); + method public android.app.Notification.Builder setTopic(android.app.Notification.Topic); method public android.app.Notification.Builder setUsesChronometer(boolean); method public android.app.Notification.Builder setVibrate(long[]); method public android.app.Notification.Builder setVisibility(int); @@ -5284,10 +5284,12 @@ package android.app { } public static class NotificationManager.Policy implements android.os.Parcelable { - ctor public NotificationManager.Policy(int, int, int); + ctor public deprecated NotificationManager.Policy(int, int, int); + ctor public NotificationManager.Policy(int, int, int, int); method public int describeContents(); method public static java.lang.String priorityCategoriesToString(int); method public static java.lang.String prioritySendersToString(int); + method public static java.lang.String suppressedEffectsToString(int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.app.NotificationManager.Policy> CREATOR; field public static final int PRIORITY_CATEGORY_CALLS = 8; // 0x8 @@ -5298,9 +5300,13 @@ package android.app { field public static final int PRIORITY_SENDERS_ANY = 0; // 0x0 field public static final int PRIORITY_SENDERS_CONTACTS = 1; // 0x1 field public static final int PRIORITY_SENDERS_STARRED = 2; // 0x2 + field public static final int SUPPRESSED_EFFECTS_UNSET = -1; // 0xffffffff + field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1 + field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2 field public final int priorityCallSenders; field public final int priorityCategories; field public final int priorityMessageSenders; + field public final int suppressedVisualEffects; } public final class PendingIntent implements android.os.Parcelable { @@ -31113,6 +31119,8 @@ package android.service.notification { field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2 field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0 field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService"; + field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1 + field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2 field public static final int TRIM_FULL = 0; // 0x0 field public static final int TRIM_LIGHT = 1; // 0x1 } @@ -31121,6 +31129,7 @@ package android.service.notification { ctor public NotificationListenerService.Ranking(); method public java.lang.String getKey(); method public int getRank(); + method public int getSuppressedVisualEffects(); method public boolean isAmbient(); method public boolean matchesInterruptionFilter(); } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 0b77be3eda20..b5b77e65f442 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1466,10 +1466,10 @@ public class Notification implements Parcelable }; } - private Topic[] topics; + private Topic topic; - public Topic[] getTopics() { - return topics; + public Topic getTopic() { + return topic; } /** @@ -1599,7 +1599,9 @@ public class Notification implements Parcelable color = parcel.readInt(); - topics = parcel.createTypedArray(Topic.CREATOR); // may be null + if (parcel.readInt() != 0) { + topic = Topic.CREATOR.createFromParcel(parcel); + } } @Override @@ -1700,11 +1702,8 @@ public class Notification implements Parcelable that.color = this.color; - if (this.topics != null) { - that.topics = new Topic[this.topics.length]; - for(int i=0; i<this.topics.length; i++) { - that.topics[i] = this.topics[i].clone(); - } + if (this.topic != null) { + that.topic = this.topic.clone(); } if (!heavy) { @@ -1878,7 +1877,12 @@ public class Notification implements Parcelable parcel.writeInt(color); - parcel.writeTypedArray(topics, 0); // null ok + if (topic != null) { + parcel.writeInt(1); + topic.writeToParcel(parcel, 0); + } else { + parcel.writeInt(0); + } } /** @@ -2008,17 +2012,9 @@ public class Notification implements Parcelable sb.append(" publicVersion="); sb.append(publicVersion.toString()); } - if (topics != null) { - sb.append("topics=["); - int N = topics.length; - if (N > 0) { - for (int i = 0; i < N-1; i++) { - sb.append(topics[i]); - sb.append(','); - } - sb.append(topics[N-1]); - } - sb.append("]"); + if (topic != null) { + sb.append("topic="); + sb.append(topic.toString()); } sb.append(")"); return sb.toString(); @@ -2136,7 +2132,6 @@ public class Notification implements Parcelable private ArrayList<String> mPersonList = new ArrayList<String>(); private NotificationColorUtil mColorUtil; private boolean mColorUtilInited = false; - private List<Topic> mTopics = new ArrayList<>(); /** * The user that built the notification originally. @@ -2187,10 +2182,6 @@ public class Notification implements Parcelable Collections.addAll(mPersonList, mN.extras.getStringArray(EXTRA_PEOPLE)); } - if (mN.getTopics() != null) { - Collections.addAll(mTopics, mN.getTopics()); - } - String templateClass = mN.extras.getString(EXTRA_TEMPLATE); if (!TextUtils.isEmpty(templateClass)) { final Class<? extends Style> styleClass @@ -2962,15 +2953,15 @@ public class Notification implements Parcelable } /** - * Add a topic to this notification. Topics are typically displayed in Notification + * Sets the topic of this notification. Topics are typically displayed in Notification * settings. * <p> * Every topic must have an id and a textual label. * * @param topic The topic to add. */ - public Builder addTopic(Topic topic) { - mTopics.add(topic); + public Builder setTopic(Topic topic) { + mN.topic = topic; return this; } @@ -3452,10 +3443,6 @@ public class Notification implements Parcelable mN.extras.putStringArray(EXTRA_PEOPLE, mPersonList.toArray(new String[mPersonList.size()])); } - if (mTopics.size() > 0) { - mN.topics = new Topic[mTopics.size()]; - mTopics.toArray(mN.topics); - } return mN; } diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 07b4d39d82f4..043c503b3ec0 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -610,15 +610,39 @@ public class NotificationManager * PRIORITY_SENDERS_ANY, PRIORITY_SENDERS_CONTACTS, PRIORITY_SENDERS_STARRED */ public final int priorityMessageSenders; + public static final int SUPPRESSED_EFFECTS_UNSET = -1; + public static final int SUPPRESSED_EFFECT_LIGHTS = 1 << 0; + public static final int SUPPRESSED_EFFECT_PEEK = 1 << 1; + + private static final int[] ALL_SUPPRESSED_EFFECTS = { + SUPPRESSED_EFFECT_LIGHTS, + SUPPRESSED_EFFECT_PEEK, + }; + + /** + * Visual effects to suppress for a notification that is filtered by Do Not Disturb mode. + * Bitmask of SUPPRESSED_EFFECT_* constants. + */ + public final int suppressedVisualEffects; + + + @Deprecated public Policy(int priorityCategories, int priorityCallSenders, int priorityMessageSenders) { + this(priorityCategories, priorityCallSenders, priorityMessageSenders, + SUPPRESSED_EFFECTS_UNSET); + } + + public Policy(int priorityCategories, int priorityCallSenders, int priorityMessageSenders, + int suppressedVisualEffects) { this.priorityCategories = priorityCategories; this.priorityCallSenders = priorityCallSenders; this.priorityMessageSenders = priorityMessageSenders; + this.suppressedVisualEffects = suppressedVisualEffects; } /** @hide */ public Policy(Parcel source) { - this(source.readInt(), source.readInt(), source.readInt()); + this(source.readInt(), source.readInt(), source.readInt(), source.readInt()); } @Override @@ -626,6 +650,7 @@ public class NotificationManager dest.writeInt(priorityCategories); dest.writeInt(priorityCallSenders); dest.writeInt(priorityMessageSenders); + dest.writeInt(suppressedVisualEffects); } @Override @@ -635,7 +660,8 @@ public class NotificationManager @Override public int hashCode() { - return Objects.hash(priorityCategories, priorityCallSenders, priorityMessageSenders); + return Objects.hash(priorityCategories, priorityCallSenders, priorityMessageSenders, + suppressedVisualEffects); } @Override @@ -645,7 +671,8 @@ public class NotificationManager final Policy other = (Policy) o; return other.priorityCategories == priorityCategories && other.priorityCallSenders == priorityCallSenders - && other.priorityMessageSenders == priorityMessageSenders; + && other.priorityMessageSenders == priorityMessageSenders + && other.suppressedVisualEffects == suppressedVisualEffects; } @Override @@ -654,9 +681,29 @@ public class NotificationManager + "priorityCategories=" + priorityCategoriesToString(priorityCategories) + ",priorityCallSenders=" + prioritySendersToString(priorityCallSenders) + ",priorityMessageSenders=" + prioritySendersToString(priorityMessageSenders) + + ",suppressedVisualEffects=" + + suppressedEffectsToString(suppressedVisualEffects) + "]"; } + public static String suppressedEffectsToString(int effects) { + if (effects <= 0) return ""; + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < ALL_SUPPRESSED_EFFECTS.length; i++) { + final int effect = ALL_SUPPRESSED_EFFECTS[i]; + if ((effects & effect) != 0) { + if (sb.length() > 0) sb.append(','); + sb.append(effectToString(effect)); + } + effects &= ~effect; + } + if (effects != 0) { + if (sb.length() > 0) sb.append(','); + sb.append("UNKNOWN_").append(effects); + } + return sb.toString(); + } + public static String priorityCategoriesToString(int priorityCategories) { if (priorityCategories == 0) return ""; final StringBuilder sb = new StringBuilder(); @@ -675,6 +722,15 @@ public class NotificationManager return sb.toString(); } + private static String effectToString(int effect) { + switch (effect) { + case SUPPRESSED_EFFECT_LIGHTS: return "SUPPRESSED_EFFECT_LIGHTS"; + case SUPPRESSED_EFFECT_PEEK: return "SUPPRESSED_EFFECT_PEEK"; + case SUPPRESSED_EFFECTS_UNSET: return "SUPPRESSED_EFFECTS_UNSET"; + default: return "UNKNOWN_" + effect; + } + } + private static String priorityCategoryToString(int priorityCategory) { switch (priorityCategory) { case PRIORITY_CATEGORY_REMINDERS: return "PRIORITY_CATEGORY_REMINDERS"; diff --git a/core/java/android/security/net/config/ApplicationConfig.java b/core/java/android/security/net/config/ApplicationConfig.java index b6276418c49d..48359d47f091 100644 --- a/core/java/android/security/net/config/ApplicationConfig.java +++ b/core/java/android/security/net/config/ApplicationConfig.java @@ -144,4 +144,18 @@ public final class ApplicationConfig { return sInstance; } } + + /** @hide */ + public static ApplicationConfig getPlatformDefault() { + return new ApplicationConfig(new ConfigSource() { + @Override + public NetworkSecurityConfig getDefaultConfig() { + return NetworkSecurityConfig.DEFAULT; + } + @Override + public Set<Pair<Domain, NetworkSecurityConfig>> getPerDomainConfigs() { + return null; + } + }); + } } diff --git a/core/java/android/security/net/config/NetworkSecurityConfig.java b/core/java/android/security/net/config/NetworkSecurityConfig.java index 8906f9b670d4..9eab80ca0771 100644 --- a/core/java/android/security/net/config/NetworkSecurityConfig.java +++ b/core/java/android/security/net/config/NetworkSecurityConfig.java @@ -16,11 +16,14 @@ package android.security.net.config; +import android.util.ArrayMap; import android.util.ArraySet; +import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Set; import javax.net.ssl.X509TrustManager; @@ -57,12 +60,24 @@ public final class NetworkSecurityConfig { if (mAnchors != null) { return mAnchors; } - Set<TrustAnchor> anchors = new ArraySet<TrustAnchor>(); + // Merge trust anchors based on the X509Certificate. + // If we see the same certificate in two TrustAnchors, one with overridesPins and one + // without, the one with overridesPins wins. + Map<X509Certificate, TrustAnchor> anchorMap = new ArrayMap<>(); for (CertificatesEntryRef ref : mCertificatesEntryRefs) { - anchors.addAll(ref.getTrustAnchors()); + Set<TrustAnchor> anchors = ref.getTrustAnchors(); + for (TrustAnchor anchor : anchors) { + if (anchor.overridesPins) { + anchorMap.put(anchor.certificate, anchor); + } else if (!anchorMap.containsKey(anchor.certificate)) { + anchorMap.put(anchor.certificate, anchor); + } + } } + ArraySet<TrustAnchor> anchors = new ArraySet<TrustAnchor>(anchorMap.size()); + anchors.addAll(anchorMap.values()); mAnchors = anchors; - return anchors; + return mAnchors; } } diff --git a/core/java/android/security/net/config/NetworkSecurityConfigProvider.java b/core/java/android/security/net/config/NetworkSecurityConfigProvider.java index ca8cdae47162..ac762efe85d2 100644 --- a/core/java/android/security/net/config/NetworkSecurityConfigProvider.java +++ b/core/java/android/security/net/config/NetworkSecurityConfigProvider.java @@ -16,13 +16,21 @@ package android.security.net.config; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.util.Log; +import java.security.Security; import java.security.Provider; /** @hide */ public final class NetworkSecurityConfigProvider extends Provider { - - private static String PREFIX = + private static final String LOG_TAG = "NetworkSecurityConfig"; + private static final String PREFIX = NetworkSecurityConfigProvider.class.getPackage().getName() + "."; + public static final String META_DATA_NETWORK_SECURITY_CONFIG = + "android.security.net.config"; + private static final boolean DBG = true; public NetworkSecurityConfigProvider() { // TODO: More clever name than this @@ -30,4 +38,43 @@ public final class NetworkSecurityConfigProvider extends Provider { put("TrustManagerFactory.PKIX", PREFIX + "RootTrustManagerFactorySpi"); put("Alg.Alias.TrustManagerFactory.X509", "PKIX"); } + + public static void install(Context context) { + ApplicationInfo info = null; + // TODO: This lookup shouldn't be done in the app startup path, it should be done lazily. + try { + info = context.getPackageManager().getApplicationInfo(context.getPackageName(), + PackageManager.GET_META_DATA); + } catch (PackageManager.NameNotFoundException e) { + throw new RuntimeException("Failed to look up ApplicationInfo", e); + } + int configResourceId = 0; + if (info != null && info.metaData != null) { + configResourceId = info.metaData.getInt(META_DATA_NETWORK_SECURITY_CONFIG); + } + + ApplicationConfig config; + if (configResourceId != 0) { + boolean debugBuild = (info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; + if (DBG) { + Log.d(LOG_TAG, "Using Network Security Config from resource " + + context.getResources().getResourceEntryName(configResourceId) + + " debugBuild: " + debugBuild); + } + ConfigSource source = new XmlConfigSource(context, configResourceId, debugBuild); + config = new ApplicationConfig(source); + } else { + if (DBG) { + Log.d(LOG_TAG, "No Network Security Config specified, using platform default"); + } + config = ApplicationConfig.getPlatformDefault(); + } + + ApplicationConfig.setDefaultInstance(config); + int pos = Security.insertProviderAt(new NetworkSecurityConfigProvider(), 1); + if (pos != 1) { + throw new RuntimeException("Failed to install provider as highest priority provider." + + " Provider was installed at position " + pos); + } + } } diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 7e7b5fcb9975..ee97e8eeba8a 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -108,6 +108,11 @@ public abstract class NotificationListenerService extends Service { * This does not change the interruption filter, only the effects. **/ public static final int HINT_HOST_DISABLE_EFFECTS = 1; + public static final int SUPPRESSED_EFFECT_LIGHTS = + NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; + public static final int SUPPRESSED_EFFECT_PEEK = + NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; + /** * The full trim of the StatusBarNotification including all its features. * @@ -822,6 +827,7 @@ public abstract class NotificationListenerService extends Service { private boolean mIsAmbient; private boolean mMatchesInterruptionFilter; private int mVisibilityOverride; + private int mSuppressedVisualEffects; public Ranking() {} @@ -861,6 +867,14 @@ public abstract class NotificationListenerService extends Service { return mVisibilityOverride; } + /** + * Returns the type(s) of visual effects that should be suppressed for this notification. + * See {@link #SUPPRESSED_EFFECT_LIGHTS}, {@link #SUPPRESSED_EFFECT_PEEK}}. + */ + public int getSuppressedVisualEffects() { + return mSuppressedVisualEffects; + } + /** * Returns whether the notification matches the user's interruption @@ -874,12 +888,14 @@ public abstract class NotificationListenerService extends Service { } private void populate(String key, int rank, boolean isAmbient, - boolean matchesInterruptionFilter, int visibilityOverride) { + boolean matchesInterruptionFilter, int visibilityOverride, + int suppressedVisualEffects) { mKey = key; mRank = rank; mIsAmbient = isAmbient; mMatchesInterruptionFilter = matchesInterruptionFilter; mVisibilityOverride = visibilityOverride; + mSuppressedVisualEffects = suppressedVisualEffects; } } @@ -896,6 +912,7 @@ public abstract class NotificationListenerService extends Service { private ArrayMap<String,Integer> mRanks; private ArraySet<Object> mIntercepted; private ArrayMap<String, Integer> mVisibilityOverrides; + private ArrayMap<String, Integer> mSuppressedVisualEffects; private RankingMap(NotificationRankingUpdate rankingUpdate) { mRankingUpdate = rankingUpdate; @@ -921,7 +938,7 @@ public abstract class NotificationListenerService extends Service { public boolean getRanking(String key, Ranking outRanking) { int rank = getRank(key); outRanking.populate(key, rank, isAmbient(key), !isIntercepted(key), - getVisibilityOverride(key)); + getVisibilityOverride(key), getSuppressedVisualEffects(key)); return rank >= 0; } @@ -959,11 +976,24 @@ public abstract class NotificationListenerService extends Service { buildVisibilityOverridesLocked(); } } - Integer overide = mVisibilityOverrides.get(key); - if (overide == null) { + Integer override = mVisibilityOverrides.get(key); + if (override == null) { return Ranking.VISIBILITY_NO_OVERRIDE; } - return overide.intValue(); + return override.intValue(); + } + + private int getSuppressedVisualEffects(String key) { + synchronized (this) { + if (mSuppressedVisualEffects == null) { + buildSuppressedVisualEffectsLocked(); + } + } + Integer suppressed = mSuppressedVisualEffects.get(key); + if (suppressed == null) { + return 0; + } + return suppressed.intValue(); } // Locked by 'this' @@ -992,6 +1022,15 @@ public abstract class NotificationListenerService extends Service { } } + // Locked by 'this' + private void buildSuppressedVisualEffectsLocked() { + Bundle suppressedBundle = mRankingUpdate.getSuppressedVisualEffects(); + mSuppressedVisualEffects = new ArrayMap<>(suppressedBundle.size()); + for (String key: suppressedBundle.keySet()) { + mSuppressedVisualEffects.put(key, suppressedBundle.getInt(key)); + } + } + // ----------- Parcelable @Override diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java index 6fba90085578..1282fb11b666 100644 --- a/core/java/android/service/notification/NotificationRankingUpdate.java +++ b/core/java/android/service/notification/NotificationRankingUpdate.java @@ -28,13 +28,15 @@ public class NotificationRankingUpdate implements Parcelable { private final String[] mInterceptedKeys; private final int mFirstAmbientIndex; private final Bundle mVisibilityOverrides; + private final Bundle mSuppressedVisualEffects; public NotificationRankingUpdate(String[] keys, String[] interceptedKeys, - Bundle visibilityOverrides, int firstAmbientIndex) { + Bundle visibilityOverrides, int firstAmbientIndex, Bundle suppressedVisualEffects) { mKeys = keys; mFirstAmbientIndex = firstAmbientIndex; mInterceptedKeys = interceptedKeys; mVisibilityOverrides = visibilityOverrides; + mSuppressedVisualEffects = suppressedVisualEffects; } public NotificationRankingUpdate(Parcel in) { @@ -42,6 +44,7 @@ public class NotificationRankingUpdate implements Parcelable { mFirstAmbientIndex = in.readInt(); mInterceptedKeys = in.readStringArray(); mVisibilityOverrides = in.readBundle(); + mSuppressedVisualEffects = in.readBundle(); } @Override @@ -55,6 +58,7 @@ public class NotificationRankingUpdate implements Parcelable { out.writeInt(mFirstAmbientIndex); out.writeStringArray(mInterceptedKeys); out.writeBundle(mVisibilityOverrides); + out.writeBundle(mSuppressedVisualEffects); } public static final Parcelable.Creator<NotificationRankingUpdate> CREATOR @@ -83,4 +87,8 @@ public class NotificationRankingUpdate implements Parcelable { public Bundle getVisibilityOverrides() { return mVisibilityOverrides; } + + public Bundle getSuppressedVisualEffects() { + return mSuppressedVisualEffects; + } } diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 82f1b28c39ae..b3399d063807 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -77,6 +77,8 @@ public class ZenModeConfig implements Parcelable { private static final boolean DEFAULT_ALLOW_REMINDERS = true; private static final boolean DEFAULT_ALLOW_EVENTS = true; private static final boolean DEFAULT_ALLOW_REPEAT_CALLERS = false; + private static final boolean DEFAULT_ALLOW_PEEK = true; + private static final boolean DEFAULT_ALLOW_LIGHTS = true; private static final int XML_VERSION = 2; private static final String ZEN_TAG = "zen"; @@ -91,6 +93,8 @@ public class ZenModeConfig implements Parcelable { private static final String ALLOW_ATT_MESSAGES_FROM = "messagesFrom"; private static final String ALLOW_ATT_REMINDERS = "reminders"; private static final String ALLOW_ATT_EVENTS = "events"; + private static final String ALLOW_ATT_PEEK = "peek"; + private static final String ALLOW_ATT_LIGHTS = "lights"; private static final String CONDITION_TAG = "condition"; private static final String CONDITION_ATT_COMPONENT = "component"; @@ -122,6 +126,8 @@ public class ZenModeConfig implements Parcelable { public int allowCallsFrom = DEFAULT_SOURCE; public int allowMessagesFrom = DEFAULT_SOURCE; public int user = UserHandle.USER_SYSTEM; + public boolean allowPeek = DEFAULT_ALLOW_PEEK; + public boolean allowLights = DEFAULT_ALLOW_LIGHTS; public ZenRule manualRule; public ArrayMap<String, ZenRule> automaticRules = new ArrayMap<>(); @@ -148,6 +154,8 @@ public class ZenModeConfig implements Parcelable { automaticRules.put(ids[i], rules[i]); } } + allowPeek = source.readInt() == 1; + allowLights = source.readInt() == 1; } @Override @@ -175,22 +183,26 @@ public class ZenModeConfig implements Parcelable { } else { dest.writeInt(0); } + dest.writeInt(allowPeek ? 1 : 0); + dest.writeInt(allowLights ? 1 : 0); } @Override public String toString() { return new StringBuilder(ZenModeConfig.class.getSimpleName()).append('[') - .append("user=").append(user) - .append(",allowCalls=").append(allowCalls) - .append(",allowRepeatCallers=").append(allowRepeatCallers) - .append(",allowMessages=").append(allowMessages) - .append(",allowCallsFrom=").append(sourceToString(allowCallsFrom)) - .append(",allowMessagesFrom=").append(sourceToString(allowMessagesFrom)) - .append(",allowReminders=").append(allowReminders) - .append(",allowEvents=").append(allowEvents) - .append(",automaticRules=").append(automaticRules) - .append(",manualRule=").append(manualRule) - .append(']').toString(); + .append("user=").append(user) + .append(",allowCalls=").append(allowCalls) + .append(",allowRepeatCallers=").append(allowRepeatCallers) + .append(",allowMessages=").append(allowMessages) + .append(",allowCallsFrom=").append(sourceToString(allowCallsFrom)) + .append(",allowMessagesFrom=").append(sourceToString(allowMessagesFrom)) + .append(",allowReminders=").append(allowReminders) + .append(",allowEvents=").append(allowEvents) + .append(",allowPeek=").append(allowPeek) + .append(",allowLights=").append(allowLights) + .append(",automaticRules=").append(automaticRules) + .append(",manualRule=").append(manualRule) + .append(']').toString(); } private Diff diff(ZenModeConfig to) { @@ -222,6 +234,12 @@ public class ZenModeConfig implements Parcelable { if (allowEvents != to.allowEvents) { d.addLine("allowEvents", allowEvents, to.allowEvents); } + if (allowPeek != to.allowPeek) { + d.addLine("allowPeek", allowPeek, to.allowPeek); + } + if (allowLights != to.allowLights) { + d.addLine("allowLights", allowLights, to.allowLights); + } final ArraySet<String> allRules = new ArraySet<>(); addKeys(allRules, automaticRules); addKeys(allRules, to.automaticRules); @@ -319,6 +337,8 @@ public class ZenModeConfig implements Parcelable { && other.allowMessagesFrom == allowMessagesFrom && other.allowReminders == allowReminders && other.allowEvents == allowEvents + && other.allowPeek == allowPeek + && other.allowLights == allowLights && other.user == user && Objects.equals(other.automaticRules, automaticRules) && Objects.equals(other.manualRule, manualRule); @@ -327,7 +347,8 @@ public class ZenModeConfig implements Parcelable { @Override public int hashCode() { return Objects.hash(allowCalls, allowRepeatCallers, allowMessages, allowCallsFrom, - allowMessagesFrom, allowReminders, allowEvents, user, automaticRules, manualRule); + allowMessagesFrom, allowReminders, allowEvents, allowPeek, allowLights, + user, automaticRules, manualRule); } private static String toDayList(int[] days) { @@ -412,6 +433,8 @@ public class ZenModeConfig implements Parcelable { rt.allowCallsFrom = DEFAULT_SOURCE; rt.allowMessagesFrom = DEFAULT_SOURCE; } + rt.allowPeek = safeBoolean(parser, ALLOW_ATT_PEEK, DEFAULT_ALLOW_PEEK); + rt.allowLights = safeBoolean(parser, ALLOW_ATT_LIGHTS, DEFAULT_ALLOW_LIGHTS); } else if (MANUAL_TAG.equals(tag)) { rt.manualRule = readRuleXml(parser); } else if (AUTOMATIC_TAG.equals(tag)) { @@ -440,6 +463,8 @@ public class ZenModeConfig implements Parcelable { out.attribute(null, ALLOW_ATT_EVENTS, Boolean.toString(allowEvents)); out.attribute(null, ALLOW_ATT_CALLS_FROM, Integer.toString(allowCallsFrom)); out.attribute(null, ALLOW_ATT_MESSAGES_FROM, Integer.toString(allowMessagesFrom)); + out.attribute(null, ALLOW_ATT_PEEK, Boolean.toString(allowPeek)); + out.attribute(null, ALLOW_ATT_LIGHTS, Boolean.toString(allowLights)); out.endTag(null, ALLOW_TAG); if (manualRule != null) { @@ -611,9 +636,17 @@ public class ZenModeConfig implements Parcelable { if (allowRepeatCallers) { priorityCategories |= Policy.PRIORITY_CATEGORY_REPEAT_CALLERS; } + int suppressedVisualEffects = 0; + if (!allowPeek) { + suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_PEEK; + } + if (!allowLights) { + suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS; + } priorityCallSenders = sourceToPrioritySenders(allowCallsFrom, priorityCallSenders); priorityMessageSenders = sourceToPrioritySenders(allowMessagesFrom, priorityMessageSenders); - return new Policy(priorityCategories, priorityCallSenders, priorityMessageSenders); + return new Policy(priorityCategories, priorityCallSenders, priorityMessageSenders, + suppressedVisualEffects); } private static int sourceToPrioritySenders(int source, int def) { @@ -645,6 +678,10 @@ public class ZenModeConfig implements Parcelable { allowCallsFrom = prioritySendersToSource(policy.priorityCallSenders, allowCallsFrom); allowMessagesFrom = prioritySendersToSource(policy.priorityMessageSenders, allowMessagesFrom); + if (policy.suppressedVisualEffects != Policy.SUPPRESSED_EFFECTS_UNSET) { + allowPeek = (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) == 0; + allowLights = (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) == 0; + } } public static Condition toTimeCondition(Context context, int minutesFromNow, int userHandle) { diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java index 88e9a952f778..b61706ef4424 100644 --- a/core/java/android/view/PointerIcon.java +++ b/core/java/android/view/PointerIcon.java @@ -24,6 +24,7 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.graphics.Bitmap; +import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Parcel; @@ -142,6 +143,10 @@ public final class PointerIcon implements Parcelable { private Bitmap mBitmap; private float mHotSpotX; private float mHotSpotY; + // The bitmaps for the additional frame of animated pointer icon. Note that the first frame + // will be stored in mBitmap. + private Bitmap mBitmapFrames[]; + private int mDurationPerFrame; private PointerIcon(int style) { mStyle = style; @@ -472,6 +477,36 @@ public final class PointerIcon implements Parcelable { } else { drawable = context.getDrawable(bitmapRes); } + if (drawable instanceof AnimationDrawable) { + // Extract animation frame bitmaps. + final AnimationDrawable animationDrawable = (AnimationDrawable) drawable; + final int frames = animationDrawable.getNumberOfFrames(); + drawable = animationDrawable.getFrame(0); + if (frames == 1) { + Log.w(TAG, "Animation icon with single frame -- simply treating the first " + + "frame as a normal bitmap icon."); + } else { + // Assumes they have the exact duration. + mDurationPerFrame = animationDrawable.getDuration(0); + mBitmapFrames = new Bitmap[frames - 1]; + final int width = drawable.getIntrinsicWidth(); + final int height = drawable.getIntrinsicHeight(); + for (int i = 1; i < frames; ++i) { + Drawable drawableFrame = animationDrawable.getFrame(i); + if (!(drawableFrame instanceof BitmapDrawable)) { + throw new IllegalArgumentException("Frame of an animated pointer icon " + + "must refer to a bitmap drawable."); + } + if (drawableFrame.getIntrinsicWidth() != width || + drawableFrame.getIntrinsicHeight() != height) { + throw new IllegalArgumentException("The bitmap size of " + i + "-th frame " + + "is different. All frames should have the exact same size and " + + "share the same hotspot."); + } + mBitmapFrames[i - 1] = ((BitmapDrawable)drawableFrame).getBitmap(); + } + } + } if (!(drawable instanceof BitmapDrawable)) { throw new IllegalArgumentException("<pointer-icon> bitmap attribute must " + "refer to a bitmap drawable."); @@ -509,8 +544,7 @@ public final class PointerIcon implements Parcelable { case STYLE_HELP: return com.android.internal.R.styleable.Pointer_pointerIconHelp; case STYLE_WAIT: - // falls back to the default icon because no animation support. - return com.android.internal.R.styleable.Pointer_pointerIconArrow; + return com.android.internal.R.styleable.Pointer_pointerIconWait; case STYLE_CELL: return com.android.internal.R.styleable.Pointer_pointerIconCell; case STYLE_CROSSHAIR: diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 461506bd6253..de4d43990ea0 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -6329,8 +6329,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, position.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); - outRect.set((int) (position.left + 0.5f), (int) (position.top + 0.5f), - (int) (position.right + 0.5f), (int) (position.bottom + 0.5f)); + outRect.set(Math.round(position.left), Math.round(position.top), + Math.round(position.right), Math.round(position.bottom)); } /** @@ -18548,8 +18548,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, position[1] -= vr.mCurScrollY; } - inOutLocation[0] = (int) (position[0] + 0.5f); - inOutLocation[1] = (int) (position[1] + 0.5f); + inOutLocation[0] = Math.round(position[0]); + inOutLocation[1] = Math.round(position[1]); } /** diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index db978a6748f7..25df00483acd 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -5114,10 +5114,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager transformMatrix = childMatrix; } transformMatrix.mapRect(boundingRect); - dirty.set((int) (boundingRect.left - 0.5f), - (int) (boundingRect.top - 0.5f), - (int) (boundingRect.right + 0.5f), - (int) (boundingRect.bottom + 0.5f)); + dirty.set((int) Math.floor(boundingRect.left), + (int) Math.floor(boundingRect.top), + (int) Math.ceil(boundingRect.right), + (int) Math.ceil(boundingRect.bottom)); } do { @@ -5154,10 +5154,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager RectF boundingRect = attachInfo.mTmpTransformRect; boundingRect.set(dirty); m.mapRect(boundingRect); - dirty.set((int) (boundingRect.left - 0.5f), - (int) (boundingRect.top - 0.5f), - (int) (boundingRect.right + 0.5f), - (int) (boundingRect.bottom + 0.5f)); + dirty.set((int) Math.floor(boundingRect.left), + (int) Math.floor(boundingRect.top), + (int) Math.ceil(boundingRect.right), + (int) Math.ceil(boundingRect.bottom)); } } } while (parent != null); @@ -5457,8 +5457,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager position[0] = offset.x; position[1] = offset.y; child.getMatrix().mapPoints(position); - offset.x = (int) (position[0] + 0.5f); - offset.y = (int) (position[1] + 0.5f); + offset.x = Math.round(position[0]); + offset.y = Math.round(position[1]); } offset.x += dx; offset.y += dy; @@ -5485,8 +5485,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager rectIsVisible = rect.intersect(mClipBounds.left, mClipBounds.top, mClipBounds.right, mClipBounds.bottom); } - r.set((int) (rect.left + 0.5f), (int) (rect.top + 0.5f), (int) (rect.right + 0.5f), - (int) (rect.bottom + 0.5f)); + r.set((int) Math.floor(rect.left), (int) Math.floor(rect.top), + (int) Math.ceil(rect.right), (int) Math.ceil(rect.bottom)); if (rectIsVisible && mParent != null) { rectIsVisible = mParent.getChildVisibleRect(this, r, offset); } diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java index 38ce033470b6..b523b84c776e 100644 --- a/core/java/android/widget/TimePickerClockDelegate.java +++ b/core/java/android/widget/TimePickerClockDelegate.java @@ -198,14 +198,7 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl mAllowAutoAdvance = true; - // Updates mHourFormat variables used below. - updateHourFormat(mLocale, mIs24Hour); - - // Update hour text field. - final int minHour = mHourFormatStartsAtZero ? 0 : 1; - final int maxHour = (mIs24Hour ? 23 : 11) + minHour; - mHourView.setRange(minHour, maxHour); - mHourView.setShowLeadingZeroes(mHourFormatShowLeadingZero); + updateHourFormat(); // Initialize with current time. mTempCalendar = Calendar.getInstance(mLocale); @@ -232,15 +225,14 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl } /** - * Determines how the hour should be formatted and updates member variables - * related to hour formatting. - * - * @param locale the locale in which the view is displayed - * @param is24Hour whether the view is in 24-hour (hour-of-day) mode + * Updates hour formatting based on the current locale and 24-hour mode. + * <p> + * Determines how the hour should be formatted, sets member variables for + * leading zero and starting hour, and sets the hour view's presentation. */ - private void updateHourFormat(Locale locale, boolean is24Hour) { + private void updateHourFormat() { final String bestDateTimePattern = DateFormat.getBestDateTimePattern( - locale, is24Hour ? "Hm" : "hm"); + mLocale, mIs24Hour ? "Hm" : "hm"); final int lengthPattern = bestDateTimePattern.length(); boolean showLeadingZero = false; char hourFormat = '\0'; @@ -258,6 +250,12 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl mHourFormatShowLeadingZero = showLeadingZero; mHourFormatStartsAtZero = hourFormat == 'K' || hourFormat == 'H'; + + // Update hour text field. + final int minHour = mHourFormatStartsAtZero ? 0 : 1; + final int maxHour = (mIs24Hour ? 23 : 11) + minHour; + mHourView.setRange(minHour, maxHour); + mHourView.setShowLeadingZeroes(mHourFormatShowLeadingZero); } private static final CharSequence obtainVerbatim(String text) { @@ -456,6 +454,7 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl mIs24Hour = is24Hour; mInitialHourOfDay = getHour(); + updateHourFormat(); updateUI(mRadialTimePickerView.getCurrentItemShowing()); } } @@ -655,6 +654,10 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl /** * Converts hour-of-day (0-23) time into a localized hour number. + * <p> + * The localized value may be in the range (0-23), (1-24), (0-11), or + * (1-12) depending on the locale. This method does not handle leading + * zeroes. * * @param hourOfDay the hour-of-day (0-23) * @return a localized hour number diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java index 2c5e50c3bb4c..08c7935895ec 100644 --- a/core/java/com/android/internal/logging/MetricsLogger.java +++ b/core/java/com/android/internal/logging/MetricsLogger.java @@ -30,6 +30,9 @@ public class MetricsLogger implements MetricsConstants { public static final int QS_LOCK_TILE = 257; public static final int QS_USER_TILE = 258; public static final int QS_BATTERY_TILE = 259; + public static final int NOTIFICATION_ZEN_MODE_VISUAL_INTERRUPTIONS = 260; + public static final int ACTION_ZEN_ALLOW_PEEK = 261; + public static final int ACTION_ZEN_ALLOW_LIGHTS = 262; public static void visible(Context context, int category) throws IllegalArgumentException { if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) { diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java new file mode 100644 index 000000000000..b101733a1a14 --- /dev/null +++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.internal.policy; + +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Looper; +import android.view.Choreographer; +import android.view.DisplayListCanvas; +import android.view.RenderNode; +import android.view.ThreadedRenderer; +import android.view.View; + +/** + * The thread which draws a fill in background while the app is resizing in areas where the app + * content draw is lagging behind the resize operation. + * It starts with the creation and it ends once someone calls destroy(). + * Any size changes can be passed by a call to setTargetRect will passed to the thread and + * executed via the Choreographer. + * @hide + */ +public class BackdropFrameRenderer extends Thread implements Choreographer.FrameCallback { + + private DecorView mDecorView; + + // This is containing the last requested size by a resize command. Note that this size might + // or might not have been applied to the output already. + private final Rect mTargetRect = new Rect(); + + // The render nodes for the multi threaded renderer. + private ThreadedRenderer mRenderer; + private RenderNode mFrameAndBackdropNode; + + private final Rect mOldTargetRect = new Rect(); + private final Rect mNewTargetRect = new Rect(); + private Choreographer mChoreographer; + + // Cached size values from the last render for the case that the view hierarchy is gone + // during a configuration change. + private int mLastContentWidth; + private int mLastContentHeight; + private int mLastCaptionHeight; + private int mLastXOffset; + private int mLastYOffset; + + // Whether to report when next frame is drawn or not. + private boolean mReportNextDraw; + + private Drawable mCaptionBackgroundDrawable; + private Drawable mResizingBackgroundDrawable; + + public BackdropFrameRenderer(DecorView decorView, ThreadedRenderer renderer, Rect initialBounds, + Drawable resizingBackgroundDrawable, Drawable captionBackgroundDrawable) { + setName("ResizeFrame"); + + mRenderer = renderer; + onResourcesLoaded(decorView, resizingBackgroundDrawable, captionBackgroundDrawable); + + // Create a render node for the content and frame backdrop + // which can be resized independently from the content. + mFrameAndBackdropNode = RenderNode.create("FrameAndBackdropNode", null); + + mRenderer.addRenderNode(mFrameAndBackdropNode, true); + + // Set the initial bounds and draw once so that we do not get a broken frame. + mTargetRect.set(initialBounds); + synchronized (this) { + changeWindowSizeLocked(initialBounds); + } + + // Kick off our draw thread. + start(); + } + + void onResourcesLoaded(DecorView decorView, Drawable resizingBackgroundDrawable, + Drawable captionBackgroundDrawableDrawable) { + mDecorView = decorView; + mResizingBackgroundDrawable = resizingBackgroundDrawable; + mCaptionBackgroundDrawable = captionBackgroundDrawableDrawable; + } + + /** + * Call this function asynchronously when the window size has been changed. The change will + * be picked up once per frame and the frame will be re-rendered accordingly. + * @param newTargetBounds The new target bounds. + */ + public void setTargetRect(Rect newTargetBounds) { + synchronized (this) { + mTargetRect.set(newTargetBounds); + // Notify of a bounds change. + pingRenderLocked(); + } + } + + /** + * The window got replaced due to a configuration change. + */ + public void onConfigurationChange() { + synchronized (this) { + if (mRenderer != null) { + // Enforce a window redraw. + mOldTargetRect.set(0, 0, 0, 0); + pingRenderLocked(); + } + } + } + + /** + * All resources of the renderer will be released. This function can be called from the + * the UI thread as well as the renderer thread. + */ + public void releaseRenderer() { + synchronized (this) { + if (mRenderer != null) { + // Invalidate the current content bounds. + mRenderer.setContentDrawBounds(0, 0, 0, 0); + + // Remove the render node again + // (see comment above - better to do that only once). + mRenderer.removeRenderNode(mFrameAndBackdropNode); + + mRenderer = null; + + // Exit the renderer loop. + pingRenderLocked(); + } + } + } + + @Override + public void run() { + try { + Looper.prepare(); + synchronized (this) { + mChoreographer = Choreographer.getInstance(); + + // Draw at least once. + mChoreographer.postFrameCallback(this); + } + Looper.loop(); + } finally { + releaseRenderer(); + } + synchronized (this) { + // Make sure no more messages are being sent. + mChoreographer = null; + } + } + + /** + * The implementation of the FrameCallback. + * @param frameTimeNanos The time in nanoseconds when the frame started being rendered, + * in the {@link System#nanoTime()} timebase. Divide this value by {@code 1000000} + */ + @Override + public void doFrame(long frameTimeNanos) { + synchronized (this) { + if (mRenderer == null) { + reportDrawIfNeeded(); + // Tell the looper to stop. We are done. + Looper.myLooper().quit(); + return; + } + mNewTargetRect.set(mTargetRect); + if (!mNewTargetRect.equals(mOldTargetRect) || mReportNextDraw) { + mOldTargetRect.set(mNewTargetRect); + changeWindowSizeLocked(mNewTargetRect); + } + } + } + + /** + * The content is about to be drawn and we got the location of where it will be shown. + * If a "changeWindowSizeLocked" call has already been processed, we will re-issue the call + * if the previous call was ignored since the size was unknown. + * @param xOffset The x offset where the content is drawn to. + * @param yOffset The y offset where the content is drawn to. + * @param xSize The width size of the content. This should not be 0. + * @param ySize The height of the content. + * @return true if a frame should be requested after the content is drawn; false otherwise. + */ + public boolean onContentDrawn(int xOffset, int yOffset, int xSize, int ySize) { + synchronized (this) { + final boolean firstCall = mLastContentWidth == 0; + // The current content buffer is drawn here. + mLastContentWidth = xSize; + mLastContentHeight = ySize - mLastCaptionHeight; + mLastXOffset = xOffset; + mLastYOffset = yOffset; + + mRenderer.setContentDrawBounds( + mLastXOffset, + mLastYOffset, + mLastXOffset + mLastContentWidth, + mLastYOffset + mLastCaptionHeight + mLastContentHeight); + // If this was the first call and changeWindowSizeLocked got already called prior + // to us, we should re-issue a changeWindowSizeLocked now. + return firstCall + && (mLastCaptionHeight != 0 || !mDecorView.isShowingCaption()); + } + } + + public void onRequestDraw(boolean reportNextDraw) { + synchronized (this) { + mReportNextDraw = reportNextDraw; + mOldTargetRect.set(0, 0, 0, 0); + pingRenderLocked(); + } + } + + /** + * Resizing the frame to fit the new window size. + * @param newBounds The window bounds which needs to be drawn. + */ + private void changeWindowSizeLocked(Rect newBounds) { + + // While a configuration change is taking place the view hierarchy might become + // inaccessible. For that case we remember the previous metrics to avoid flashes. + // Note that even when there is no visible caption, the caption child will exist. + final int captionHeight = mDecorView.getCaptionHeight(); + // The caption height will probably never dynamically change while we are resizing. + // Once set to something other then 0 it should be kept that way. + if (captionHeight != 0) { + // Remember the height of the caption. + mLastCaptionHeight = captionHeight; + } + + // Make sure that the other thread has already prepared the render draw calls for the + // content. If any size is 0, we have to wait for it to be drawn first. + if ((mLastCaptionHeight == 0 && mDecorView.isShowingCaption()) || + mLastContentWidth == 0 || mLastContentHeight == 0) { + return; + } + + // Since the surface is spanning the entire screen, we have to add the start offset of + // the bounds to get to the surface location. + final int left = mLastXOffset + newBounds.left; + final int top = mLastYOffset + newBounds.top; + final int width = newBounds.width(); + final int height = newBounds.height(); + + mFrameAndBackdropNode.setLeftTopRightBottom(left, top, left + width, top + height); + + // Draw the caption and content backdrops in to our render node. + final DisplayListCanvas canvas = mFrameAndBackdropNode.start(width, height); + mCaptionBackgroundDrawable.setBounds(0, 0, left + width, top + mLastCaptionHeight); + mCaptionBackgroundDrawable.draw(canvas); + + // The backdrop: clear everything with the background. Clipping is done elsewhere. + mResizingBackgroundDrawable.setBounds(0, mLastCaptionHeight, left + width, top + height); + mResizingBackgroundDrawable.draw(canvas); + mFrameAndBackdropNode.end(canvas); + + // We need to render the node explicitly + mRenderer.drawRenderNode(mFrameAndBackdropNode); + + reportDrawIfNeeded(); + } + + /** Notify view root that a frame has been drawn by us, if it has requested so. */ + private void reportDrawIfNeeded() { + if (mReportNextDraw) { + if (mDecorView.isAttachedToWindow()) { + mDecorView.getViewRootImpl().reportDrawFinish(); + } + mReportNextDraw = false; + } + } + + /** + * Sends a message to the renderer to wake up and perform the next action which can be + * either the next rendering or the self destruction if mRenderer is null. + * Note: This call must be synchronized. + */ + private void pingRenderLocked() { + if (mChoreographer != null) { + mChoreographer.postFrameCallback(this); + } + } +} diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index 4f38ff34e7da..077cebc4ebf9 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -26,6 +26,7 @@ import com.android.internal.view.menu.MenuPopupHelper; import com.android.internal.widget.ActionBarContextView; import com.android.internal.widget.BackgroundFallback; import com.android.internal.widget.FloatingToolbar; +import com.android.internal.widget.NonClientDecorView; import android.animation.Animator; import android.animation.ObjectAnimator; @@ -38,6 +39,7 @@ import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Build; +import android.os.RemoteException; import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; @@ -46,14 +48,17 @@ import android.view.ContextThemeWrapper; import android.view.Gravity; import android.view.InputQueue; import android.view.KeyEvent; +import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; +import android.view.ThreadedRenderer; import android.view.View; import android.view.ViewGroup; import android.view.ViewStub; import android.view.ViewTreeObserver; import android.view.Window; +import android.view.WindowCallbacks; import android.view.WindowInsets; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; @@ -63,6 +68,8 @@ import android.view.animation.Interpolator; import android.widget.FrameLayout; import android.widget.PopupWindow; +import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.view.View.MeasureSpec.AT_MOST; import static android.view.View.MeasureSpec.EXACTLY; import static android.view.View.MeasureSpec.getMode; @@ -72,8 +79,11 @@ import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACK import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; +import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; -class DecorView extends FrameLayout implements RootViewSurfaceTaker { +/** @hide */ +public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks { private static final String TAG = "DecorView"; private static final boolean SWEEP_OPEN_MENU = false; @@ -151,6 +161,21 @@ class DecorView extends FrameLayout implements RootViewSurfaceTaker { private Rect mTempRect; private Rect mOutsets = new Rect(); + // This is the non client decor view for the window, containing the caption and window control + // buttons. The visibility of this decor depends on the workspace and the window type. + // If the window type does not require such a view, this member might be null. + NonClientDecorView mNonClientDecorView; + + // The non client decor needs to adapt to the used workspace. Since querying and changing the + // workspace is expensive, this is the workspace value the window is currently set up for. + int mWorkspaceId; + + private boolean mWindowResizeCallbacksAdded = false; + + public BackdropFrameRenderer mBackdropFrameRenderer = null; + private Drawable mResizingBackgroundDrawable; + private Drawable mCaptionBackgroundDrawable; + DecorView(Context context, int featureId, PhoneWindow window) { super(context); mFeatureId = featureId; @@ -326,7 +351,7 @@ class DecorView extends FrameLayout implements RootViewSurfaceTaker { @Override public boolean onInterceptTouchEvent(MotionEvent event) { int action = event.getAction(); - if (mHasNonClientDecor && mWindow.mNonClientDecorView.mVisible) { + if (mHasNonClientDecor && mNonClientDecorView.mVisible) { // Don't dispatch ACTION_DOWN to the non client decor if the window is // resizable and the event was (starting) outside the window. // Window resizing events should be handled by WindowManager. @@ -1209,6 +1234,17 @@ class DecorView extends FrameLayout implements RootViewSurfaceTaker { */ mWindow.openPanelsAfterRestore(); } + + if (!mWindowResizeCallbacksAdded) { + // If there is no window callback installed there was no window set before. Set it now. + // Note that our ViewRootImpl object will not change. + getViewRootImpl().addWindowCallbacks(this); + mWindowResizeCallbacksAdded = true; + } else if (mBackdropFrameRenderer != null) { + // We are resizing and this call happened due to a configuration change. Tell the + // renderer about it. + mBackdropFrameRenderer.onConfigurationChange(); + } } @Override @@ -1240,6 +1276,11 @@ class DecorView extends FrameLayout implements RootViewSurfaceTaker { if (st != null && st.menu != null && mFeatureId < 0) { st.menu.close(); } + + if (mWindowResizeCallbacksAdded) { + getViewRootImpl().removeWindowCallbacks(this); + mWindowResizeCallbacksAdded = false; + } } @Override @@ -1483,19 +1524,245 @@ class DecorView extends FrameLayout implements RootViewSurfaceTaker { * @return Returns true when the window has a shadow created by the non client decor. **/ private boolean windowHasShadow() { - return windowHasNonClientDecor() && ActivityManager.StackId - .hasWindowShadow(mWindow.mWorkspaceId); + return windowHasNonClientDecor() && ActivityManager.StackId.hasWindowShadow(mWorkspaceId); } void setWindow(PhoneWindow phoneWindow) { mWindow = phoneWindow; Context context = getContext(); if (context instanceof DecorContext) { - DecorContext decorContex = (DecorContext) context; - decorContex.setPhoneWindow(mWindow); + DecorContext decorContext = (DecorContext) context; + decorContext.setPhoneWindow(mWindow); + } + } + + void onConfigurationChanged() { + if (mNonClientDecorView != null) { + int workspaceId = getWorkspaceId(); + if (mWorkspaceId != workspaceId) { + mWorkspaceId = workspaceId; + // We might have to change the kind of surface before we do anything else. + mNonClientDecorView.onConfigurationChanged( + ActivityManager.StackId.hasWindowDecor(mWorkspaceId), + ActivityManager.StackId.hasWindowShadow(mWorkspaceId)); + enableNonClientDecor(ActivityManager.StackId.hasWindowDecor(workspaceId)); + } } } + View onResourcesLoaded(LayoutInflater inflater, int layoutResource) { + mWorkspaceId = getWorkspaceId(); + + mResizingBackgroundDrawable = getResizingBackgroundDrawable( + mWindow.mBackgroundResource, mWindow.mBackgroundFallbackResource); + mCaptionBackgroundDrawable = + getContext().getDrawable(R.drawable.non_client_decor_title_focused); + + if (mBackdropFrameRenderer != null) { + mBackdropFrameRenderer.onResourcesLoaded( + this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable); + } + + mNonClientDecorView = createNonClientDecorView(inflater); + final View root = inflater.inflate(layoutResource, null); + if (mNonClientDecorView != null) { + if (mNonClientDecorView.getParent() == null) { + addView(mNonClientDecorView, + new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); + } + mNonClientDecorView.addView(root, + new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); + } else { + addView(root, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); + } + mContentRoot = (ViewGroup) root; + return root; + } + + // Free floating overlapping windows require a non client decor with a caption and shadow.. + private NonClientDecorView createNonClientDecorView(LayoutInflater inflater) { + NonClientDecorView nonClientDecorView = null; + for (int i = getChildCount() - 1; i >= 0 && nonClientDecorView == null; i--) { + View view = getChildAt(i); + if (view instanceof NonClientDecorView) { + // The decor was most likely saved from a relaunch - so reuse it. + nonClientDecorView = (NonClientDecorView) view; + removeViewAt(i); + } + } + final WindowManager.LayoutParams attrs = mWindow.getAttributes(); + boolean isApplication = attrs.type == TYPE_BASE_APPLICATION || + attrs.type == TYPE_APPLICATION; + // Only a non floating application window on one of the allowed workspaces can get a non + // client decor. + final boolean hasNonClientDecor = ActivityManager.StackId.hasWindowDecor(mWorkspaceId); + if (!mWindow.isFloating() && isApplication && hasNonClientDecor) { + // Dependent on the brightness of the used title we either use the + // dark or the light button frame. + if (nonClientDecorView == null) { + Context context = getContext(); + TypedValue value = new TypedValue(); + context.getTheme().resolveAttribute(R.attr.colorPrimary, value, true); + inflater = inflater.from(context); + if (Color.luminance(value.data) < 0.5) { + nonClientDecorView = (NonClientDecorView) inflater.inflate( + R.layout.non_client_decor_dark, null); + } else { + nonClientDecorView = (NonClientDecorView) inflater.inflate( + R.layout.non_client_decor_light, null); + } + } + nonClientDecorView.setPhoneWindow(mWindow, + ActivityManager.StackId.hasWindowDecor(mWorkspaceId), + ActivityManager.StackId.hasWindowShadow(mWorkspaceId)); + } else { + nonClientDecorView = null; + } + + // Tell the decor if it has a visible non client decor. + enableNonClientDecor(nonClientDecorView != null && hasNonClientDecor); + return nonClientDecorView; + } + + /** + * Returns the color used to fill areas the app has not rendered content to yet when the + * user is resizing the window of an activity in multi-window mode. + */ + private Drawable getResizingBackgroundDrawable(int backgroundRes, int backgroundFallbackRes) { + final Context context = getContext(); + + if (backgroundRes != 0) { + final Drawable drawable = context.getDrawable(backgroundRes); + if (drawable != null) { + return drawable; + } + } + + if (backgroundFallbackRes != 0) { + final Drawable fallbackDrawable = context.getDrawable(backgroundFallbackRes); + if (fallbackDrawable != null) { + return fallbackDrawable; + } + } + + // We shouldn't really get here as the background fallback should be always available since + // it is defaulted by the system. + Log.w(TAG, "Failed to find background drawable for PhoneWindow=" + mWindow); + return null; + } + + /** + * Returns the Id of the workspace which contains this window. + * Note that if no workspace can be determined - which usually means that it was not + * created for an activity - the fullscreen workspace ID will be returned. + * @return Returns the workspace stack id which contains this window. + **/ + private int getWorkspaceId() { + int workspaceId = INVALID_STACK_ID; + final Window.WindowControllerCallback callback = mWindow.getWindowControllerCallback(); + if (callback != null) { + try { + workspaceId = callback.getWindowStackId(); + } catch (RemoteException ex) { + Log.e(TAG, "Failed to get the workspace ID of a PhoneWindow."); + } + } + if (workspaceId == INVALID_STACK_ID) { + return FULLSCREEN_WORKSPACE_STACK_ID; + } + return workspaceId; + } + + void clearContentView() { + if (mNonClientDecorView != null) { + if (mNonClientDecorView.getChildCount() > 1) { + mNonClientDecorView.removeViewAt(1); + } + } else { + // This window doesn't have non client decor, so we need to just remove the + // children of the decor view. + removeAllViews(); + } + } + + @Override + public void onWindowSizeIsChanging(Rect newBounds) { + if (mBackdropFrameRenderer != null) { + mBackdropFrameRenderer.setTargetRect(newBounds); + } + } + + @Override + public void onWindowDragResizeStart(Rect initialBounds) { + if (mWindow.isDestroyed()) { + // If the owner's window is gone, we should not be able to come here anymore. + releaseThreadedRenderer(); + return; + } + if (mBackdropFrameRenderer != null) { + return; + } + final ThreadedRenderer renderer = (ThreadedRenderer) getHardwareRenderer(); + if (renderer != null) { + mBackdropFrameRenderer = new BackdropFrameRenderer(this, renderer, + initialBounds, mResizingBackgroundDrawable, mCaptionBackgroundDrawable); + + // Get rid of the shadow while we are resizing. Shadow drawing takes considerable time. + // If we want to get the shadow shown while resizing, we would need to elevate a new + // element which owns the caption and has the elevation. + updateElevation(); + } + } + + @Override + public void onWindowDragResizeEnd() { + releaseThreadedRenderer(); + } + + @Override + public boolean onContentDrawn(int offsetX, int offsetY, int sizeX, int sizeY) { + if (mBackdropFrameRenderer == null) { + return false; + } + return mBackdropFrameRenderer.onContentDrawn(offsetX, offsetY, sizeX, sizeY); + } + + @Override + public void onRequestDraw(boolean reportNextDraw) { + if (mBackdropFrameRenderer != null) { + mBackdropFrameRenderer.onRequestDraw(reportNextDraw); + } else if (reportNextDraw) { + // If render thread is gone, just report immediately. + if (isAttachedToWindow()) { + getViewRootImpl().reportDrawFinish(); + } + } + } + + /** Release the renderer thread which is usually done when the user stops resizing. */ + private void releaseThreadedRenderer() { + if (mBackdropFrameRenderer != null) { + mBackdropFrameRenderer.releaseRenderer(); + mBackdropFrameRenderer = null; + // Bring the shadow back. + updateElevation(); + } + } + + private void updateElevation() { + if (mNonClientDecorView != null) { + mNonClientDecorView.updateElevation(); + } + } + + boolean isShowingCaption() { + return mNonClientDecorView != null && mNonClientDecorView.isShowingDecor(); + } + + int getCaptionHeight() { + return isShowingCaption() ? mNonClientDecorView.getDecorCaptionHeight() : 0; + } + private static class ColorViewState { View view = null; int targetVisibility = View.INVISIBLE; diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index c42714941a5b..6e7e5cfba131 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -16,13 +16,10 @@ package com.android.internal.policy; -import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; import static android.view.WindowManager.LayoutParams.*; -import android.app.ActivityManager.StackId; import android.app.ActivityManagerNative; import android.app.SearchManager; import android.os.UserHandle; @@ -60,7 +57,6 @@ import com.android.internal.view.menu.MenuPopupHelper; import com.android.internal.view.menu.MenuPresenter; import com.android.internal.view.menu.MenuView; import com.android.internal.widget.DecorContentParent; -import com.android.internal.widget.NonClientDecorView; import com.android.internal.widget.SwipeDismissLayout; import android.app.ActivityManager; @@ -72,7 +68,6 @@ import android.content.res.Configuration; import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.graphics.Color; -import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.media.session.MediaController; @@ -149,15 +144,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // view is requested, so we need to force the recreating without introducing an infinite loop. private boolean mForceDecorInstall = false; - // This is the non client decor view for the window, containing the caption and window control - // buttons. The visibility of this decor depends on the workspace and the window type. - // If the window type does not require such a view, this member might be null. - NonClientDecorView mNonClientDecorView; - - // The non client decor needs to adapt to the used workspace. Since querying and changing the - // workspace is expensive, this is the workspace value the window is currently set up for. - int mWorkspaceId; - // This is the view in which the window contents are placed. It is either // mDecor itself, or a child of mDecor where the contents go. ViewGroup mContentParent; @@ -220,12 +206,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private ProgressBar mHorizontalProgressBar; - private int mBackgroundResource = 0; - private int mBackgroundFallbackResource = 0; + int mBackgroundResource = 0; + int mBackgroundFallbackResource = 0; private Drawable mBackgroundDrawable; - private boolean mLoadEleveation = true; + private boolean mLoadElevation = true; private float mElevation; /** Whether window content should be clipped to the background outline. */ @@ -305,7 +291,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (preservedWindow != null) { mDecor = (DecorView) preservedWindow.getDecorView(); mElevation = preservedWindow.getElevation(); - mLoadEleveation = false; + mLoadElevation = false; mForceDecorInstall = true; // If we're preserving window, carry over the app token from the preserved // window, as we'll be skipping the addView in handleResumeActivity(), and @@ -478,15 +464,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } + @Override public void clearContentView() { - if (mNonClientDecorView != null) { - if (mNonClientDecorView.getChildCount() > 1) { - mNonClientDecorView.removeViewAt(1); - } - } else { - // This window doesn't have non client decor, so we need to just remove the children - // of the decor view. - mDecor.removeAllViews(); + if (mDecor != null) { + mDecor.clearContentView(); } } @@ -700,15 +681,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } } - if (mNonClientDecorView != null) { - int workspaceId = getWorkspaceId(); - if (mWorkspaceId != workspaceId) { - mWorkspaceId = workspaceId; - // We might have to change the kind of surface before we do anything else. - mNonClientDecorView.phoneWindowUpdated(StackId.hasWindowDecor(mWorkspaceId), - StackId.hasWindowShadow(mWorkspaceId)); - mDecor.enableNonClientDecor(StackId.hasWindowDecor(workspaceId)); - } + if (mDecor != null) { + mDecor.onConfigurationChanged(); } } @@ -2511,7 +2485,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { + Integer.toHexString(mFrameResource)); } } - if (mLoadEleveation) { + if (mLoadElevation) { mElevation = a.getDimension(R.styleable.Window_windowElevation, 0); } mClipToOutline = a.getBoolean(R.styleable.Window_windowClipToOutline, false); @@ -2581,19 +2555,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } mDecor.startChanging(); - - mNonClientDecorView = createNonClientDecorView(); - View in = mLayoutInflater.inflate(layoutResource, null); - if (mNonClientDecorView != null) { - if (mNonClientDecorView.getParent() == null) { - decor.addView(mNonClientDecorView, - new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); - } - mNonClientDecorView.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); - } else { - decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); - } - decor.mContentRoot = (ViewGroup) in; + final View in = mDecor.onResourcesLoaded(mLayoutInflater, layoutResource); ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); if (contentParent == null) { @@ -2648,50 +2610,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return contentParent; } - // Free floating overlapping windows require a non client decor with a caption and shadow.. - private NonClientDecorView createNonClientDecorView() { - NonClientDecorView nonClientDecorView = null; - for (int i = mDecor.getChildCount() - 1; i >= 0 && nonClientDecorView == null; i--) { - View view = mDecor.getChildAt(i); - if (view instanceof NonClientDecorView) { - // The decor was most likely saved from a relaunch - so reuse it. - nonClientDecorView = (NonClientDecorView) view; - mDecor.removeViewAt(i); - } - } - final WindowManager.LayoutParams attrs = getAttributes(); - boolean isApplication = attrs.type == TYPE_BASE_APPLICATION || - attrs.type == TYPE_APPLICATION; - mWorkspaceId = getWorkspaceId(); - // Only a non floating application window on one of the allowed workspaces can get a non - // client decor. - if (!isFloating() && isApplication && StackId.isStaticStack(mWorkspaceId)) { - // Dependent on the brightness of the used title we either use the - // dark or the light button frame. - if (nonClientDecorView == null) { - Context context = mDecor.getContext(); - TypedValue value = new TypedValue(); - context.getTheme().resolveAttribute(R.attr.colorPrimary, value, true); - LayoutInflater inflater = mLayoutInflater.from(context); - if (Color.luminance(value.data) < 0.5) { - nonClientDecorView = (NonClientDecorView) inflater.inflate( - R.layout.non_client_decor_dark, null); - } else { - nonClientDecorView = (NonClientDecorView) inflater.inflate( - R.layout.non_client_decor_light, null); - } - } - nonClientDecorView.setPhoneWindow(this, StackId.hasWindowDecor(mWorkspaceId), - StackId.hasWindowShadow(mWorkspaceId), getResizingBackgroundDrawable(), - mDecor.getContext().getDrawable(R.drawable.non_client_decor_title_focused)); - } - // Tell the decor if it has a visible non client decor. - mDecor.enableNonClientDecor( - nonClientDecorView != null&& StackId.hasWindowDecor(mWorkspaceId)); - - return nonClientDecorView; - } - /** @hide */ public void alwaysReadCloseOnTouchAttr() { mAlwaysReadCloseOnTouchAttr = true; @@ -3819,28 +3737,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { mIsStartingWindow = isStartingWindow; } - /** - * Returns the Id of the workspace which contains this window. - * Note that if no workspace can be determined - which usually means that it was not - * created for an activity - the fullscreen workspace ID will be returned. - * @return Returns the workspace stack id which contains this window. - **/ - private int getWorkspaceId() { - int workspaceId = INVALID_STACK_ID; - WindowControllerCallback callback = getWindowControllerCallback(); - if (callback != null) { - try { - workspaceId = callback.getWindowStackId(); - } catch (RemoteException ex) { - Log.e(TAG, "Failed to get the workspace ID of a PhoneWindow."); - } - } - if (workspaceId == INVALID_STACK_ID) { - return FULLSCREEN_WORKSPACE_STACK_ID; - } - return workspaceId; - } - @Override public void setTheme(int resid) { mTheme = resid; @@ -3851,31 +3747,4 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } } } - - /** - * Returns the color used to fill areas the app has not rendered content to yet when the user - * is resizing the window of an activity in multi-window mode. - * */ - private Drawable getResizingBackgroundDrawable() { - final Context context = mDecor.getContext(); - - if (mBackgroundResource != 0) { - final Drawable drawable = context.getDrawable(mBackgroundResource); - if (drawable != null) { - return drawable; - } - } - - if (mBackgroundFallbackResource != 0) { - final Drawable fallbackDrawable = context.getDrawable(mBackgroundFallbackResource); - if (fallbackDrawable != null) { - return fallbackDrawable; - } - } - - // We shouldn't really get here as the background fallback should be always available since - // it is defaulted by the system. - Log.w(TAG, "Failed to find background drawable for PhoneWindow=" + this); - return null; - } } diff --git a/core/java/com/android/internal/widget/NonClientDecorView.java b/core/java/com/android/internal/widget/NonClientDecorView.java index de6e2286fde9..33b8e0515ab0 100644 --- a/core/java/com/android/internal/widget/NonClientDecorView.java +++ b/core/java/com/android/internal/widget/NonClientDecorView.java @@ -19,26 +19,19 @@ package com.android.internal.widget; import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import android.content.Context; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.os.Looper; import android.os.RemoteException; import android.util.AttributeSet; -import android.view.Choreographer; -import android.view.DisplayListCanvas; import android.view.MotionEvent; -import android.view.RenderNode; -import android.view.ThreadedRenderer; import android.view.View; import android.widget.LinearLayout; import android.view.ViewGroup; import android.view.ViewOutlineProvider; import android.view.Window; -import android.view.WindowCallbacks; import android.util.Log; import android.util.TypedValue; import com.android.internal.R; +import com.android.internal.policy.DecorView; import com.android.internal.policy.PhoneWindow; /** @@ -67,7 +60,7 @@ import com.android.internal.policy.PhoneWindow; * This will be mitigated once b/22527834 will be addressed. */ public class NonClientDecorView extends LinearLayout - implements View.OnClickListener, View.OnTouchListener, WindowCallbacks { + implements View.OnClickListener, View.OnTouchListener { private final static String TAG = "NonClientDecorView"; // The height of a window which has focus in DIP. private final int DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP = 20; @@ -76,8 +69,6 @@ public class NonClientDecorView extends LinearLayout private PhoneWindow mOwner = null; private boolean mWindowHasShadow = false; private boolean mShowDecor = false; - // True when this object is listening for window size changes. - private boolean mAttachedCallbacksToRootViewImpl = false; // True if the window is being dragged. private boolean mDragging = false; @@ -96,12 +87,6 @@ public class NonClientDecorView extends LinearLayout // to max until the first layout command has been executed. private boolean mAllowUpdateElevation = false; - // The resize frame renderer. - private ResizeFrameThread mFrameRendererThread = null; - - private Drawable mResizingBackgroundDrawable; - private Drawable mCaptionBackgroundDrawable; - public NonClientDecorView(Context context) { super(context); } @@ -114,37 +99,10 @@ public class NonClientDecorView extends LinearLayout super(context, attrs, defStyle); } - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - if (!mAttachedCallbacksToRootViewImpl) { - // If there is no window callback installed there was no window set before. Set it now. - // Note that our ViewRootImpl object will not change. - getViewRootImpl().addWindowCallbacks(this); - mAttachedCallbacksToRootViewImpl = true; - } else if (mFrameRendererThread != null) { - // We are resizing and this call happened due to a configuration change. Tell the - // renderer about it. - mFrameRendererThread.onConfigurationChange(); - } - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - if (mAttachedCallbacksToRootViewImpl) { - getViewRootImpl().removeWindowCallbacks(this); - mAttachedCallbacksToRootViewImpl = false; - } - } - - public void setPhoneWindow(PhoneWindow owner, boolean showDecor, boolean windowHasShadow, - Drawable resizingBackgroundDrawable, Drawable captionBackgroundDrawableDrawable) { + public void setPhoneWindow(PhoneWindow owner, boolean showDecor, boolean windowHasShadow) { mOwner = owner; mWindowHasShadow = windowHasShadow; mShowDecor = showDecor; - mResizingBackgroundDrawable = resizingBackgroundDrawable; - mCaptionBackgroundDrawable = captionBackgroundDrawableDrawable; updateCaptionVisibility(); if (mWindowHasShadow) { initializeElevation(); @@ -208,7 +166,7 @@ public class NonClientDecorView extends LinearLayout * @param showDecor True if the decor should be shown. * @param windowHasShadow True when the window should show a shadow. **/ - public void phoneWindowUpdated(boolean showDecor, boolean windowHasShadow) { + public void onConfigurationChanged(boolean showDecor, boolean windowHasShadow) { mShowDecor = showDecor; updateCaptionVisibility(); if (windowHasShadow != mWindowHasShadow) { @@ -294,11 +252,12 @@ public class NonClientDecorView extends LinearLayout * Note: Windows which have (temporarily) changed their attributes to cover the SystemUI * will get no shadow as they are expected to be "full screen". **/ - private void updateElevation() { + public void updateElevation() { float elevation = 0; // Do not use a shadow when we are in resizing mode (mRenderer not null) since the shadow // is bound to the content size and not the target size. - if (mWindowHasShadow && mFrameRendererThread == null) { + if (mWindowHasShadow + && ((DecorView) mOwner.getDecorView()).mBackdropFrameRenderer == null) { boolean fill = isFillingScreen(); elevation = fill ? 0 : (mWindowHasFocus ? DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP : @@ -340,329 +299,12 @@ public class NonClientDecorView extends LinearLayout } } - @Override - public void onWindowDragResizeStart(Rect initialBounds) { - if (mOwner.isDestroyed()) { - // If the owner's window is gone, we should not be able to come here anymore. - releaseResources(); - return; - } - if (mFrameRendererThread != null) { - return; - } - final ThreadedRenderer renderer = - (ThreadedRenderer) mOwner.getDecorView().getHardwareRenderer(); - if (renderer != null) { - mFrameRendererThread = new ResizeFrameThread(renderer, initialBounds); - // Get rid of the shadow while we are resizing. Shadow drawing takes considerable time. - // If we want to get the shadow shown while resizing, we would need to elevate a new - // element which owns the caption and has the elevation. - updateElevation(); - } - } - - @Override - public boolean onContentDrawn(int xOffset, int yOffset, int xSize, int ySize) { - if (mFrameRendererThread == null) { - return false; - } - return mFrameRendererThread.onContentDrawn(xOffset, yOffset, xSize, ySize); - } - - @Override - public void onRequestDraw(boolean reportNextDraw) { - if (mFrameRendererThread != null) { - mFrameRendererThread.onRequestDraw(reportNextDraw); - } else if (reportNextDraw) { - // If render thread is gone, just report immediately. - if (isAttachedToWindow()) { - getViewRootImpl().reportDrawFinish(); - } - } - } - - @Override - public void onWindowDragResizeEnd() { - releaseThreadedRenderer(); - } - - @Override - public void onWindowSizeIsChanging(Rect newBounds) { - if (mFrameRendererThread != null) { - mFrameRendererThread.setTargetRect(newBounds); - } - } - - /** - * Release the renderer thread which is usually done when the user stops resizing. - */ - private void releaseThreadedRenderer() { - if (mFrameRendererThread != null) { - mFrameRendererThread.releaseRenderer(); - mFrameRendererThread = null; - // Bring the shadow back. - updateElevation(); - } - } - - /** - * Called when the parent window is destroyed to release all resources. Note that this will also - * destroy the renderer thread. - */ - private void releaseResources() { - releaseThreadedRenderer(); + public boolean isShowingDecor() { + return mShowDecor; } - /** - * The thread which draws the chrome while we are resizing. - * It starts with the creation and it ends once someone calls destroy(). - * Any size changes can be passed by a call to setTargetRect will passed to the thread and - * executed via the Choreographer. - * TODO(b/24810450): Separate functionality from non-client-decor so that it can be used - * independently. - */ - private class ResizeFrameThread extends Thread implements Choreographer.FrameCallback { - // This is containing the last requested size by a resize command. Note that this size might - // or might not have been applied to the output already. - private final Rect mTargetRect = new Rect(); - - // The render nodes for the multi threaded renderer. - private ThreadedRenderer mRenderer; - private RenderNode mFrameAndBackdropNode; - - private final Rect mOldTargetRect = new Rect(); - private final Rect mNewTargetRect = new Rect(); - private Choreographer mChoreographer; - - // Cached size values from the last render for the case that the view hierarchy is gone - // during a configuration change. - private int mLastContentWidth; - private int mLastContentHeight; - private int mLastCaptionHeight; - private int mLastXOffset; - private int mLastYOffset; - - // Whether to report when next frame is drawn or not. - private boolean mReportNextDraw; - - ResizeFrameThread(ThreadedRenderer renderer, Rect initialBounds) { - setName("ResizeFrame"); - mRenderer = renderer; - - // Create a render node for the content and frame backdrop - // which can be resized independently from the content. - mFrameAndBackdropNode = RenderNode.create("FrameAndBackdropNode", null); - - mRenderer.addRenderNode(mFrameAndBackdropNode, true); - - // Set the initial bounds and draw once so that we do not get a broken frame. - mTargetRect.set(initialBounds); - synchronized (this) { - changeWindowSizeLocked(initialBounds); - } - - // Kick off our draw thread. - start(); - } - - /** - * Call this function asynchronously when the window size has been changed. The change will - * be picked up once per frame and the frame will be re-rendered accordingly. - * @param newTargetBounds The new target bounds. - */ - public void setTargetRect(Rect newTargetBounds) { - synchronized (this) { - mTargetRect.set(newTargetBounds); - // Notify of a bounds change. - pingRenderLocked(); - } - } - - /** - * The window got replaced due to a configuration change. - */ - public void onConfigurationChange() { - synchronized (this) { - if (mRenderer != null) { - // Enforce a window redraw. - mOldTargetRect.set(0, 0, 0, 0); - pingRenderLocked(); - } - } - } - - /** - * All resources of the renderer will be released. This function can be called from the - * the UI thread as well as the renderer thread. - */ - public void releaseRenderer() { - synchronized (this) { - if (mRenderer != null) { - // Invalidate the current content bounds. - mRenderer.setContentDrawBounds(0, 0, 0, 0); - - // Remove the render node again - // (see comment above - better to do that only once). - mRenderer.removeRenderNode(mFrameAndBackdropNode); - - mRenderer = null; - - // Exit the renderer loop. - pingRenderLocked(); - } - } - } - - @Override - public void run() { - try { - Looper.prepare(); - synchronized (this) { - mChoreographer = Choreographer.getInstance(); - - // Draw at least once. - mChoreographer.postFrameCallback(this); - } - Looper.loop(); - } finally { - releaseRenderer(); - } - synchronized (this) { - // Make sure no more messages are being sent. - mChoreographer = null; - } - } - - /** - * The implementation of the FrameCallback. - * @param frameTimeNanos The time in nanoseconds when the frame started being rendered, - * in the {@link System#nanoTime()} timebase. Divide this value by {@code 1000000} - */ - @Override - public void doFrame(long frameTimeNanos) { - synchronized (this) { - if (mRenderer == null) { - reportDrawIfNeeded(); - // Tell the looper to stop. We are done. - Looper.myLooper().quit(); - return; - } - mNewTargetRect.set(mTargetRect); - if (!mNewTargetRect.equals(mOldTargetRect) || mReportNextDraw) { - mOldTargetRect.set(mNewTargetRect); - changeWindowSizeLocked(mNewTargetRect); - } - } - } - - /** - * The content is about to be drawn and we got the location of where it will be shown. - * If a "changeWindowSizeLocked" call has already been processed, we will re-issue the call - * if the previous call was ignored since the size was unknown. - * @param xOffset The x offset where the content is drawn to. - * @param yOffset The y offset where the content is drawn to. - * @param xSize The width size of the content. This should not be 0. - * @param ySize The height of the content. - * @return true if a frame should be requested after the content is drawn; false otherwise. - */ - public boolean onContentDrawn(int xOffset, int yOffset, int xSize, int ySize) { - synchronized (this) { - final boolean firstCall = mLastContentWidth == 0; - // The current content buffer is drawn here. - mLastContentWidth = xSize; - mLastContentHeight = ySize - mLastCaptionHeight; - mLastXOffset = xOffset; - mLastYOffset = yOffset; - - mRenderer.setContentDrawBounds( - mLastXOffset, - mLastYOffset, - mLastXOffset + mLastContentWidth, - mLastYOffset + mLastCaptionHeight + mLastContentHeight); - // If this was the first call and changeWindowSizeLocked got already called prior - // to us, we should re-issue a changeWindowSizeLocked now. - return firstCall && (mLastCaptionHeight != 0 || !mShowDecor); - } - } - - public void onRequestDraw(boolean reportNextDraw) { - synchronized (this) { - mReportNextDraw = reportNextDraw; - mOldTargetRect.set(0, 0, 0, 0); - pingRenderLocked(); - } - } - - /** - * Resizing the frame to fit the new window size. - * @param newBounds The window bounds which needs to be drawn. - */ - private void changeWindowSizeLocked(Rect newBounds) { - // While a configuration change is taking place the view hierarchy might become - // inaccessible. For that case we remember the previous metrics to avoid flashes. - // Note that even when there is no visible caption, the caption child will exist. - View caption = getChildAt(0); - if (caption != null) { - final int captionHeight = caption.getHeight(); - // The caption height will probably never dynamically change while we are resizing. - // Once set to something other then 0 it should be kept that way. - if (captionHeight != 0) { - // Remember the height of the caption. - mLastCaptionHeight = captionHeight; - } - } - // Make sure that the other thread has already prepared the render draw calls for the - // content. If any size is 0, we have to wait for it to be drawn first. - if ((mLastCaptionHeight == 0 && mShowDecor) || - mLastContentWidth == 0 || mLastContentHeight == 0) { - return; - } - // Since the surface is spanning the entire screen, we have to add the start offset of - // the bounds to get to the surface location. - final int left = mLastXOffset + newBounds.left; - final int top = mLastYOffset + newBounds.top; - final int width = newBounds.width(); - final int height = newBounds.height(); - - mFrameAndBackdropNode.setLeftTopRightBottom(left, top, left + width, top + height); - - // Draw the caption and content backdrops in to our render node. - DisplayListCanvas canvas = mFrameAndBackdropNode.start(width, height); - mCaptionBackgroundDrawable.setBounds(0, 0, left + width, top + mLastCaptionHeight); - mCaptionBackgroundDrawable.draw(canvas); - - // The backdrop: clear everything with the background. Clipping is done elsewhere. - mResizingBackgroundDrawable.setBounds(0, mLastCaptionHeight, left + width, top + height); - mResizingBackgroundDrawable.draw(canvas); - mFrameAndBackdropNode.end(canvas); - - // We need to render the node explicitly - mRenderer.drawRenderNode(mFrameAndBackdropNode); - - reportDrawIfNeeded(); - } - - /** - * Notify view root that a frame has been drawn by us, if it has requested so. - */ - private void reportDrawIfNeeded() { - if (mReportNextDraw) { - if (isAttachedToWindow()) { - getViewRootImpl().reportDrawFinish(); - } - mReportNextDraw = false; - } - } - - /** - * Sends a message to the renderer to wake up and perform the next action which can be - * either the next rendering or the self destruction if mRenderer is null. - * Note: This call must be synchronized. - */ - private void pingRenderLocked() { - if (mChoreographer != null) { - mChoreographer.postFrameCallback(this); - } - } + public int getDecorCaptionHeight() { + final View caption = getChildAt(0); + return (caption != null) ? caption.getHeight() : 0; } } diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 815d3302ee0b..65e8058f25ba 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -608,15 +608,6 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote) kEMIntFast, kEMJitCompiler, } executionMode = kEMDefault; - char profilePeriod[sizeof("-Xprofile-period:")-1 + PROPERTY_VALUE_MAX]; - char profileDuration[sizeof("-Xprofile-duration:")-1 + PROPERTY_VALUE_MAX]; - char profileInterval[sizeof("-Xprofile-interval:")-1 + PROPERTY_VALUE_MAX]; - char profileBackoff[sizeof("-Xprofile-backoff:")-1 + PROPERTY_VALUE_MAX]; - char profileTopKThreshold[sizeof("-Xprofile-top-k-threshold:")-1 + PROPERTY_VALUE_MAX]; - char profileTopKChangeThreshold[sizeof("-Xprofile-top-k-change-threshold:")-1 + - PROPERTY_VALUE_MAX]; - char profileType[sizeof("-Xprofile-type:")-1 + PROPERTY_VALUE_MAX]; - char profileMaxStackDepth[sizeof("-Xprofile-max-stack-depth:")-1 + PROPERTY_VALUE_MAX]; char localeOption[sizeof("-Duser.locale=") + PROPERTY_VALUE_MAX]; char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:")-1 + PROPERTY_VALUE_MAX]; char nativeBridgeLibrary[sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX]; @@ -835,60 +826,6 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote) addOption(localeOption); } - /* - * Set profiler options - */ - // Whether or not the profiler should be enabled. - property_get("dalvik.vm.profiler", propBuf, "0"); - if (propBuf[0] == '1') { - addOption("-Xenable-profiler"); - } - - // Whether the profile should start upon app startup or be delayed by some random offset - // (in seconds) that is bound between 0 and a fixed value. - property_get("dalvik.vm.profile.start-immed", propBuf, "0"); - if (propBuf[0] == '1') { - addOption("-Xprofile-start-immediately"); - } - - // Number of seconds during profile runs. - parseRuntimeOption("dalvik.vm.profile.period-secs", profilePeriod, "-Xprofile-period:"); - - // Length of each profile run (seconds). - parseRuntimeOption("dalvik.vm.profile.duration-secs", - profileDuration, - "-Xprofile-duration:"); - - // Polling interval during profile run (microseconds). - parseRuntimeOption("dalvik.vm.profile.interval-us", profileInterval, "-Xprofile-interval:"); - - // Coefficient for period backoff. The the period is multiplied - // by this value after each profile run. - parseRuntimeOption("dalvik.vm.profile.backoff-coeff", profileBackoff, "-Xprofile-backoff:"); - - // Top K% of samples that are considered relevant when - // deciding if the app should be recompiled. - parseRuntimeOption("dalvik.vm.profile.top-k-thr", - profileTopKThreshold, - "-Xprofile-top-k-threshold:"); - - // The threshold after which a change in the structure of the - // top K% profiled samples becomes significant and triggers - // recompilation. A change in profile is considered - // significant if X% (top-k-change-threshold) of the top K% - // (top-k-threshold property) samples has changed. - parseRuntimeOption("dalvik.vm.profile.top-k-ch-thr", - profileTopKChangeThreshold, - "-Xprofile-top-k-change-threshold:"); - - // Type of profile data. - parseRuntimeOption("dalvik.vm.profiler.type", profileType, "-Xprofile-type:"); - - // Depth of bounded stack data - parseRuntimeOption("dalvik.vm.profile.stack-depth", - profileMaxStackDepth, - "-Xprofile-max-stack-depth:"); - // Trace files are stored in /data/misc/trace which is writable only in debug mode. property_get("ro.debuggable", propBuf, "0"); if (strcmp(propBuf, "1") == 0) { diff --git a/core/jni/android_view_PointerIcon.cpp b/core/jni/android_view_PointerIcon.cpp index d04adbfc742b..d7e2c028a23f 100644 --- a/core/jni/android_view_PointerIcon.cpp +++ b/core/jni/android_view_PointerIcon.cpp @@ -24,6 +24,7 @@ #include <android_runtime/Log.h> #include <utils/Log.h> #include <android/graphics/GraphicsJNI.h> +#include "ScopedLocalRef.h" #include "core_jni_helpers.h" @@ -35,6 +36,8 @@ static struct { jfieldID mBitmap; jfieldID mHotSpotX; jfieldID mHotSpotY; + jfieldID mBitmapFrames; + jfieldID mDurationPerFrame; jmethodID getSystemIcon; jmethodID load; } gPointerIconClassInfo; @@ -84,6 +87,19 @@ status_t android_view_PointerIcon_load(JNIEnv* env, jobject pointerIconObj, jobj env->DeleteLocalRef(bitmapObj); } + ScopedLocalRef<jobjectArray> bitmapFramesObj(env, reinterpret_cast<jobjectArray>( + env->GetObjectField(loadedPointerIconObj, gPointerIconClassInfo.mBitmapFrames))); + if (bitmapFramesObj.get()) { + outPointerIcon->durationPerFrame = env->GetIntField( + loadedPointerIconObj, gPointerIconClassInfo.mDurationPerFrame); + jsize size = env->GetArrayLength(bitmapFramesObj.get()); + outPointerIcon->bitmapFrames.resize(size); + for (jsize i = 0; i < size; ++i) { + ScopedLocalRef<jobject> bitmapObj(env, env->GetObjectArrayElement(bitmapFramesObj.get(), i)); + GraphicsJNI::getSkBitmap(env, bitmapObj.get(), &(outPointerIcon->bitmapFrames[i])); + } + } + env->DeleteLocalRef(loadedPointerIconObj); return OK; } @@ -121,6 +137,12 @@ int register_android_view_PointerIcon(JNIEnv* env) { gPointerIconClassInfo.mHotSpotY = GetFieldIDOrDie(env, gPointerIconClassInfo.clazz, "mHotSpotY", "F"); + gPointerIconClassInfo.mBitmapFrames = GetFieldIDOrDie(env, gPointerIconClassInfo.clazz, + "mBitmapFrames", "[Landroid/graphics/Bitmap;"); + + gPointerIconClassInfo.mDurationPerFrame = GetFieldIDOrDie(env, gPointerIconClassInfo.clazz, + "mDurationPerFrame", "I"); + gPointerIconClassInfo.getSystemIcon = GetStaticMethodIDOrDie(env, gPointerIconClassInfo.clazz, "getSystemIcon", "(Landroid/content/Context;I)Landroid/view/PointerIcon;"); diff --git a/core/jni/android_view_PointerIcon.h b/core/jni/android_view_PointerIcon.h index 86f288d0d711..ca080850df94 100644 --- a/core/jni/android_view_PointerIcon.h +++ b/core/jni/android_view_PointerIcon.h @@ -19,6 +19,8 @@ #include "jni.h" +#include <vector> + #include <utils/Errors.h> #include <SkBitmap.h> @@ -69,6 +71,8 @@ struct PointerIcon { SkBitmap bitmap; float hotSpotX; float hotSpotY; + std::vector<SkBitmap> bitmapFrames; + int32_t durationPerFrame; inline bool isNullIcon() { return style == POINTER_ICON_STYLE_NULL; @@ -79,6 +83,8 @@ struct PointerIcon { bitmap.reset(); hotSpotX = 0; hotSpotY = 0; + bitmapFrames.clear(); + durationPerFrame = 0; } }; diff --git a/core/res/res/drawable-mdpi/pointer_wait_0.png b/core/res/res/drawable-mdpi/pointer_wait_0.png Binary files differnew file mode 100644 index 000000000000..adb78064f03c --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_0.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_1.png b/core/res/res/drawable-mdpi/pointer_wait_1.png Binary files differnew file mode 100644 index 000000000000..fc6b42fbb856 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_1.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_10.png b/core/res/res/drawable-mdpi/pointer_wait_10.png Binary files differnew file mode 100644 index 000000000000..02968b524ff1 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_10.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_11.png b/core/res/res/drawable-mdpi/pointer_wait_11.png Binary files differnew file mode 100644 index 000000000000..24f866bf1d41 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_11.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_12.png b/core/res/res/drawable-mdpi/pointer_wait_12.png Binary files differnew file mode 100644 index 000000000000..d1a31bc5bce4 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_12.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_13.png b/core/res/res/drawable-mdpi/pointer_wait_13.png Binary files differnew file mode 100644 index 000000000000..b0c679862384 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_13.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_14.png b/core/res/res/drawable-mdpi/pointer_wait_14.png Binary files differnew file mode 100644 index 000000000000..721e86d168a0 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_14.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_15.png b/core/res/res/drawable-mdpi/pointer_wait_15.png Binary files differnew file mode 100644 index 000000000000..adb019909813 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_15.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_16.png b/core/res/res/drawable-mdpi/pointer_wait_16.png Binary files differnew file mode 100644 index 000000000000..3695c18f6397 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_16.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_17.png b/core/res/res/drawable-mdpi/pointer_wait_17.png Binary files differnew file mode 100644 index 000000000000..861605e20f82 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_17.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_18.png b/core/res/res/drawable-mdpi/pointer_wait_18.png Binary files differnew file mode 100644 index 000000000000..f5dfdcf69af4 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_18.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_19.png b/core/res/res/drawable-mdpi/pointer_wait_19.png Binary files differnew file mode 100644 index 000000000000..9d51f79208d5 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_19.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_2.png b/core/res/res/drawable-mdpi/pointer_wait_2.png Binary files differnew file mode 100644 index 000000000000..d73a1542165e --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_2.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_20.png b/core/res/res/drawable-mdpi/pointer_wait_20.png Binary files differnew file mode 100644 index 000000000000..81d1d51f680b --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_20.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_21.png b/core/res/res/drawable-mdpi/pointer_wait_21.png Binary files differnew file mode 100644 index 000000000000..331820bccce8 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_21.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_22.png b/core/res/res/drawable-mdpi/pointer_wait_22.png Binary files differnew file mode 100644 index 000000000000..2678d3204424 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_22.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_23.png b/core/res/res/drawable-mdpi/pointer_wait_23.png Binary files differnew file mode 100644 index 000000000000..d54d9eb77b8d --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_23.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_24.png b/core/res/res/drawable-mdpi/pointer_wait_24.png Binary files differnew file mode 100644 index 000000000000..442ace7c9af2 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_24.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_25.png b/core/res/res/drawable-mdpi/pointer_wait_25.png Binary files differnew file mode 100644 index 000000000000..27ce60da8e4a --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_25.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_26.png b/core/res/res/drawable-mdpi/pointer_wait_26.png Binary files differnew file mode 100644 index 000000000000..8143634e9256 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_26.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_27.png b/core/res/res/drawable-mdpi/pointer_wait_27.png Binary files differnew file mode 100644 index 000000000000..496ab9a0509f --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_27.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_28.png b/core/res/res/drawable-mdpi/pointer_wait_28.png Binary files differnew file mode 100644 index 000000000000..a2aab2bf6262 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_28.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_29.png b/core/res/res/drawable-mdpi/pointer_wait_29.png Binary files differnew file mode 100644 index 000000000000..646d15366f5a --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_29.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_3.png b/core/res/res/drawable-mdpi/pointer_wait_3.png Binary files differnew file mode 100644 index 000000000000..9f45afeebf85 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_3.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_30.png b/core/res/res/drawable-mdpi/pointer_wait_30.png Binary files differnew file mode 100644 index 000000000000..27b3fc40f1e1 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_30.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_31.png b/core/res/res/drawable-mdpi/pointer_wait_31.png Binary files differnew file mode 100644 index 000000000000..6dbe184c4f64 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_31.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_32.png b/core/res/res/drawable-mdpi/pointer_wait_32.png Binary files differnew file mode 100644 index 000000000000..9f072ef2fe35 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_32.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_33.png b/core/res/res/drawable-mdpi/pointer_wait_33.png Binary files differnew file mode 100644 index 000000000000..881ec5f97139 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_33.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_34.png b/core/res/res/drawable-mdpi/pointer_wait_34.png Binary files differnew file mode 100644 index 000000000000..94961e3a4b82 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_34.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_35.png b/core/res/res/drawable-mdpi/pointer_wait_35.png Binary files differnew file mode 100644 index 000000000000..dfa65d72b863 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_35.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_4.png b/core/res/res/drawable-mdpi/pointer_wait_4.png Binary files differnew file mode 100644 index 000000000000..5d3d652fa231 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_4.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_5.png b/core/res/res/drawable-mdpi/pointer_wait_5.png Binary files differnew file mode 100644 index 000000000000..d440a82fa94e --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_5.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_6.png b/core/res/res/drawable-mdpi/pointer_wait_6.png Binary files differnew file mode 100644 index 000000000000..ae6559074c89 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_6.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_7.png b/core/res/res/drawable-mdpi/pointer_wait_7.png Binary files differnew file mode 100644 index 000000000000..cd84aa5d874d --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_7.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_8.png b/core/res/res/drawable-mdpi/pointer_wait_8.png Binary files differnew file mode 100644 index 000000000000..0b81a9aeab25 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_8.png diff --git a/core/res/res/drawable-mdpi/pointer_wait_9.png b/core/res/res/drawable-mdpi/pointer_wait_9.png Binary files differnew file mode 100644 index 000000000000..c13a90c19482 --- /dev/null +++ b/core/res/res/drawable-mdpi/pointer_wait_9.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_0.png b/core/res/res/drawable-xhdpi/pointer_wait_0.png Binary files differnew file mode 100644 index 000000000000..5396784c20e8 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_0.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_1.png b/core/res/res/drawable-xhdpi/pointer_wait_1.png Binary files differnew file mode 100644 index 000000000000..25edbf573011 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_1.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_10.png b/core/res/res/drawable-xhdpi/pointer_wait_10.png Binary files differnew file mode 100644 index 000000000000..96d93a9049ce --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_10.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_11.png b/core/res/res/drawable-xhdpi/pointer_wait_11.png Binary files differnew file mode 100644 index 000000000000..cd78675c34ba --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_11.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_12.png b/core/res/res/drawable-xhdpi/pointer_wait_12.png Binary files differnew file mode 100644 index 000000000000..1b2c7b218e4a --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_12.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_13.png b/core/res/res/drawable-xhdpi/pointer_wait_13.png Binary files differnew file mode 100644 index 000000000000..3b00f101a5b4 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_13.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_14.png b/core/res/res/drawable-xhdpi/pointer_wait_14.png Binary files differnew file mode 100644 index 000000000000..eca5c3f50c6e --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_14.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_15.png b/core/res/res/drawable-xhdpi/pointer_wait_15.png Binary files differnew file mode 100644 index 000000000000..0fc2085ac6fd --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_15.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_16.png b/core/res/res/drawable-xhdpi/pointer_wait_16.png Binary files differnew file mode 100644 index 000000000000..db13cf61e018 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_16.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_17.png b/core/res/res/drawable-xhdpi/pointer_wait_17.png Binary files differnew file mode 100644 index 000000000000..9b6fac59d823 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_17.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_18.png b/core/res/res/drawable-xhdpi/pointer_wait_18.png Binary files differnew file mode 100644 index 000000000000..c56ff6c1a6f2 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_18.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_19.png b/core/res/res/drawable-xhdpi/pointer_wait_19.png Binary files differnew file mode 100644 index 000000000000..22b7c9099e4b --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_19.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_2.png b/core/res/res/drawable-xhdpi/pointer_wait_2.png Binary files differnew file mode 100644 index 000000000000..4bdbe3fadfc7 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_2.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_20.png b/core/res/res/drawable-xhdpi/pointer_wait_20.png Binary files differnew file mode 100644 index 000000000000..6d042fb318f8 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_20.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_21.png b/core/res/res/drawable-xhdpi/pointer_wait_21.png Binary files differnew file mode 100644 index 000000000000..e3ab63fbe627 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_21.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_22.png b/core/res/res/drawable-xhdpi/pointer_wait_22.png Binary files differnew file mode 100644 index 000000000000..b25f6b7dba47 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_22.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_23.png b/core/res/res/drawable-xhdpi/pointer_wait_23.png Binary files differnew file mode 100644 index 000000000000..49faba909561 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_23.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_24.png b/core/res/res/drawable-xhdpi/pointer_wait_24.png Binary files differnew file mode 100644 index 000000000000..e91c340e3333 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_24.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_25.png b/core/res/res/drawable-xhdpi/pointer_wait_25.png Binary files differnew file mode 100644 index 000000000000..f4785c6d4fb7 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_25.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_26.png b/core/res/res/drawable-xhdpi/pointer_wait_26.png Binary files differnew file mode 100644 index 000000000000..ea902f80fde4 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_26.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_27.png b/core/res/res/drawable-xhdpi/pointer_wait_27.png Binary files differnew file mode 100644 index 000000000000..7d628c3886d3 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_27.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_28.png b/core/res/res/drawable-xhdpi/pointer_wait_28.png Binary files differnew file mode 100644 index 000000000000..92d6dc183b11 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_28.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_29.png b/core/res/res/drawable-xhdpi/pointer_wait_29.png Binary files differnew file mode 100644 index 000000000000..5a8d18915190 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_29.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_3.png b/core/res/res/drawable-xhdpi/pointer_wait_3.png Binary files differnew file mode 100644 index 000000000000..de4d79c80d35 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_3.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_30.png b/core/res/res/drawable-xhdpi/pointer_wait_30.png Binary files differnew file mode 100644 index 000000000000..ba04b5e8acb2 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_30.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_31.png b/core/res/res/drawable-xhdpi/pointer_wait_31.png Binary files differnew file mode 100644 index 000000000000..3ef8e9838a6e --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_31.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_32.png b/core/res/res/drawable-xhdpi/pointer_wait_32.png Binary files differnew file mode 100644 index 000000000000..3297a7d15e5f --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_32.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_33.png b/core/res/res/drawable-xhdpi/pointer_wait_33.png Binary files differnew file mode 100644 index 000000000000..b0ac3b9655ed --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_33.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_34.png b/core/res/res/drawable-xhdpi/pointer_wait_34.png Binary files differnew file mode 100644 index 000000000000..0eaa38623280 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_34.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_35.png b/core/res/res/drawable-xhdpi/pointer_wait_35.png Binary files differnew file mode 100644 index 000000000000..73894d8981c9 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_35.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_4.png b/core/res/res/drawable-xhdpi/pointer_wait_4.png Binary files differnew file mode 100644 index 000000000000..ea44e85ded92 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_4.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_5.png b/core/res/res/drawable-xhdpi/pointer_wait_5.png Binary files differnew file mode 100644 index 000000000000..46c399dc57e2 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_5.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_6.png b/core/res/res/drawable-xhdpi/pointer_wait_6.png Binary files differnew file mode 100644 index 000000000000..3b9aff69813d --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_6.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_7.png b/core/res/res/drawable-xhdpi/pointer_wait_7.png Binary files differnew file mode 100644 index 000000000000..a54edc06e45f --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_7.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_8.png b/core/res/res/drawable-xhdpi/pointer_wait_8.png Binary files differnew file mode 100644 index 000000000000..2f30732dbc57 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_8.png diff --git a/core/res/res/drawable-xhdpi/pointer_wait_9.png b/core/res/res/drawable-xhdpi/pointer_wait_9.png Binary files differnew file mode 100644 index 000000000000..f39c7a753959 --- /dev/null +++ b/core/res/res/drawable-xhdpi/pointer_wait_9.png diff --git a/core/res/res/drawable/pointer_wait.xml b/core/res/res/drawable/pointer_wait.xml new file mode 100644 index 000000000000..8955ce8dd418 --- /dev/null +++ b/core/res/res/drawable/pointer_wait.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> + <item android:drawable="@drawable/pointer_wait_1" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_2" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_3" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_4" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_5" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_6" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_7" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_8" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_9" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_10" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_11" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_12" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_13" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_14" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_15" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_16" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_17" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_18" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_19" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_20" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_21" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_22" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_23" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_24" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_25" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_26" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_27" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_28" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_29" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_30" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_31" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_32" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_33" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_34" android:duration="25"/> + <item android:drawable="@drawable/pointer_wait_35" android:duration="25"/> +</animation-list> diff --git a/core/res/res/drawable/pointer_wait_icon.xml b/core/res/res/drawable/pointer_wait_icon.xml new file mode 100644 index 000000000000..d9b03b096093 --- /dev/null +++ b/core/res/res/drawable/pointer_wait_icon.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android" + android:bitmap="@drawable/pointer_wait" + android:hotSpotX="7dp" + android:hotSpotY="7dp" /> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 90fc22b8b3b8..0f817f330284 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -7631,6 +7631,8 @@ i <attr name="pointerIconHand" format="reference"/> <!-- Reference to a pointer drawable with STYLE_HELP --> <attr name="pointerIconHelp" format="reference"/> + <!-- Reference to a pointer drawable with STYLE_WAIT --> + <attr name="pointerIconWait" format="reference"/> <!-- Reference to a pointer drawable with STYLE_CELL --> <attr name="pointerIconCell" format="reference"/> <!-- Reference to a pointer drawable with STYLE_CROSSHAIR --> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index b831df827a8c..eb99077beff6 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -1339,6 +1339,7 @@ please see styles_device_defaults.xml. <item name="pointerIconHand">@drawable/pointer_hand_icon</item> <item name="pointerIconContextMenu">@drawable/pointer_context_menu_icon</item> <item name="pointerIconHelp">@drawable/pointer_help_icon</item> + <item name="pointerIconWait">@drawable/pointer_wait_icon</item> <item name="pointerIconCell">@drawable/pointer_cell_icon</item> <item name="pointerIconCrosshair">@drawable/pointer_crosshair_icon</item> <item name="pointerIconText">@drawable/pointer_text_icon</item> diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java index c31a8b7bf2bf..8c20ddcc33ad 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java @@ -101,20 +101,21 @@ public class AndroidKeyStoreProvider extends Provider { */ public static void install() { Provider[] providers = Security.getProviders(); - int bcProviderPosition = -1; - for (int position = 0; position < providers.length; position++) { - Provider provider = providers[position]; + int bcProviderIndex = -1; + for (int i = 0; i < providers.length; i++) { + Provider provider = providers[i]; if ("BC".equals(provider.getName())) { - bcProviderPosition = position; + bcProviderIndex = i; break; } } Security.addProvider(new AndroidKeyStoreProvider()); Provider workaroundProvider = new AndroidKeyStoreBCWorkaroundProvider(); - if (bcProviderPosition != -1) { + if (bcProviderIndex != -1) { // Bouncy Castle provider found -- install the workaround provider above it. - Security.insertProviderAt(workaroundProvider, bcProviderPosition); + // insertProviderAt uses 1-based positions. + Security.insertProviderAt(workaroundProvider, bcProviderIndex + 1); } else { // Bouncy Castle provider not found -- install the workaround provider at lowest // priority. diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp index 39b7ecb9a914..4cfbb2a43198 100644 --- a/libs/hwui/DeviceInfo.cpp +++ b/libs/hwui/DeviceInfo.cpp @@ -18,6 +18,7 @@ #include "Extensions.h" #include <GLES2/gl2.h> +#include <log/log.h> #include <thread> #include <mutex> @@ -29,6 +30,7 @@ static DeviceInfo* sDeviceInfo = nullptr; static std::once_flag sInitializedFlag; const DeviceInfo* DeviceInfo::get() { + LOG_ALWAYS_FATAL_IF(!sDeviceInfo, "DeviceInfo not yet initialized."); return sDeviceInfo; } diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp index b04f16fe4788..96cac7eedaf0 100644 --- a/libs/hwui/OpReorderer.cpp +++ b/libs/hwui/OpReorderer.cpp @@ -21,10 +21,10 @@ #include "renderstate/OffscreenBufferPool.h" #include "utils/FatVector.h" #include "utils/PaintUtils.h" +#include "utils/TraceUtils.h" #include <SkCanvas.h> #include <SkPathOps.h> -#include <utils/Trace.h> #include <utils/TypeHelpers.h> namespace android { @@ -331,13 +331,15 @@ OpReorderer::OpReorderer(const LayerUpdateQueue& layers, const SkRect& clip, RenderNode* layerNode = layers.entries()[i].renderNode; const Rect& layerDamage = layers.entries()[i].damage; - saveForLayer(layerNode->getWidth(), layerNode->getHeight(), - layerDamage, nullptr, layerNode); - mCanvasState.writableSnapshot()->setClip( - layerDamage.left, layerDamage.top, layerDamage.right, layerDamage.bottom); + // map current light center into RenderNode's coordinate space + Vector3 lightCenter = mCanvasState.currentSnapshot()->getRelativeLightCenter(); + layerNode->getLayer()->inverseTransformInWindow.mapPoint3d(lightCenter); + + saveForLayer(layerNode->getWidth(), layerNode->getHeight(), 0, 0, + layerDamage, lightCenter, nullptr, layerNode); if (layerNode->getDisplayList()) { - deferImpl(*(layerNode->getDisplayList())); + deferDisplayList(*(layerNode->getDisplayList())); } restoreForLayer(); } @@ -363,7 +365,7 @@ OpReorderer::OpReorderer(int viewportWidth, int viewportHeight, const DisplayLis mCanvasState.initializeSaveStack(viewportWidth, viewportHeight, 0, 0, viewportWidth, viewportHeight, lightCenter); - deferImpl(displayList); + deferDisplayList(displayList); } void OpReorderer::onViewportInitialized() {} @@ -371,18 +373,99 @@ void OpReorderer::onViewportInitialized() {} void OpReorderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {} void OpReorderer::deferNodePropsAndOps(RenderNode& node) { - if (node.applyViewProperties(mCanvasState, mAllocator)) { - // not rejected so render + const RenderProperties& properties = node.properties(); + const Outline& outline = properties.getOutline(); + if (properties.getAlpha() <= 0 + || (outline.getShouldClip() && outline.isEmpty()) + || properties.getScaleX() == 0 + || properties.getScaleY() == 0) { + return; // rejected + } + + if (properties.getLeft() != 0 || properties.getTop() != 0) { + mCanvasState.translate(properties.getLeft(), properties.getTop()); + } + if (properties.getStaticMatrix()) { + mCanvasState.concatMatrix(*properties.getStaticMatrix()); + } else if (properties.getAnimationMatrix()) { + mCanvasState.concatMatrix(*properties.getAnimationMatrix()); + } + if (properties.hasTransformMatrix()) { + if (properties.isTransformTranslateOnly()) { + mCanvasState.translate(properties.getTranslationX(), properties.getTranslationY()); + } else { + mCanvasState.concatMatrix(*properties.getTransformMatrix()); + } + } + + const int width = properties.getWidth(); + const int height = properties.getHeight(); + + Rect saveLayerBounds; // will be set to non-empty if saveLayer needed + const bool isLayer = properties.effectiveLayerType() != LayerType::None; + int clipFlags = properties.getClippingFlags(); + if (properties.getAlpha() < 1) { + if (isLayer) { + clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer + } + if (CC_LIKELY(isLayer || !properties.getHasOverlappingRendering())) { + // simply scale rendering content's alpha + mCanvasState.scaleAlpha(properties.getAlpha()); + } else { + // schedule saveLayer by initializing saveLayerBounds + saveLayerBounds.set(0, 0, width, height); + if (clipFlags) { + properties.getClippingRectForFlags(clipFlags, &saveLayerBounds); + clipFlags = 0; // all clipping done by savelayer + } + } + + if (CC_UNLIKELY(ATRACE_ENABLED() && properties.promotedToLayer())) { + // pretend alpha always causes savelayer to warn about + // performance problem affecting old versions + ATRACE_FORMAT("%s alpha caused saveLayer %dx%d", node.getName(), width, height); + } + } + if (clipFlags) { + Rect clipRect; + properties.getClippingRectForFlags(clipFlags, &clipRect); + mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, + SkRegion::kIntersect_Op); + } + + if (properties.getRevealClip().willClip()) { + Rect bounds; + properties.getRevealClip().getBounds(&bounds); + mCanvasState.setClippingRoundRect(mAllocator, + bounds, properties.getRevealClip().getRadius()); + } else if (properties.getOutline().willClip()) { + mCanvasState.setClippingOutline(mAllocator, &(properties.getOutline())); + } + + if (!mCanvasState.quickRejectConservative(0, 0, width, height)) { + // not rejected, so defer render as either Layer, or direct (possibly wrapped in saveLayer) if (node.getLayer()) { // HW layer LayerOp* drawLayerOp = new (mAllocator) LayerOp(node); BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp); if (bakedOpState) { - // Layer will be drawn into parent layer (which is now current, since we popped mLayerStack) + // Node's layer already deferred, schedule it to render into parent layer currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Bitmap); } + } else if (CC_UNLIKELY(!saveLayerBounds.isEmpty())) { + // draw DisplayList contents within temporary, since persisted layer could not be used. + // (temp layers are clipped to viewport, since they don't persist offscreen content) + SkPaint saveLayerPaint; + saveLayerPaint.setAlpha(properties.getAlpha()); + onBeginLayerOp(*new (mAllocator) BeginLayerOp( + saveLayerBounds, + Matrix4::identity(), + saveLayerBounds, + &saveLayerPaint)); + deferDisplayList(*(node.getDisplayList())); + onEndLayerOp(*new (mAllocator) EndLayerOp()); } else { - deferImpl(*(node.getDisplayList())); + deferDisplayList(*(node.getDisplayList())); } } } @@ -535,7 +618,7 @@ void OpReorderer::deferShadow(const RenderNodeOp& casterNodeOp) { */ #define OP_RECEIVER(Type) \ [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.on##Type(static_cast<const Type&>(op)); }, -void OpReorderer::deferImpl(const DisplayList& displayList) { +void OpReorderer::deferDisplayList(const DisplayList& displayList) { static std::function<void(OpReorderer& reorderer, const RecordedOp&)> receivers[] = { MAP_OPS(OP_RECEIVER) }; @@ -600,34 +683,21 @@ void OpReorderer::onSimpleRectsOp(const SimpleRectsOp& op) { currentLayer().deferUnmergeableOp(mAllocator, bakedStateOp, OpBatchType::Vertices); } -void OpReorderer::saveForLayer(uint32_t layerWidth, uint32_t layerHeight, const Rect& repaintRect, +void OpReorderer::saveForLayer(uint32_t layerWidth, uint32_t layerHeight, + float contentTranslateX, float contentTranslateY, + const Rect& repaintRect, + const Vector3& lightCenter, const BeginLayerOp* beginLayerOp, RenderNode* renderNode) { - - auto previous = mCanvasState.currentSnapshot(); mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag); - mCanvasState.writableSnapshot()->transform->loadIdentity(); mCanvasState.writableSnapshot()->initializeViewport(layerWidth, layerHeight); mCanvasState.writableSnapshot()->roundRectClipState = nullptr; - - Vector3 lightCenter = previous->getRelativeLightCenter(); - if (renderNode) { - Matrix4& inverse = renderNode->getLayer()->inverseTransformInWindow; - inverse.mapPoint3d(lightCenter); - } else { - // Combine all transforms used to present saveLayer content: - // parent content transform * canvas transform * bounds offset - Matrix4 contentTransform(*previous->transform); - contentTransform.multiply(beginLayerOp->localMatrix); - contentTransform.translate(beginLayerOp->unmappedBounds.left, beginLayerOp->unmappedBounds.top); - - // inverse the total transform, to map light center into layer-relative space - Matrix4 inverse; - inverse.loadInverse(contentTransform); - inverse.mapPoint3d(lightCenter); - } mCanvasState.writableSnapshot()->setRelativeLightCenter(lightCenter); + mCanvasState.writableSnapshot()->transform->loadTranslate( + contentTranslateX, contentTranslateY, 0); + mCanvasState.writableSnapshot()->setClip( + repaintRect.left, repaintRect.top, repaintRect.right, repaintRect.bottom); - // create a new layer, and push its index on the stack + // create a new layer repaint, and push its index on the stack mLayerStack.push_back(mLayerReorderers.size()); mLayerReorderers.emplace_back(layerWidth, layerHeight, repaintRect, beginLayerOp, renderNode); } @@ -640,9 +710,48 @@ void OpReorderer::restoreForLayer() { // TODO: test rejection at defer time, where the bounds become empty void OpReorderer::onBeginLayerOp(const BeginLayerOp& op) { - const uint32_t layerWidth = (uint32_t) op.unmappedBounds.getWidth(); - const uint32_t layerHeight = (uint32_t) op.unmappedBounds.getHeight(); - saveForLayer(layerWidth, layerHeight, Rect(layerWidth, layerHeight), &op, nullptr); + uint32_t layerWidth = (uint32_t) op.unmappedBounds.getWidth(); + uint32_t layerHeight = (uint32_t) op.unmappedBounds.getHeight(); + + auto previous = mCanvasState.currentSnapshot(); + Vector3 lightCenter = previous->getRelativeLightCenter(); + + // Combine all transforms used to present saveLayer content: + // parent content transform * canvas transform * bounds offset + Matrix4 contentTransform(*previous->transform); + contentTransform.multiply(op.localMatrix); + contentTransform.translate(op.unmappedBounds.left, op.unmappedBounds.top); + + Matrix4 inverseContentTransform; + inverseContentTransform.loadInverse(contentTransform); + + // map the light center into layer-relative space + inverseContentTransform.mapPoint3d(lightCenter); + + // Clip bounds of temporary layer to parent's clip rect, so: + Rect saveLayerBounds(layerWidth, layerHeight); + // 1) transform Rect(width, height) into parent's space + // note: left/top offsets put in contentTransform above + contentTransform.mapRect(saveLayerBounds); + // 2) intersect with parent's clip + saveLayerBounds.doIntersect(previous->getRenderTargetClip()); + // 3) and transform back + inverseContentTransform.mapRect(saveLayerBounds); + saveLayerBounds.doIntersect(Rect(layerWidth, layerHeight)); + saveLayerBounds.roundOut(); + + // if bounds are reduced, will clip the layer's area by reducing required bounds... + layerWidth = saveLayerBounds.getWidth(); + layerHeight = saveLayerBounds.getHeight(); + // ...and shifting drawing content to account for left/top side clipping + float contentTranslateX = -saveLayerBounds.left; + float contentTranslateY = -saveLayerBounds.top; + + saveForLayer(layerWidth, layerHeight, + contentTranslateX, contentTranslateY, + Rect(layerWidth, layerHeight), + lightCenter, + &op, nullptr); } void OpReorderer::onEndLayerOp(const EndLayerOp& /* ignored */) { diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h index 09d5cbcf7559..976f41323efa 100644 --- a/libs/hwui/OpReorderer.h +++ b/libs/hwui/OpReorderer.h @@ -190,7 +190,10 @@ private: Positive }; void saveForLayer(uint32_t layerWidth, uint32_t layerHeight, - const Rect& repaintRect, const BeginLayerOp* beginLayerOp, RenderNode* renderNode); + float contentTranslateX, float contentTranslateY, + const Rect& repaintRect, + const Vector3& lightCenter, + const BeginLayerOp* beginLayerOp, RenderNode* renderNode); void restoreForLayer(); LayerReorderer& currentLayer() { return mLayerReorderers[mLayerStack.back()]; } @@ -204,7 +207,7 @@ private: void deferShadow(const RenderNodeOp& casterOp); - void deferImpl(const DisplayList& displayList); + void deferDisplayList(const DisplayList& displayList); template <typename V> void defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes); diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h index 50199db75640..0736a109e572 100644 --- a/libs/hwui/Rect.h +++ b/libs/hwui/Rect.h @@ -276,7 +276,7 @@ public: } void dump(const char* label = nullptr) const { - ALOGD("%s[l=%f t=%f r=%f b=%f]", label ? label : "Rect", left, top, right, bottom); + ALOGD("%s[l=%.2f t=%.2f r=%.2f b=%.2f]", label ? label : "Rect", left, top, right, bottom); } }; // class Rect diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 2713f46ab33b..716d5360c25c 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -524,76 +524,6 @@ void RenderNode::decParentRefCount() { } } -bool RenderNode::applyViewProperties(CanvasState& canvasState, LinearAllocator& allocator) const { - const Outline& outline = properties().getOutline(); - if (properties().getAlpha() <= 0 - || (outline.getShouldClip() && outline.isEmpty()) - || properties().getScaleX() == 0 - || properties().getScaleY() == 0) { - return false; // rejected - } - - if (properties().getLeft() != 0 || properties().getTop() != 0) { - canvasState.translate(properties().getLeft(), properties().getTop()); - } - if (properties().getStaticMatrix()) { - canvasState.concatMatrix(*properties().getStaticMatrix()); - } else if (properties().getAnimationMatrix()) { - canvasState.concatMatrix(*properties().getAnimationMatrix()); - } - if (properties().hasTransformMatrix()) { - if (properties().isTransformTranslateOnly()) { - canvasState.translate(properties().getTranslationX(), properties().getTranslationY()); - } else { - canvasState.concatMatrix(*properties().getTransformMatrix()); - } - } - - const bool isLayer = properties().effectiveLayerType() != LayerType::None; - int clipFlags = properties().getClippingFlags(); - if (properties().getAlpha() < 1) { - if (isLayer) { - clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer - } - if (CC_LIKELY(isLayer || !properties().getHasOverlappingRendering())) { - // simply scale rendering content's alpha - canvasState.scaleAlpha(properties().getAlpha()); - } else { - // savelayer needed to create an offscreen buffer - Rect layerBounds(0, 0, getWidth(), getHeight()); - if (clipFlags) { - properties().getClippingRectForFlags(clipFlags, &layerBounds); - clipFlags = 0; // all clipping done by savelayer - } - LOG_ALWAYS_FATAL("TODO: savelayer"); - } - - if (CC_UNLIKELY(ATRACE_ENABLED() && properties().promotedToLayer())) { - // pretend alpha always causes savelayer to warn about - // performance problem affecting old versions - ATRACE_FORMAT("%s alpha caused saveLayer %dx%d", getName(), getWidth(), getHeight()); - } - } - if (clipFlags) { - Rect clipRect; - properties().getClippingRectForFlags(clipFlags, &clipRect); - canvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, - SkRegion::kIntersect_Op); - } - - // TODO: support nesting round rect clips - if (mProperties.getRevealClip().willClip()) { - Rect bounds; - mProperties.getRevealClip().getBounds(&bounds); - canvasState.setClippingRoundRect(allocator, - bounds, mProperties.getRevealClip().getRadius()); - } else if (mProperties.getOutline().willClip()) { - canvasState.setClippingOutline(allocator, &(mProperties.getOutline())); - } - return !canvasState.quickRejectConservative( - 0, 0, properties().getWidth(), properties().getHeight()); -} - /* * For property operations, we pass a savecount of 0, since the operations aren't part of the * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index bae5ebe3f754..83d1b5888b64 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -187,9 +187,6 @@ public: AnimatorManager& animators() { return mAnimatorManager; } - // Returns false if the properties dictate the subtree contained in this RenderNode won't render - bool applyViewProperties(CanvasState& canvasState, LinearAllocator& allocator) const; - void applyViewPropertyTransforms(mat4& matrix, bool true3dTransform = false) const; bool nothingToDraw() const { diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h index 0bd5b65f86aa..395279806adb 100644 --- a/libs/hwui/RenderProperties.h +++ b/libs/hwui/RenderProperties.h @@ -610,7 +610,6 @@ public: bool fitsOnLayer() const { const DeviceInfo* deviceInfo = DeviceInfo::get(); - LOG_ALWAYS_FATAL_IF(!deviceInfo, "DeviceInfo uninitialized"); return mPrimitiveFields.mWidth <= deviceInfo->maxTextureSize() && mPrimitiveFields.mHeight <= deviceInfo->maxTextureSize(); } diff --git a/libs/hwui/unit_tests/OpReordererTests.cpp b/libs/hwui/unit_tests/OpReordererTests.cpp index a8c9bba32e64..07a1855490d4 100644 --- a/libs/hwui/unit_tests/OpReordererTests.cpp +++ b/libs/hwui/unit_tests/OpReordererTests.cpp @@ -17,10 +17,10 @@ #include <gtest/gtest.h> #include <BakedOpState.h> +#include <LayerUpdateQueue.h> #include <OpReorderer.h> #include <RecordedOp.h> #include <RecordingCanvas.h> -#include <renderthread/CanvasContext.h> // todo: remove #include <unit_tests/TestUtils.h> #include <unordered_map> @@ -28,8 +28,8 @@ namespace android { namespace uirenderer { -LayerUpdateQueue sEmptyLayerUpdateQueue; -Vector3 sLightCenter = {100, 100, 100}; +const LayerUpdateQueue sEmptyLayerUpdateQueue; +const Vector3 sLightCenter = {100, 100, 100}; static std::vector<sp<RenderNode>> createSyncedNodeList(sp<RenderNode>& node) { TestUtils::syncHierarchyPropertiesAndDisplayList(node); @@ -79,7 +79,7 @@ protected: /** * Dispatches all static methods to similar formed methods on renderer, which fail by default but - * are overriden by subclasses per test. + * are overridden by subclasses per test. */ class TestDispatcher { public: @@ -117,7 +117,6 @@ TEST(OpReorderer, simple) { canvas.drawBitmap(bitmap, 10, 10, nullptr); }); OpReorderer reorderer(100, 200, *dl, sLightCenter); - SimpleTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end @@ -163,7 +162,6 @@ TEST(OpReorderer, simpleBatching) { }); OpReorderer reorderer(200, 200, *dl, sLightCenter); - SimpleBatchingTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(2 * SIMPLE_BATCHING_LOOPS, renderer.getIndex()); // 2 x loops ops, because no merging (TODO: force no merging) @@ -208,7 +206,6 @@ TEST(OpReorderer, renderNode) { OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, createSyncedNodeList(parent), sLightCenter); - RenderNodeTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); } @@ -232,7 +229,6 @@ TEST(OpReorderer, clipped) { OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver 200, 200, createSyncedNodeList(node), sLightCenter); - ClippedTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); } @@ -274,7 +270,6 @@ TEST(OpReorderer, saveLayerSimple) { }); OpReorderer reorderer(200, 200, *dl, sLightCenter); - SaveLayerSimpleTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(4, renderer.getIndex()); @@ -345,7 +340,6 @@ TEST(OpReorderer, saveLayerNested) { }); OpReorderer reorderer(800, 800, *dl, sLightCenter); - SaveLayerNestedTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(10, renderer.getIndex()); @@ -520,7 +514,6 @@ RENDERTHREAD_TEST(OpReorderer, hwLayerComplex) { OpReorderer reorderer(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, syncedList, sLightCenter); - HwLayerComplexTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(13, renderer.getIndex()); @@ -570,7 +563,6 @@ TEST(OpReorderer, zReorder) { }); OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100, createSyncedNodeList(parent), sLightCenter); - ZReorderTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(10, renderer.getIndex()); @@ -616,7 +608,6 @@ TEST(OpReorderer, shadow) { OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, createSyncedNodeList(parent), sLightCenter); - ShadowTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(2, renderer.getIndex()); @@ -658,7 +649,6 @@ TEST(OpReorderer, shadowSaveLayer) { OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, createSyncedNodeList(parent), (Vector3) { 100, 100, 100 }); - ShadowSaveLayerTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(5, renderer.getIndex()); @@ -708,7 +698,6 @@ RENDERTHREAD_TEST(OpReorderer, shadowHwLayer) { layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100)); OpReorderer reorderer(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, syncedList, (Vector3) { 100, 100, 100 }); - ShadowHwLayerTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(5, renderer.getIndex()); @@ -738,13 +727,11 @@ TEST(OpReorderer, shadowLayering) { OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, createSyncedNodeList(parent), sLightCenter); - ShadowLayeringTestRenderer renderer; reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(4, renderer.getIndex()); } - static void testProperty(TestUtils::PropSetupCallback propSetupCallback, std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) { class PropertyTestRenderer : public TestRendererBase { @@ -766,7 +753,6 @@ static void testProperty(TestUtils::PropSetupCallback propSetupCallback, OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200, createSyncedNodeList(node), sLightCenter); - PropertyTestRenderer renderer(opValidateCallback); reorderer.replayBakedOps<TestDispatcher>(renderer); EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op"; @@ -854,5 +840,128 @@ TEST(OpReorderer, renderPropTransform) { }); } +struct SaveLayerAlphaData { + uint32_t layerWidth = 0; + uint32_t layerHeight = 0; + Rect rectClippedBounds; + Matrix4 rectMatrix; +}; +/** + * Constructs a view to hit the temporary layer alpha property implementation: + * a) 0 < alpha < 1 + * b) too big for layer (larger than maxTextureSize) + * c) overlapping rendering content + * returning observed data about layer size and content clip/transform. + * + * Used to validate clipping behavior of temporary layer, where requested layer size is reduced + * (for efficiency, and to fit in layer size constraints) based on parent clip. + */ +void testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData, + TestUtils::PropSetupCallback propSetupCallback) { + class SaveLayerAlphaClipTestRenderer : public TestRendererBase { + public: + SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData) + : mOutData(outData) {} + + OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override { + EXPECT_EQ(0, mIndex++); + mOutData->layerWidth = width; + mOutData->layerHeight = height; + return nullptr; + } + void onRectOp(const RectOp& op, const BakedOpState& state) override { + EXPECT_EQ(1, mIndex++); + + mOutData->rectClippedBounds = state.computedState.clippedBounds; + mOutData->rectMatrix = state.computedState.transform; + } + void endLayer() override { + EXPECT_EQ(2, mIndex++); + } + void onLayerOp(const LayerOp& op, const BakedOpState& state) override { + EXPECT_EQ(3, mIndex++); + } + private: + SaveLayerAlphaData* mOutData; + }; + + ASSERT_GT(10000, DeviceInfo::get()->maxTextureSize()) + << "Node must be bigger than max texture size to exercise saveLayer codepath"; + auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 10000, 10000, [](RecordingCanvas& canvas) { + SkPaint paint; + paint.setColor(SK_ColorWHITE); + canvas.drawRect(0, 0, 10000, 10000, paint); + }, [&propSetupCallback](RenderProperties& properties) { + properties.setHasOverlappingRendering(true); + properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer + + // apply other properties + int flags = propSetupCallback(properties); + return RenderNode::GENERIC | RenderNode::ALPHA | flags; + }); + auto nodes = createSyncedNodeList(node); // sync before querying height + + OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, nodes, sLightCenter); + SaveLayerAlphaClipTestRenderer renderer(outObservedData); + reorderer.replayBakedOps<TestDispatcher>(renderer); + + // assert, since output won't be valid if we haven't seen a save layer triggered + ASSERT_EQ(4, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior."; +} + +TEST(OpReorderer, renderPropSaveLayerAlphaClipBig) { + SaveLayerAlphaData observedData; + testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) { + properties.setTranslationX(10); // offset rendering content + properties.setTranslationY(-2000); // offset rendering content + return RenderNode::TRANSLATION_X | RenderNode::TRANSLATION_Y; + }); + EXPECT_EQ(190u, observedData.layerWidth); + EXPECT_EQ(200u, observedData.layerHeight); + EXPECT_EQ(Rect(0, 0, 190, 200), observedData.rectClippedBounds) + << "expect content to be clipped to screen area"; + Matrix4 expected; + expected.loadTranslate(0, -2000, 0); + EXPECT_MATRIX_APPROX_EQ(expected, observedData.rectMatrix) + << "expect content to be translated as part of being clipped"; +} + +TEST(OpReorderer, renderPropSaveLayerAlphaRotate) { + SaveLayerAlphaData observedData; + testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) { + // Translate and rotate the view so that the only visible part is the top left corner of + // the view. It will form an isoceles right triangle with a long side length of 200 at the + // bottom of the viewport. + properties.setTranslationX(100); + properties.setTranslationY(100); + properties.setPivotX(0); + properties.setPivotY(0); + properties.setRotation(45); + return RenderNode::GENERIC + | RenderNode::TRANSLATION_X | RenderNode::TRANSLATION_Y + | RenderNode::ROTATION; + }); + // ceil(sqrt(2) / 2 * 200) = 142 + EXPECT_EQ(142u, observedData.layerWidth); + EXPECT_EQ(142u, observedData.layerHeight); + EXPECT_EQ(Rect(0, 0, 142, 142), observedData.rectClippedBounds); + EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix); +} + +TEST(OpReorderer, renderPropSaveLayerAlphaScale) { + SaveLayerAlphaData observedData; + testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) { + properties.setPivotX(0); + properties.setPivotY(0); + properties.setScaleX(2); + properties.setScaleY(0.5f); + return RenderNode::GENERIC | RenderNode::SCALE_X | RenderNode::SCALE_Y; + }); + EXPECT_EQ(100u, observedData.layerWidth); + EXPECT_EQ(400u, observedData.layerHeight); + EXPECT_EQ(Rect(0, 0, 100, 400), observedData.rectClippedBounds); + EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix); +} + } // namespace uirenderer } // namespace android diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp index c9586e4ca81d..bd6af788bcf7 100644 --- a/libs/input/PointerController.cpp +++ b/libs/input/PointerController.cpp @@ -86,6 +86,9 @@ PointerController::PointerController(const sp<PointerControllerPolicyInterface>& mLocked.pointerIconChanged = false; mLocked.requestedPointerShape = mPolicy->getDefaultPointerIconId(); + mLocked.animationFrameIndex = 0; + mLocked.lastFrameUpdatedTime = 0; + mLocked.buttonState = 0; loadResources(); @@ -239,7 +242,8 @@ void PointerController::setPresentation(Presentation presentation) { AutoMutex _l(mLock); if (presentation == PRESENTATION_POINTER && mLocked.additionalMouseResources.empty()) { - mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources); + mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources, + &mLocked.animationResources); } if (mLocked.presentation != presentation) { @@ -402,7 +406,7 @@ void PointerController::setDisplayViewport(int32_t width, int32_t height, int32_ updatePointerLocked(); } -void PointerController::updatePointerShape(int iconId) { +void PointerController::updatePointerShape(int32_t iconId) { AutoMutex _l(mLock); if (mLocked.requestedPointerShape != iconId) { mLocked.requestedPointerShape = iconId; @@ -462,8 +466,17 @@ int PointerController::handleEvent(int /* fd */, int events, void* /* data */) { void PointerController::doAnimate(nsecs_t timestamp) { AutoMutex _l(mLock); - bool keepAnimating = false; mLocked.animationPending = false; + + bool keepFading = doFadingAnimationLocked(timestamp); + bool keepBitmapFlipping = doBitmapAnimationLocked(timestamp); + if (keepFading || keepBitmapFlipping) { + startAnimationLocked(); + } +} + +bool PointerController::doFadingAnimationLocked(nsecs_t timestamp) { + bool keepAnimating = false; nsecs_t frameDelay = timestamp - mLocked.animationTime; // Animate pointer fade. @@ -501,10 +514,32 @@ void PointerController::doAnimate(nsecs_t timestamp) { } } } + return keepAnimating; +} + +bool PointerController::doBitmapAnimationLocked(nsecs_t timestamp) { + std::map<int32_t, PointerAnimation>::const_iterator iter = mLocked.animationResources.find( + mLocked.requestedPointerShape); + if (iter == mLocked.animationResources.end()) { + return false; + } - if (keepAnimating) { - startAnimationLocked(); + if (timestamp - mLocked.lastFrameUpdatedTime > iter->second.durationPerFrame) { + mSpriteController->openTransaction(); + + int incr = (timestamp - mLocked.lastFrameUpdatedTime) / iter->second.durationPerFrame; + mLocked.animationFrameIndex += incr; + mLocked.lastFrameUpdatedTime += iter->second.durationPerFrame * incr; + while (mLocked.animationFrameIndex >= iter->second.animationFrames.size()) { + mLocked.animationFrameIndex -= iter->second.animationFrames.size(); + } + mLocked.pointerSprite->setIcon(iter->second.animationFrames[mLocked.animationFrameIndex]); + + mSpriteController->closeTransaction(); } + + // Keep animating. + return true; } void PointerController::doInactivityTimeout() { @@ -549,9 +584,16 @@ void PointerController::updatePointerLocked() { if (mLocked.requestedPointerShape == mPolicy->getDefaultPointerIconId()) { mLocked.pointerSprite->setIcon(mLocked.pointerIcon); } else { - std::map<int, SpriteIcon>::const_iterator iter = + std::map<int32_t, SpriteIcon>::const_iterator iter = mLocked.additionalMouseResources.find(mLocked.requestedPointerShape); if (iter != mLocked.additionalMouseResources.end()) { + std::map<int32_t, PointerAnimation>::const_iterator anim_iter = + mLocked.animationResources.find(mLocked.requestedPointerShape); + if (anim_iter != mLocked.animationResources.end()) { + mLocked.animationFrameIndex = 0; + mLocked.lastFrameUpdatedTime = systemTime(SYSTEM_TIME_MONOTONIC); + startAnimationLocked(); + } mLocked.pointerSprite->setIcon(iter->second); } else { ALOGW("Can't find the resource for icon id %d", mLocked.requestedPointerShape); diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h index 6d840db0ec5c..b6c01d2903a9 100644 --- a/libs/input/PointerController.h +++ b/libs/input/PointerController.h @@ -20,6 +20,7 @@ #include "SpriteController.h" #include <map> +#include <vector> #include <ui/DisplayInfo.h> #include <input/Input.h> @@ -30,8 +31,6 @@ #include <utils/String8.h> #include <gui/DisplayEventReceiver.h> -#include <SkBitmap.h> - namespace android { /* @@ -43,6 +42,11 @@ struct PointerResources { SpriteIcon spotAnchor; }; +struct PointerAnimation { + std::vector<SpriteIcon> animationFrames; + nsecs_t durationPerFrame; +}; + /* * Pointer controller policy interface. * @@ -59,7 +63,8 @@ protected: public: virtual void loadPointerResources(PointerResources* outResources) = 0; - virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources) = 0; + virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources, + std::map<int32_t, PointerAnimation>* outAnimationResources) = 0; virtual int32_t getDefaultPointerIconId() = 0; }; @@ -98,7 +103,7 @@ public: const uint32_t* spotIdToIndex, BitSet32 spotIdBits); virtual void clearSpots(); - void updatePointerShape(int iconId); + void updatePointerShape(int32_t iconId); void setDisplayViewport(int32_t width, int32_t height, int32_t orientation); void setPointerIcon(const SpriteIcon& icon); void setInactivityTimeout(InactivityTimeout inactivityTimeout); @@ -145,6 +150,9 @@ private: bool animationPending; nsecs_t animationTime; + size_t animationFrameIndex; + nsecs_t lastFrameUpdatedTime; + int32_t displayWidth; int32_t displayHeight; int32_t displayOrientation; @@ -162,7 +170,8 @@ private: SpriteIcon pointerIcon; bool pointerIconChanged; - std::map<int, SpriteIcon> additionalMouseResources; + std::map<int32_t, SpriteIcon> additionalMouseResources; + std::map<int32_t, PointerAnimation> animationResources; int32_t requestedPointerShape; @@ -178,6 +187,8 @@ private: void handleMessage(const Message& message); int handleEvent(int fd, int events, void* data); void doAnimate(nsecs_t timestamp); + bool doFadingAnimationLocked(nsecs_t timestamp); + bool doBitmapAnimationLocked(nsecs_t timestamp); void doInactivityTimeout(); void startAnimationLocked(); diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java index 6bf5721d55c3..445ee6f91508 100644 --- a/media/java/android/media/ExifInterface.java +++ b/media/java/android/media/ExifInterface.java @@ -17,6 +17,8 @@ package android.media; import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.Date; @@ -128,6 +130,9 @@ public class ExifInterface { // use sLock to serialize the accesses. private static final Object sLock = new Object(); + // Pattern to check non zero timestamp + private static final Pattern sNonZeroTimePattern = Pattern.compile(".*[1-9].*"); + /** * Reads Exif tags from the specified JPEG file. */ @@ -367,7 +372,8 @@ public class ExifInterface { */ public long getDateTime() { String dateTimeString = mAttributes.get(TAG_DATETIME); - if (dateTimeString == null) return -1; + if (dateTimeString == null + || !sNonZeroTimePattern.matcher(dateTimeString).matches()) return -1; ParsePosition pos = new ParsePosition(0); try { @@ -402,7 +408,9 @@ public class ExifInterface { public long getGpsDateTime() { String date = mAttributes.get(TAG_GPS_DATESTAMP); String time = mAttributes.get(TAG_GPS_TIMESTAMP); - if (date == null || time == null) return -1; + if (date == null || time == null + || (!sNonZeroTimePattern.matcher(date).matches() + && !sNonZeroTimePattern.matcher(time).matches())) return -1; String dateTimeString = date + ' ' + time; diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index d5f9557ea56a..00b10a1191f9 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1067,6 +1067,9 @@ <!-- Name of status bar --> <string name="status_bar">Status bar</string> + <!-- Name of overview --> + <string name="overview">Overview</string> + <!-- Name of demo mode (mode with preset icons for screenshots) --> <string name="demo_mode">Demo mode</string> @@ -1156,6 +1159,11 @@ <!-- Option to use new paging layout in quick settings [CHAR LIMIT=60] --> <string name="qs_paging" translatable="false">Use the new Quick Settings</string> + <!-- Toggles fast-toggling recents via the recents button --> + <string name="overview_fast_toggle_via_button">Enable fast toggle</string> + <!-- Description for the toggle for fast-toggling recents via the recents button --> + <string name="overview_fast_toggle_via_button_desc">Enable paging via the Overview button</string> + <!-- Category in the System UI Tuner settings, where new/experimental settings are --> <string name="experimental">Experimental</string> diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml index 59801089d1bd..c36cab8c3c5a 100644 --- a/packages/SystemUI/res/xml/tuner_prefs.xml +++ b/packages/SystemUI/res/xml/tuner_prefs.xml @@ -87,6 +87,17 @@ </PreferenceScreen> + + <PreferenceScreen + android:title="@string/overview" > + + <com.android.systemui.tuner.TunerSwitch + android:key="overview_fast_toggle" + android:title="@string/overview_fast_toggle_via_button" + android:summary="@string/overview_fast_toggle_via_button_desc" /> + + </PreferenceScreen> + <SwitchPreference android:key="battery_pct" android:title="@string/show_battery_percentage" diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java index 3657cf27a6a9..9d9877237a04 100644 --- a/packages/SystemUI/src/com/android/systemui/Prefs.java +++ b/packages/SystemUI/src/com/android/systemui/Prefs.java @@ -30,7 +30,8 @@ public final class Prefs { @Retention(RetentionPolicy.SOURCE) @StringDef({ - Key.SEARCH_APP_WIDGET_ID, + Key.OVERVIEW_SEARCH_APP_WIDGET_ID, + Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, Key.DEBUG_MODE_ENABLED, Key.HOTSPOT_TILE_LAST_USED, Key.COLOR_INVERSION_TILE_LAST_USED, @@ -43,8 +44,8 @@ public final class Prefs { Key.DND_FAVORITE_ZEN, }) public @interface Key { - String SEARCH_APP_WIDGET_ID = "searchAppWidgetId"; - String SEARCH_APP_WIDGET_PACKAGE = "searchAppWidgetPackage"; + String OVERVIEW_SEARCH_APP_WIDGET_ID = "searchAppWidgetId"; + String OVERVIEW_SEARCH_APP_WIDGET_PACKAGE = "searchAppWidgetPackage"; String DEBUG_MODE_ENABLED = "debugModeEnabled"; String HOTSPOT_TILE_LAST_USED = "HotspotTileLastUsed"; String COLOR_INVERSION_TILE_LAST_USED = "ColorInversionTileLastUsed"; diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java index a429447e18e7..c08fb0522b9b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java @@ -29,34 +29,4 @@ public class Constants { public static final int DismissSourceHeaderButton = 2; } - // TODO: Move into RecentsDebugFlags - public static class DebugFlags { - - public static class App { - // Enables debug drawing for the transition thumbnail - public static final boolean EnableTransitionThumbnailDebugMode = false; - // Enables the filtering of tasks according to their grouping - public static final boolean EnableTaskFiltering = false; - // Enables dismiss-all - public static final boolean EnableDismissAll = false; - // Enables fast-toggling by just tapping on the recents button - public static final boolean EnableFastToggleRecents = false; - // Enables the thumbnail alpha on the front-most task - public static final boolean EnableThumbnailAlphaOnFrontmost = false; - // This disables the search bar integration - public static final boolean DisableSearchBar = true; - // This disables the bitmap and icon caches - public static final boolean DisableBackgroundCache = false; - // Enables the simulated task affiliations - public static final boolean EnableSimulatedTaskGroups = false; - // Defines the number of mock task affiliations per group - public static final int TaskAffiliationsGroupCount = 12; - // Enables us to create mock recents tasks - public static final boolean EnableSystemServicesProxy = false; - // Defines the number of mock recents packages to create - public static final int SystemServicesProxyMockPackageCount = 3; - // Defines the number of mock recents tasks to create - public static final int SystemServicesProxyMockTaskCount = 100; - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java index 95f1eb22255e..3806b4682e7a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java @@ -62,6 +62,7 @@ public class Recents extends SystemUI private final static String ACTION_TOGGLE_RECENTS = "com.android.systemui.recents.ACTION_TOGGLE"; private static SystemServicesProxy sSystemServicesProxy; + private static RecentsDebugFlags sDebugFlags; private static RecentsTaskLoader sTaskLoader; private static RecentsConfiguration sConfiguration; @@ -148,8 +149,13 @@ public class Recents extends SystemUI return sConfiguration; } + public static RecentsDebugFlags getDebugFlags() { + return sDebugFlags; + } + @Override public void start() { + sDebugFlags = new RecentsDebugFlags(mContext); sSystemServicesProxy = new SystemServicesProxy(mContext); sTaskLoader = new RecentsTaskLoader(mContext); sConfiguration = new RecentsConfiguration(mContext); @@ -166,6 +172,7 @@ public class Recents extends SystemUI // Register with the event bus EventBus.getDefault().register(this, EVENT_BUS_PRIORITY); + EventBus.getDefault().register(sSystemServicesProxy, EVENT_BUS_PRIORITY); EventBus.getDefault().register(sTaskLoader, EVENT_BUS_PRIORITY); // Due to the fact that RecentsActivity is per-user, we need to establish and interface for diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index 1e46e6f54245..b4bb392f930f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -45,6 +45,7 @@ import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEven import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent; import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent; import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent; +import com.android.systemui.recents.events.activity.DebugFlagsChangedEvent; import com.android.systemui.recents.events.activity.HideRecentsEvent; import com.android.systemui.recents.events.activity.IterateRecentsEvent; import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent; @@ -217,14 +218,14 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView mEmptyView = mEmptyViewStub.inflate(); } mEmptyView.setVisibility(View.VISIBLE); - if (!Constants.DebugFlags.App.DisableSearchBar) { + if (!RecentsDebugFlags.Static.DisableSearchBar) { mRecentsView.setSearchBarVisibility(View.GONE); } } else { if (mEmptyView != null) { mEmptyView.setVisibility(View.GONE); } - if (!Constants.DebugFlags.App.DisableSearchBar) { + if (!RecentsDebugFlags.Static.DisableSearchBar) { if (mRecentsView.hasValidSearchBar()) { mRecentsView.setSearchBarVisibility(View.VISIBLE); } else { @@ -338,7 +339,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView EventBus.getDefault().register(this, EVENT_BUS_PRIORITY); // Initialize the widget host (the host id is static and does not change) - if (!Constants.DebugFlags.App.DisableSearchBar) { + if (!RecentsDebugFlags.Static.DisableSearchBar) { mAppWidgetHost = new RecentsAppWidgetHost(this, RecentsAppWidgetHost.HOST_ID); } mPackageMonitor = new RecentsPackageMonitor(); @@ -364,14 +365,14 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent); // Bind the search app widget when we first start up - if (!Constants.DebugFlags.App.DisableSearchBar) { + if (!RecentsDebugFlags.Static.DisableSearchBar) { mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost); } // Register the broadcast receiver to handle messages when the screen is turned off IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_OFF); - if (!Constants.DebugFlags.App.DisableSearchBar) { + if (!RecentsDebugFlags.Static.DisableSearchBar) { filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED); } registerReceiver(mSystemBroadcastReceiver, filter); @@ -433,12 +434,8 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView protected void onPause() { super.onPause(); - if (Constants.DebugFlags.App.EnableFastToggleRecents) { - // Stop the fast-toggle dozer - mIterateTrigger.stopDozing(); - } - - if (Constants.DebugFlags.App.EnableFastToggleRecents) { + RecentsDebugFlags flags = Recents.getDebugFlags(); + if (flags.isFastToggleRecentsEnabled()) { // Stop the fast-toggle dozer mIterateTrigger.stopDozing(); } @@ -483,7 +480,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView mPackageMonitor.unregister(); // Stop listening for widget package changes if there was one bound - if (!Constants.DebugFlags.App.DisableSearchBar) { + if (!RecentsDebugFlags.Static.DisableSearchBar) { mAppWidgetHost.stopListening(); } @@ -617,7 +614,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView ViewAnimation.TaskViewEnterContext ctx = new ViewAnimation.TaskViewEnterContext(t); ctx.postAnimationTrigger.increment(); if (mSearchWidgetInfo != null) { - if (!Constants.DebugFlags.App.DisableSearchBar) { + if (!RecentsDebugFlags.Static.DisableSearchBar) { ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() { @Override public void run() { @@ -636,8 +633,8 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // the dozer now RecentsConfiguration config = Recents.getConfiguration(); RecentsActivityLaunchState launchState = config.getLaunchState(); - if (Constants.DebugFlags.App.EnableFastToggleRecents && - !launchState.launchedWithAltTab) { + RecentsDebugFlags flags = Recents.getDebugFlags(); + if (flags.isFastToggleRecentsEnabled() && !launchState.launchedWithAltTab) { mIterateTrigger.startDozing(); } } @@ -725,6 +722,11 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView MetricsLogger.count(this, "overview_screen_pinned", 1); } + public final void onBusEvent(DebugFlagsChangedEvent event) { + // Just finish recents so that we can reload the flags anew on the next instantiation + finish(); + } + private void refreshSearchWidgetView() { if (mSearchWidgetInfo != null) { SystemServicesProxy ssp = Recents.getSystemServices(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java index 01ffd2a5afdc..7f7dbce0abfd 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java @@ -74,7 +74,8 @@ public class RecentsActivityLaunchState { * Returns the task to focus given the current launch state. */ public int getInitialFocusTaskIndex(int numTasks) { - if (Constants.DebugFlags.App.EnableFastToggleRecents && !launchedWithAltTab) { + RecentsDebugFlags flags = Recents.getDebugFlags(); + if (flags.isFastToggleRecentsEnabled() && !launchedWithAltTab) { // If we are fast toggling, then focus the next task depending on when you are on home // or coming in from another app if (launchedFromHome) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java index a73f3234ed44..8f952beb5038 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -154,7 +154,7 @@ public class RecentsConfiguration { int swInset = getInsetToSmallestWidth(windowBounds.right - windowBounds.left); int top = searchBarBounds.isEmpty() ? topInset : 0; taskStackBounds.set(windowBounds.left + swInset, searchBarBounds.bottom + top, - windowBounds.right - swInset, windowBounds.bottom); + windowBounds.right - swInset - rightInset, windowBounds.bottom); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java new file mode 100644 index 000000000000..6c74a4e9200d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.recents; + +import android.content.Context; +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.events.activity.DebugFlagsChangedEvent; +import com.android.systemui.tuner.TunerService; + +/** + * Tunable debug flags + */ +public class RecentsDebugFlags implements TunerService.Tunable { + + private static final String KEY_FAST_TOGGLE = "overview_fast_toggle"; + + public static class Static { + // Enables debug drawing for the transition thumbnail + public static final boolean EnableTransitionThumbnailDebugMode = false; + // This disables the search bar integration + public static final boolean DisableSearchBar = true; + // This disables the bitmap and icon caches + public static final boolean DisableBackgroundCache = false; + // Enables the simulated task affiliations + public static final boolean EnableSimulatedTaskGroups = false; + // Defines the number of mock task affiliations per group + public static final int TaskAffiliationsGroupCount = 12; + // Enables us to create mock recents tasks + public static final boolean EnableSystemServicesProxy = false; + // Defines the number of mock recents packages to create + public static final int SystemServicesProxyMockPackageCount = 3; + // Defines the number of mock recents tasks to create + public static final int SystemServicesProxyMockTaskCount = 100; + } + + private boolean mForceEnableFreeformWorkspace; + private boolean mEnableFastToggleRecents; + + /** + * We read the prefs once when we start the activity, then update them as the tuner changes + * the flags. + */ + public RecentsDebugFlags(Context context) { + // Register all our flags, this will also call onTuningChanged() for each key, which will + // initialize the current state of each flag + TunerService.get(context).addTunable(this, KEY_FAST_TOGGLE); + } + + /** + * @return whether we are enabling fast toggling. + */ + public boolean isFastToggleRecentsEnabled() { + return mEnableFastToggleRecents; + } + + @Override + public void onTuningChanged(String key, String newValue) { + switch (key) { + case KEY_FAST_TOGGLE: + mEnableFastToggleRecents = (newValue != null) && + (Integer.parseInt(newValue) != 0); + break; + } + EventBus.getDefault().send(new DebugFlagsChangedEvent()); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index b491f943734d..85a2edab6437 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -324,8 +324,8 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements if (topTask != null && ssp.isRecentsTopMost(topTask, isTopTaskHome)) { RecentsConfiguration config = Recents.getConfiguration(); RecentsActivityLaunchState launchState = config.getLaunchState(); - if (Constants.DebugFlags.App.EnableFastToggleRecents && - !launchState.launchedWithAltTab) { + RecentsDebugFlags flags = Recents.getDebugFlags(); + if (flags.isFastToggleRecentsEnabled() && !launchState.launchedWithAltTab) { // Notify recents to move onto the next task EventBus.getDefault().post(new IterateRecentsEvent()); } else { @@ -555,7 +555,7 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements // Update the configuration for the current state config.update(mContext, ssp, ssp.getWindowRect()); - if (!Constants.DebugFlags.App.DisableSearchBar && tryAndBindSearchWidget) { + if (!RecentsDebugFlags.Static.DisableSearchBar && tryAndBindSearchWidget) { // Try and pre-emptively bind the search widget on startup to ensure that we // have the right thumbnail bounds to animate to. // Note: We have to reload the widget id before we get the task stack bounds below @@ -758,7 +758,7 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements int toHeaderHeight = (int) (mHeaderBar.getMeasuredHeight() * toTransform.scale); thumbnail = Bitmap.createBitmap(toHeaderWidth, toHeaderHeight, Bitmap.Config.ARGB_8888); - if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) { + if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) { thumbnail.eraseColor(0xFFff0000); } else { Canvas c = new Canvas(thumbnail); @@ -816,11 +816,11 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements if (!useThumbnailTransition) { // If there is no thumbnail transition, but is launching from home into recents, then // use a quick home transition and do the animation from home - if (!Constants.DebugFlags.App.DisableSearchBar && hasRecentTasks) { + if (!RecentsDebugFlags.Static.DisableSearchBar && hasRecentTasks) { SystemServicesProxy ssp = Recents.getSystemServices(); String homeActivityPackage = ssp.getHomeActivityPackageName(); String searchWidgetPackage = Prefs.getString(mContext, - Prefs.Key.SEARCH_APP_WIDGET_PACKAGE, null); + Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, null); // Determine whether we are coming from a search owned home activity boolean fromSearchHome = (homeActivityPackage != null) && diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DebugFlagsChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DebugFlagsChangedEvent.java new file mode 100644 index 000000000000..fe3bf26334b9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DebugFlagsChangedEvent.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.recents.events.activity; + +import com.android.systemui.recents.events.EventBus; + +/** + * This is sent when the SystemUI tuner changes a flag. + */ +public class DebugFlagsChangedEvent extends EventBus.Event { + // Simple event +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 0432ac99de2f..16d692921da4 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -63,7 +63,8 @@ import com.android.internal.app.AssistUtils; import com.android.internal.os.BackgroundThread; import com.android.systemui.Prefs; import com.android.systemui.R; -import com.android.systemui.recents.Constants; +import com.android.systemui.recents.Recents; +import com.android.systemui.recents.RecentsDebugFlags; import com.android.systemui.recents.RecentsImpl; import java.io.IOException; @@ -113,6 +114,7 @@ public class SystemServicesProxy { /** Private constructor */ public SystemServicesProxy(Context context) { + RecentsDebugFlags flags = Recents.getDebugFlags(); mAccm = AccessibilityManager.getInstance(context); mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); mIam = ActivityManagerNative.getDefault(); @@ -124,8 +126,8 @@ public class SystemServicesProxy { mUm = UserManager.get(context); mDisplay = mWm.getDefaultDisplay(); mRecentsPackage = context.getPackageName(); - mHasFreeformWorkspaceSupport = false && mPm.hasSystemFeature( - PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT); + mHasFreeformWorkspaceSupport = false && + mPm.hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT); // Get the dummy thumbnail width/heights Resources res = context.getResources(); @@ -143,7 +145,7 @@ public class SystemServicesProxy { // Resolve the assist intent mAssistComponent = mAssistUtils.getAssistComponentForUser(UserHandle.myUserId()); - if (Constants.DebugFlags.App.EnableSystemServicesProxy) { + if (RecentsDebugFlags.Static.EnableSystemServicesProxy) { // Create a dummy icon mDummyIcon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); mDummyIcon.eraseColor(0xFF999999); @@ -156,13 +158,13 @@ public class SystemServicesProxy { if (mAm == null) return null; // If we are mocking, then create some recent tasks - if (Constants.DebugFlags.App.EnableSystemServicesProxy) { + if (RecentsDebugFlags.Static.EnableSystemServicesProxy) { ArrayList<ActivityManager.RecentTaskInfo> tasks = new ArrayList<ActivityManager.RecentTaskInfo>(); - int count = Math.min(numLatestTasks, Constants.DebugFlags.App.SystemServicesProxyMockTaskCount); + int count = Math.min(numLatestTasks, RecentsDebugFlags.Static.SystemServicesProxyMockTaskCount); for (int i = 0; i < count; i++) { // Create a dummy component name - int packageIndex = i % Constants.DebugFlags.App.SystemServicesProxyMockPackageCount; + int packageIndex = i % RecentsDebugFlags.Static.SystemServicesProxyMockPackageCount; ComponentName cn = new ComponentName("com.android.test" + packageIndex, "com.android.test" + i + ".Activity"); String description = "" + i + " - " + @@ -381,7 +383,7 @@ public class SystemServicesProxy { if (mAm == null) return null; // If we are mocking, then just return a dummy thumbnail - if (Constants.DebugFlags.App.EnableSystemServicesProxy) { + if (RecentsDebugFlags.Static.EnableSystemServicesProxy) { Bitmap thumbnail = Bitmap.createBitmap(mDummyThumbnailWidth, mDummyThumbnailHeight, Bitmap.Config.ARGB_8888); thumbnail.eraseColor(0xff333333); @@ -443,7 +445,7 @@ public class SystemServicesProxy { /** Moves a task to the front with the specified activity options. */ public void moveTaskToFront(int taskId, ActivityOptions opts) { if (mAm == null) return; - if (Constants.DebugFlags.App.EnableSystemServicesProxy) return; + if (RecentsDebugFlags.Static.EnableSystemServicesProxy) return; if (opts != null) { mAm.moveTaskToFront(taskId, ActivityManager.MOVE_TASK_WITH_HOME, @@ -456,7 +458,7 @@ public class SystemServicesProxy { /** Removes the task */ public void removeTask(final int taskId) { if (mAm == null) return; - if (Constants.DebugFlags.App.EnableSystemServicesProxy) return; + if (RecentsDebugFlags.Static.EnableSystemServicesProxy) return; // Remove the task. BackgroundThread.getHandler().post(new Runnable() { @@ -475,7 +477,7 @@ public class SystemServicesProxy { */ public ActivityInfo getActivityInfo(ComponentName cn, int userId) { if (mIpm == null) return null; - if (Constants.DebugFlags.App.EnableSystemServicesProxy) return new ActivityInfo(); + if (RecentsDebugFlags.Static.EnableSystemServicesProxy) return new ActivityInfo(); try { return mIpm.getActivityInfo(cn, PackageManager.GET_META_DATA, userId); @@ -492,7 +494,7 @@ public class SystemServicesProxy { */ public ActivityInfo getActivityInfo(ComponentName cn) { if (mPm == null) return null; - if (Constants.DebugFlags.App.EnableSystemServicesProxy) return new ActivityInfo(); + if (RecentsDebugFlags.Static.EnableSystemServicesProxy) return new ActivityInfo(); try { return mPm.getActivityInfo(cn, PackageManager.GET_META_DATA); @@ -507,7 +509,7 @@ public class SystemServicesProxy { if (mPm == null) return null; // If we are mocking, then return a mock label - if (Constants.DebugFlags.App.EnableSystemServicesProxy) { + if (RecentsDebugFlags.Static.EnableSystemServicesProxy) { return "Recent Task"; } @@ -519,7 +521,7 @@ public class SystemServicesProxy { if (mPm == null) return null; // If we are mocking, then return a mock label - if (Constants.DebugFlags.App.EnableSystemServicesProxy) { + if (RecentsDebugFlags.Static.EnableSystemServicesProxy) { return "Recent Task"; } @@ -549,7 +551,7 @@ public class SystemServicesProxy { if (mPm == null) return null; // If we are mocking, then return a mock label - if (Constants.DebugFlags.App.EnableSystemServicesProxy) { + if (RecentsDebugFlags.Static.EnableSystemServicesProxy) { return new ColorDrawable(0xFF666666); } @@ -580,7 +582,7 @@ public class SystemServicesProxy { /** Returns the package name of the home activity. */ public String getHomeActivityPackageName() { if (mPm == null) return null; - if (Constants.DebugFlags.App.EnableSystemServicesProxy) return null; + if (RecentsDebugFlags.Static.EnableSystemServicesProxy) return null; ArrayList<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>(); ComponentName defaultHomeActivity = mPm.getHomeActivities(homeActivities); @@ -623,22 +625,22 @@ public class SystemServicesProxy { * Returns the current search widget id. */ public int getSearchAppWidgetId(Context context) { - return Prefs.getInt(context, Prefs.Key.SEARCH_APP_WIDGET_ID, -1); + return Prefs.getInt(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_ID, -1); } /** * Returns the current search widget info, binding a new one if necessary. */ public AppWidgetProviderInfo getOrBindSearchAppWidget(Context context, AppWidgetHost host) { - int searchWidgetId = Prefs.getInt(context, Prefs.Key.SEARCH_APP_WIDGET_ID, -1); + int searchWidgetId = Prefs.getInt(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_ID, -1); AppWidgetProviderInfo searchWidgetInfo = mAwm.getAppWidgetInfo(searchWidgetId); AppWidgetProviderInfo resolvedSearchWidgetInfo = resolveSearchAppWidget(); // Return the search widget info if it hasn't changed if (searchWidgetInfo != null && resolvedSearchWidgetInfo != null && searchWidgetInfo.provider.equals(resolvedSearchWidgetInfo.provider)) { - if (Prefs.getString(context, Prefs.Key.SEARCH_APP_WIDGET_PACKAGE, null) == null) { - Prefs.putString(context, Prefs.Key.SEARCH_APP_WIDGET_PACKAGE, + if (Prefs.getString(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, null) == null) { + Prefs.putString(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, searchWidgetInfo.provider.getPackageName()); } return searchWidgetInfo; @@ -654,16 +656,16 @@ public class SystemServicesProxy { Pair<Integer, AppWidgetProviderInfo> widgetInfo = bindSearchAppWidget(host, resolvedSearchWidgetInfo); if (widgetInfo != null) { - Prefs.putInt(context, Prefs.Key.SEARCH_APP_WIDGET_ID, widgetInfo.first); - Prefs.putString(context, Prefs.Key.SEARCH_APP_WIDGET_PACKAGE, + Prefs.putInt(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_ID, widgetInfo.first); + Prefs.putString(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, widgetInfo.second.provider.getPackageName()); return widgetInfo.second; } } // If we fall through here, then there is no resolved search widget, so clear the state - Prefs.remove(context, Prefs.Key.SEARCH_APP_WIDGET_ID); - Prefs.remove(context, Prefs.Key.SEARCH_APP_WIDGET_PACKAGE); + Prefs.remove(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_ID); + Prefs.remove(context, Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE); return null; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java index bba453a09172..fe67fd94fff9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java @@ -30,9 +30,9 @@ import android.os.HandlerThread; import android.util.Log; import android.util.LruCache; import com.android.systemui.R; -import com.android.systemui.recents.Constants; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsConfiguration; +import com.android.systemui.recents.RecentsDebugFlags; import com.android.systemui.recents.events.activity.PackagesChangedEvent; import com.android.systemui.recents.misc.SystemServicesProxy; @@ -283,9 +283,9 @@ public class RecentsTaskLoader { res.getColor(R.color.recents_task_bar_default_background_color); mMaxThumbnailCacheSize = res.getInteger(R.integer.config_recents_max_thumbnail_count); mMaxIconCacheSize = res.getInteger(R.integer.config_recents_max_icon_count); - int iconCacheSize = Constants.DebugFlags.App.DisableBackgroundCache ? 1 : + int iconCacheSize = RecentsDebugFlags.Static.DisableBackgroundCache ? 1 : mMaxIconCacheSize; - int thumbnailCacheSize = Constants.DebugFlags.App.DisableBackgroundCache ? 1 : + int thumbnailCacheSize = RecentsDebugFlags.Static.DisableBackgroundCache ? 1 : mMaxThumbnailCacheSize; // Create the default assets diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java index 6734012c4e3d..f26dcdea1dfd 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java @@ -24,8 +24,8 @@ import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.ColorDrawable; import com.android.systemui.R; -import com.android.systemui.recents.Constants; import com.android.systemui.recents.Recents; +import com.android.systemui.recents.RecentsDebugFlags; import com.android.systemui.recents.misc.NamedCounter; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.misc.Utilities; @@ -543,7 +543,7 @@ public class TaskStack { * Temporary: This method will simulate affiliation groups by */ public void createAffiliatedGroupings(Context context) { - if (Constants.DebugFlags.App.EnableSimulatedTaskGroups) { + if (RecentsDebugFlags.Static.EnableSimulatedTaskGroups) { HashMap<Task.TaskKey, Task> taskMap = new HashMap<Task.TaskKey, Task>(); // Sort all tasks by increasing firstActiveTime of the task ArrayList<Task> tasks = mTaskList.getTasks(); @@ -559,7 +559,7 @@ public class TaskStack { String prevPackage = ""; int prevAffiliation = -1; Random r = new Random(); - int groupCountDown = Constants.DebugFlags.App.TaskAffiliationsGroupCount; + int groupCountDown = RecentsDebugFlags.Static.TaskAffiliationsGroupCount; for (int i = 0; i < taskCount; i++) { Task t = tasks.get(i); String packageName = t.key.getComponent().getPackageName(); @@ -574,7 +574,7 @@ public class TaskStack { addGroup(group); prevAffiliation = affiliation; prevPackage = packageName; - groupCountDown = Constants.DebugFlags.App.TaskAffiliationsGroupCount; + groupCountDown = RecentsDebugFlags.Static.TaskAffiliationsGroupCount; } group.addTask(t); taskMap.put(t.key, t); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java index b2f716d2add5..4ecb80a22f36 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java @@ -34,6 +34,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.systemui.recents.Constants; import com.android.systemui.recents.ExitRecentsWindowFirstAnimationFrameEvent; import com.android.systemui.recents.Recents; +import com.android.systemui.recents.RecentsDebugFlags; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent; import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent; @@ -319,7 +320,7 @@ public class RecentsTransitionHelper { b = Bitmap.createBitmap(fromHeaderWidth, fromHeaderHeight, Bitmap.Config.ARGB_8888); - if (Constants.DebugFlags.App.EnableTransitionThumbnailDebugMode) { + if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) { b.eraseColor(0xFFff0000); } else { Canvas c = new Canvas(b); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java index 51091c38eec0..b3bd6edc84dd 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java @@ -201,7 +201,7 @@ public class TaskStackLayoutAlgorithm { taskStackBounds.right - widthPadding, taskStackBounds.bottom); // Anchor the task rect to the top-center of the non-freeform stack rect - int size = Math.min(mStackRect.width(), mStackRect.height() - mStackBottomOffset); + int size = mStackRect.width(); mTaskRect.set(mStackRect.left, mStackRect.top, mStackRect.left + size, mStackRect.top + size); mCurrentStackRect = ssp.hasFreeformWorkspaceSupport() ? mFreeformStackRect : mStackRect; 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 a57ac9dd570f..7250d6abaede 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -114,6 +114,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal HashMap<Task, TaskView> mTmpTaskViewMap = new HashMap<>(); ArrayList<TaskView> mTaskViews = new ArrayList<>(); List<TaskView> mImmutableTaskViews = new ArrayList<>(); + List<TaskView> mTmpTaskViews = new ArrayList<>(); LayoutInflater mInflater; boolean mLayersDisabled; boolean mTouchExplorationEnabled; @@ -279,14 +280,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } // Mark each task view for relayout - if (mViewPool != null) { - Iterator<TaskView> iter = mViewPool.poolViewIterator(); - if (iter != null) { - while (iter.hasNext()) { - TaskView tv = iter.next(); - tv.reset(); - } - } + List<TaskView> poolViews = mViewPool.getViews(); + for (TaskView tv : poolViews) { + tv.reset(); } // Reset the stack state @@ -862,10 +858,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } // Measure each of the TaskViews - List<TaskView> taskViews = getTaskViews(); - int taskViewCount = taskViews.size(); + mTmpTaskViews.clear(); + mTmpTaskViews.addAll(getTaskViews()); + mTmpTaskViews.addAll(mViewPool.getViews()); + int taskViewCount = mTmpTaskViews.size(); for (int i = 0; i < taskViewCount; i++) { - TaskView tv = taskViews.get(i); + TaskView tv = mTmpTaskViews.get(i); if (tv.getBackground() != null) { tv.getBackground().getPadding(mTmpRect); } else { @@ -891,10 +889,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { // Layout each of the TaskViews - List<TaskView> taskViews = getTaskViews(); - int taskViewCount = taskViews.size(); + mTmpTaskViews.clear(); + mTmpTaskViews.addAll(getTaskViews()); + mTmpTaskViews.addAll(mViewPool.getViews()); + int taskViewCount = mTmpTaskViews.size(); for (int i = 0; i < taskViewCount; i++) { - TaskView tv = taskViews.get(i); + TaskView tv = mTmpTaskViews.get(i); if (tv.getBackground() != null) { tv.getBackground().getPadding(mTmpRect); } else { @@ -911,6 +911,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } if (changed) { + if (mStackScroller.isScrollOutOfBounds()) { + mStackScroller.boundScroll(); + } requestSynchronizeStackViewsWithModel(); synchronizeStackViewsWithModel(); clipTaskViews(true /* forceUpdate */); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index cb7465d12918..2c8f3168f272 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -45,6 +45,7 @@ import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsActivity; import com.android.systemui.recents.RecentsActivityLaunchState; import com.android.systemui.recents.RecentsConfiguration; +import com.android.systemui.recents.RecentsDebugFlags; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.ui.DismissTaskViewEvent; import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; @@ -324,22 +325,9 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, if (launchState.launchedFromAppWithThumbnail) { if (mTask.isLaunchTarget) { - // Animate the dim/overlay - if (Constants.DebugFlags.App.EnableThumbnailAlphaOnFrontmost) { - // Animate the thumbnail alpha before the dim animation (to prevent updating the - // hardware layer) - mThumbnailView.startEnterRecentsAnimation(new Runnable() { - @Override - public void run() { - animateDimToProgress(taskViewEnterFromAppDuration, - ctx.postAnimationTrigger.decrementOnAnimationEnd()); - } - }); - } else { - // Immediately start the dim animation - animateDimToProgress(taskViewEnterFromAppDuration, - ctx.postAnimationTrigger.decrementOnAnimationEnd()); - } + // Immediately start the dim animation + animateDimToProgress(taskViewEnterFromAppDuration, + ctx.postAnimationTrigger.decrementOnAnimationEnd()); ctx.postAnimationTrigger.increment(); // Animate the action button in @@ -635,7 +623,9 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); - if (Constants.DebugFlags.App.EnableFastToggleRecents && mIsFocused) { + + RecentsDebugFlags flags = Recents.getDebugFlags(); + if (flags.isFastToggleRecentsEnabled() && mIsFocused) { Paint tmpPaint = new Paint(); Rect tmpRect = new Rect(); tmpRect.set(0, 0, getWidth(), getHeight()); @@ -676,7 +666,8 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, clearAccessibilityFocus(); } } - if (Constants.DebugFlags.App.EnableFastToggleRecents) { + RecentsDebugFlags flags = Recents.getDebugFlags(); + if (flags.isFastToggleRecentsEnabled()) { invalidate(); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/ViewPool.java b/packages/SystemUI/src/com/android/systemui/recents/views/ViewPool.java index 12b91affce7d..31fbd3e15705 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/ViewPool.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/ViewPool.java @@ -20,6 +20,7 @@ import android.content.Context; import java.util.Iterator; import java.util.LinkedList; +import java.util.List; /* A view pool to manage more views than we can visibly handle */ @@ -76,11 +77,10 @@ public class ViewPool<V, T> { return v; } - /** Returns an iterator to the list of the views in the pool. */ - Iterator<V> poolViewIterator() { - if (mPool != null) { - return mPool.iterator(); - } - return null; + /** + * Returns the list of views in the pool. + */ + List<V> getViews() { + return mPool; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 069279fdafe3..d3d9bef0b703 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -470,7 +470,6 @@ public abstract class BaseStatusBar extends SystemUI implements processForRemoteInput(sbn.getNotification()); String key = sbn.getKey(); boolean isUpdate = mNotificationData.get(key) != null; - // In case we don't allow child notifications, we ignore children of // notifications that have a summary, since we're not going to show them // anyway. This is true also when the summary is canceled, @@ -2023,6 +2022,7 @@ public abstract class BaseStatusBar extends SystemUI implements } Notification n = notification.getNotification(); + mNotificationData.updateRanking(ranking); boolean applyInPlace = !entry.cacheContentViews(mContext, notification.getNotification()); boolean shouldInterrupt = shouldInterrupt(entry, notification); @@ -2077,7 +2077,6 @@ public abstract class BaseStatusBar extends SystemUI implements inflateViews(entry, mStackScroller); } updateHeadsUp(key, entry, shouldInterrupt, alertAgain); - mNotificationData.updateRanking(ranking); updateNotifications(); // Update the veto button accordingly (and as a result, whether this row is @@ -2167,7 +2166,6 @@ public abstract class BaseStatusBar extends SystemUI implements boolean accessibilityForcesLaunch = isFullscreen && mAccessibilityManager.isTouchExplorationEnabled(); boolean justLaunchedFullScreenIntent = entry.hasJustLaunchedFullScreenIntent(); - boolean interrupt = (isFullscreen || (isHighPriority && (isNoisy || hasTicker))) && isAllowed && !accessibilityForcesLaunch @@ -2175,7 +2173,8 @@ public abstract class BaseStatusBar extends SystemUI implements && mPowerManager.isScreenOn() && (!mStatusBarKeyguardViewManager.isShowing() || mStatusBarKeyguardViewManager.isOccluded()) - && !mStatusBarKeyguardViewManager.isInputRestricted(); + && !mStatusBarKeyguardViewManager.isInputRestricted() + && !mNotificationData.shouldSuppressPeek(sbn.getKey()); try { interrupt = interrupt && !mDreamManager.isDreaming(); } catch (RemoteException e) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java index 6a90d8e2e147..4328e24aa5eb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java @@ -292,6 +292,15 @@ public class NotificationData { return NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE; } + public boolean shouldSuppressPeek(String key) { + if (mRankingMap != null) { + mRankingMap.getRanking(key, mTmpRanking); + return (mTmpRanking.getSuppressedVisualEffects() + & NotificationListenerService.SUPPRESSED_EFFECT_PEEK) != 0; + } + return false; + } + private void updateRankingAndSort(RankingMap ranking) { if (ranking != null) { mRankingMap = ranking; 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 9ab2a2c28793..0cddf1d851ff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -1261,6 +1261,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, Entry oldEntry) { if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey()); + mNotificationData.updateRanking(ranking); Entry shadeEntry = createNotificationViews(notification); if (shadeEntry == null) { return; diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index c2284224502d..9eb66dd281e1 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -88,6 +88,7 @@ public class VibratorService extends IVibratorService.Stub private SettingsObserver mSettingObserver; native static boolean vibratorExists(); + native static void vibratorInit(); native static void vibratorOn(long milliseconds); native static void vibratorOff(); @@ -195,6 +196,7 @@ public class VibratorService extends IVibratorService.Stub } VibratorService(Context context) { + vibratorInit(); // Reset the hardware to a default state, in case this is a runtime // restart instead of a fresh boot. vibratorOff(); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index b84811fa8c4d..fd1e9dd1f465 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -17,6 +17,8 @@ package com.android.server.notification; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; +import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_LIGHTS; +import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_PEEK; import static android.service.notification.NotificationListenerService.TRIM_FULL; import static android.service.notification.NotificationListenerService.TRIM_LIGHT; import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; @@ -78,7 +80,6 @@ import android.os.UserManager; import android.os.Vibrator; import android.provider.Settings; import android.service.notification.Condition; -import android.service.notification.IConditionListener; import android.service.notification.IConditionProvider; import android.service.notification.INotificationListener; import android.service.notification.IStatusBarNotificationHolder; @@ -2511,7 +2512,9 @@ public class NotificationManagerService extends SystemService { // light // release the light boolean wasShowLights = mLights.remove(record.getKey()); - if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold) { + if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold + && ((record.getSuppressedVisualEffects() + & NotificationListenerService.SUPPRESSED_EFFECT_LIGHTS) == 0)) { mLights.add(record.getKey()); updateLightsLocked(); if (mUseAttentionLight) { @@ -2701,6 +2704,11 @@ public class NotificationManagerService extends SystemService { // let zen mode evaluate this record private void applyZenModeLocked(NotificationRecord record) { record.setIntercepted(mZenModeHelper.shouldIntercept(record)); + if (record.isIntercepted()) { + int suppressed = (mZenModeHelper.shouldSuppressLight() ? SUPPRESSED_EFFECT_LIGHTS : 0) + | (mZenModeHelper.shouldSuppressPeek() ? SUPPRESSED_EFFECT_PEEK : 0); + record.setSuppressedVisualEffects(suppressed); + } } // lock on mNotificationList @@ -3234,6 +3242,7 @@ public class NotificationManagerService extends SystemService { ArrayList<String> keys = new ArrayList<String>(N); ArrayList<String> interceptedKeys = new ArrayList<String>(N); Bundle visibilityOverrides = new Bundle(); + Bundle suppressedVisualEffects = new Bundle(); for (int i = 0; i < N; i++) { NotificationRecord record = mNotificationList.get(i); if (!isVisibleToListener(record.sbn, info)) { @@ -3242,7 +3251,10 @@ public class NotificationManagerService extends SystemService { keys.add(record.sbn.getKey()); if (record.isIntercepted()) { interceptedKeys.add(record.sbn.getKey()); + } + suppressedVisualEffects.putInt( + record.sbn.getKey(), record.getSuppressedVisualEffects()); if (record.getPackageVisibilityOverride() != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) { visibilityOverrides.putInt(record.sbn.getKey(), @@ -3264,7 +3276,7 @@ public class NotificationManagerService extends SystemService { String[] keysAr = keys.toArray(new String[keys.size()]); String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]); return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides, - speedBumpIndex); + speedBumpIndex, suppressedVisualEffects); } private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) { diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index f37702c8db94..2a7568db2040 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -83,6 +83,8 @@ public final class NotificationRecord { private String mGlobalSortKey; private int mPackageVisibility; + private int mSuppressedVisualEffects = 0; + @VisibleForTesting public NotificationRecord(StatusBarNotification sbn, int score) { @@ -199,6 +201,7 @@ public final class NotificationRecord { pw.println(prefix + " mCreationTimeMs=" + mCreationTimeMs); pw.println(prefix + " mVisibleSinceMs=" + mVisibleSinceMs); pw.println(prefix + " mUpdateTimeMs=" + mUpdateTimeMs); + pw.println(prefix + " mSuppressedVisualEffects= " + mSuppressedVisualEffects); } @@ -274,6 +277,14 @@ public final class NotificationRecord { return mIntercept; } + public void setSuppressedVisualEffects(int effects) { + mSuppressedVisualEffects = effects; + } + + public int getSuppressedVisualEffects() { + return mSuppressedVisualEffects; + } + public boolean isCategory(String category) { return Objects.equals(getNotification().category, category); } diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index a1f8c41619d0..dbdc3f4ca40b 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -138,6 +138,18 @@ public class ZenModeHelper { } } + public boolean shouldSuppressLight() { + synchronized (mConfig) { + return !mConfig.allowLights; + } + } + + public boolean shouldSuppressPeek() { + synchronized (mConfig) { + return !mConfig.allowPeek; + } + } + public void addCallback(Callback callback) { mCallbacks.add(callback); } @@ -394,11 +406,11 @@ public class ZenModeHelper { return; } pw.printf("allow(calls=%s,callsFrom=%s,repeatCallers=%s,messages=%s,messagesFrom=%s," - + "events=%s,reminders=%s)\n", + + "events=%s,reminders=%s,lights=%s,peek=%s)\n", config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom), config.allowRepeatCallers, config.allowMessages, ZenModeConfig.sourceToString(config.allowMessagesFrom), - config.allowEvents, config.allowReminders); + config.allowEvents, config.allowReminders, config.allowLights, config.allowPeek); pw.print(prefix); pw.print(" manualRule="); pw.println(config.manualRule); if (config.automaticRules.isEmpty()) return; final int N = config.automaticRules.size(); diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java index e4dbf65764d1..8fac9dac4a64 100644 --- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java @@ -871,7 +871,7 @@ final class DefaultPermissionGrantPolicy { return false; } PackageSetting sysPkg = mService.mSettings.getDisabledSystemPkgLPr(pkg.packageName); - if (sysPkg != null) { + if (sysPkg != null && sysPkg.pkg != null) { if ((sysPkg.pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) { return false; } diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp index 64278ed4499b..03fbd19094ba 100644 --- a/services/core/jni/com_android_server_VibratorService.cpp +++ b/services/core/jni/com_android_server_VibratorService.cpp @@ -22,32 +22,69 @@ #include <utils/misc.h> #include <utils/Log.h> -#include <hardware_legacy/vibrator.h> +#include <hardware/vibrator.h> #include <stdio.h> namespace android { +static hw_module_t *gVibraModule = NULL; +static vibrator_device_t *gVibraDevice = NULL; + +static void vibratorInit(JNIEnv /* env */, jobject /* clazz */) +{ + if (gVibraModule != NULL) { + return; + } + + int err = hw_get_module(VIBRATOR_HARDWARE_MODULE_ID, (hw_module_t const**)&gVibraModule); + + if (err) { + ALOGE("Couldn't load %s module (%s)", VIBRATOR_HARDWARE_MODULE_ID, strerror(-err)); + } else { + if (gVibraModule) { + vibrator_open(gVibraModule, &gVibraDevice); + } + } +} + static jboolean vibratorExists(JNIEnv* /* env */, jobject /* clazz */) { - return vibrator_exists() > 0 ? JNI_TRUE : JNI_FALSE; + if (gVibraModule && gVibraDevice) { + return JNI_TRUE; + } else { + return JNI_FALSE; + } } static void vibratorOn(JNIEnv* /* env */, jobject /* clazz */, jlong timeout_ms) { - // ALOGI("vibratorOn\n"); - vibrator_on(timeout_ms); + if (gVibraDevice) { + int err = gVibraDevice->vibrator_on(gVibraDevice, timeout_ms); + if (err != 0) { + ALOGE("The hw module failed in vibrator_on: %s", strerror(-err)); + } + } else { + ALOGW("Tried to vibrate but there is no vibrator device."); + } } static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */) { - // ALOGI("vibratorOff\n"); - vibrator_off(); + if (gVibraDevice) { + int err = gVibraDevice->vibrator_off(gVibraDevice); + if (err != 0) { + ALOGE("The hw module failed in vibrator_off(): %s", strerror(-err)); + } + } else { + ALOGW("Tried to stop vibrating but there is no vibrator device."); + } } static const JNINativeMethod method_table[] = { { "vibratorExists", "()Z", (void*)vibratorExists }, + { "vibratorInit", "()V", (void*)vibratorInit }, { "vibratorOn", "(J)V", (void*)vibratorOn }, { "vibratorOff", "()V", (void*)vibratorOff } }; diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index be190cbef47d..b5654eebd34f 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -152,18 +152,23 @@ static jobject getInputWindowHandleObjLocalRef(JNIEnv* env, getInputWindowHandleObjLocalRef(env); } -static void loadSystemIconAsSprite(JNIEnv* env, jobject contextObj, int32_t style, - SpriteIcon* outSpriteIcon) { - PointerIcon pointerIcon; +static void loadSystemIconAsSpriteWithPointerIcon(JNIEnv* env, jobject contextObj, int32_t style, + PointerIcon* outPointerIcon, SpriteIcon* outSpriteIcon) { status_t status = android_view_PointerIcon_loadSystemIcon(env, - contextObj, style, &pointerIcon); + contextObj, style, outPointerIcon); if (!status) { - pointerIcon.bitmap.copyTo(&outSpriteIcon->bitmap, kN32_SkColorType); - outSpriteIcon->hotSpotX = pointerIcon.hotSpotX; - outSpriteIcon->hotSpotY = pointerIcon.hotSpotY; + outPointerIcon->bitmap.copyTo(&outSpriteIcon->bitmap, kN32_SkColorType); + outSpriteIcon->hotSpotX = outPointerIcon->hotSpotX; + outSpriteIcon->hotSpotY = outPointerIcon->hotSpotY; } } +static void loadSystemIconAsSprite(JNIEnv* env, jobject contextObj, int32_t style, + SpriteIcon* outSpriteIcon) { + PointerIcon pointerIcon; + loadSystemIconAsSpriteWithPointerIcon(env, contextObj, style, &pointerIcon, outSpriteIcon); +} + enum { WM_ACTION_PASS_TO_USER = 1, }; @@ -238,7 +243,8 @@ public: /* --- PointerControllerPolicyInterface implementation --- */ virtual void loadPointerResources(PointerResources* outResources); - virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources); + virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources, + std::map<int32_t, PointerAnimation>* outAnimationResources); virtual int32_t getDefaultPointerIconId(); private: @@ -1041,14 +1047,31 @@ void NativeInputManager::loadPointerResources(PointerResources* outResources) { &outResources->spotAnchor); } -void NativeInputManager::loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources) { +void NativeInputManager::loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources, + std::map<int32_t, PointerAnimation>* outAnimationResources) { JNIEnv* env = jniEnv(); for (int iconId = POINTER_ICON_STYLE_CONTEXT_MENU; iconId <= POINTER_ICON_STYLE_GRABBING; ++iconId) { - loadSystemIconAsSprite(env, mContextObj, iconId, &((*outResources)[iconId])); + PointerIcon pointerIcon; + loadSystemIconAsSpriteWithPointerIcon( + env, mContextObj, iconId, &pointerIcon, &((*outResources)[iconId])); + if (!pointerIcon.bitmapFrames.empty()) { + PointerAnimation& animationData = (*outAnimationResources)[iconId]; + size_t numFrames = pointerIcon.bitmapFrames.size() + 1; + animationData.durationPerFrame = + milliseconds_to_nanoseconds(pointerIcon.durationPerFrame); + animationData.animationFrames.reserve(numFrames); + animationData.animationFrames.push_back(SpriteIcon( + pointerIcon.bitmap, pointerIcon.hotSpotX, pointerIcon.hotSpotY)); + for (size_t i = 0; i < numFrames - 1; ++i) { + animationData.animationFrames.push_back(SpriteIcon( + pointerIcon.bitmapFrames[i], pointerIcon.hotSpotX, pointerIcon.hotSpotY)); + } + } } - loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_NULL, &((*outResources)[POINTER_ICON_STYLE_NULL])); + loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_NULL, + &((*outResources)[POINTER_ICON_STYLE_NULL])); } int32_t NativeInputManager::getDefaultPointerIconId() { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index c743f2426828..31c367001e9b 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -2436,6 +2436,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Active device/profile owners must remain active admins. if (isDeviceOwner(adminReceiver, userHandle) || isProfileOwner(adminReceiver, userHandle)) { + Slog.e(LOG_TAG, "Device/profile owner cannot be removed: component=" + + adminReceiver); return; } mContext.enforceCallingOrSelfPermission( @@ -3184,7 +3186,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!mHasFeature) { return false; } - final int userHandle = UserHandle.getCallingUserId(); + final int callingUid = mInjector.binderGetCallingUid(); + final int userHandle = mInjector.userHandleGetCallingUserId(); long ident = mInjector.binderClearCallingIdentity(); try { @@ -3200,10 +3203,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int quality; synchronized (this) { - // This api can only be called by an active device admin, - // so try to retrieve it to check that the caller is one. - final ActiveAdmin admin = getActiveAdminForCallerLocked(null, - DeviceAdminInfo.USES_POLICY_RESET_PASSWORD); + // If caller has PO (or DO), it can clear the password, so see if that's the case + // first. + ActiveAdmin admin = getActiveAdminWithPolicyForUidLocked( + null, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, callingUid); + if (admin == null) { + // Otherwise, make sure the caller has any active admin with the right policy. + admin = getActiveAdminForCallerLocked(null, + DeviceAdminInfo.USES_POLICY_RESET_PASSWORD); + } + final ComponentName adminComponent = admin.info.getComponent(); // As of N, only profile owners and device owners can reset the password. @@ -3316,7 +3325,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - int callingUid = mInjector.binderGetCallingUid(); DevicePolicyData policy = getUserData(userHandle); if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) { Slog.w(LOG_TAG, "resetPassword: already set by another uid and not entered by user"); diff --git a/tests/RenderScriptTests/Fountain/Android.mk b/tests/RenderScriptTests/Fountain/Android.mk deleted file mode 100644 index 0517aef8434e..000000000000 --- a/tests/RenderScriptTests/Fountain/Android.mk +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (C) 2008 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. -# - -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := tests - -LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) - -LOCAL_SDK_VERSION := 17 - -LOCAL_PACKAGE_NAME := RsFountain - -include $(BUILD_PACKAGE) diff --git a/tests/RenderScriptTests/Fountain/AndroidManifest.xml b/tests/RenderScriptTests/Fountain/AndroidManifest.xml deleted file mode 100644 index d19b8c335112..000000000000 --- a/tests/RenderScriptTests/Fountain/AndroidManifest.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.example.android.rs.fountain"> - <uses-sdk android:minSdkVersion="14" /> - <application - android:label="RsFountain" - android:hardwareAccelerated="true" - android:icon="@drawable/test_pattern"> - <activity android:name="Fountain"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - </application> -</manifest> diff --git a/tests/RenderScriptTests/Fountain/_index.html b/tests/RenderScriptTests/Fountain/_index.html deleted file mode 100644 index 223242f73bc7..000000000000 --- a/tests/RenderScriptTests/Fountain/_index.html +++ /dev/null @@ -1,5 +0,0 @@ -<p>An example that renders many dots on the screen that follow a user's touch. The dots fall -to the bottom of the screen when the user releases the finger.</p> - - - diff --git a/tests/RenderScriptTests/Fountain/res/drawable/test_pattern.png b/tests/RenderScriptTests/Fountain/res/drawable/test_pattern.png Binary files differdeleted file mode 100644 index e7d145554c00..000000000000 --- a/tests/RenderScriptTests/Fountain/res/drawable/test_pattern.png +++ /dev/null diff --git a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/Fountain.java b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/Fountain.java deleted file mode 100644 index 311455ad932b..000000000000 --- a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/Fountain.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.rs.fountain; - -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScript; - -import android.app.Activity; -import android.content.res.Configuration; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.provider.Settings.System; -import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.Window; -import android.widget.Button; -import android.widget.ListView; - -import java.lang.Runtime; - -public class Fountain extends Activity { - //EventListener mListener = new EventListener(); - - private static final String LOG_TAG = "libRS_jni"; - private static final boolean DEBUG = false; - private static final boolean LOG_ENABLED = false; - - private FountainView mView; - - // get the current looper (from your Activity UI thread for instance - - - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - // Create our Preview view and set it as the content of our - // Activity - mView = new FountainView(this); - setContentView(mView); - } - - @Override - protected void onResume() { - Log.e("rs", "onResume"); - - // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity looses focus - super.onResume(); - mView.resume(); - } - - @Override - protected void onPause() { - Log.e("rs", "onPause"); - - // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity looses focus - super.onPause(); - mView.pause(); - - - - //Runtime.getRuntime().exit(0); - } - - - static void log(String message) { - if (LOG_ENABLED) { - Log.v(LOG_TAG, message); - } - } - - -} - diff --git a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainRS.java b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainRS.java deleted file mode 100644 index 646c807e17fe..000000000000 --- a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainRS.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.rs.fountain; - -import android.content.res.Resources; -import android.renderscript.*; -import android.util.Log; - - -public class FountainRS { - public static final int PART_COUNT = 50000; - - public FountainRS() { - } - - private Resources mRes; - private RenderScriptGL mRS; - private ScriptC_fountain mScript; - public void init(RenderScriptGL rs, Resources res) { - mRS = rs; - mRes = res; - - ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs); - pfb.setVaryingColor(true); - rs.bindProgramFragment(pfb.create()); - - ScriptField_Point points = new ScriptField_Point(mRS, PART_COUNT);// - // Allocation.USAGE_GRAPHICS_VERTEX); - - Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS); - smb.addVertexAllocation(points.getAllocation()); - smb.addIndexSetType(Mesh.Primitive.POINT); - Mesh sm = smb.create(); - - mScript = new ScriptC_fountain(mRS, mRes, R.raw.fountain); - mScript.set_partMesh(sm); - mScript.bind_point(points); - mRS.bindRootScript(mScript); - } - - boolean holdingColor[] = new boolean[10]; - public void newTouchPosition(float x, float y, float pressure, int id) { - if (id >= holdingColor.length) { - return; - } - int rate = (int)(pressure * pressure * 500.f); - if (rate > 500) { - rate = 500; - } - if (rate > 0) { - mScript.invoke_addParticles(rate, x, y, id, !holdingColor[id]); - holdingColor[id] = true; - } else { - holdingColor[id] = false; - } - - } -} diff --git a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainView.java b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainView.java deleted file mode 100644 index 98cec55b278b..000000000000 --- a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainView.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.rs.fountain; - -import java.io.Writer; -import java.util.ArrayList; -import java.util.concurrent.Semaphore; - -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScript; -import android.renderscript.RenderScriptGL; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.os.Message; -import android.util.AttributeSet; -import android.util.Log; -import android.view.Surface; -import android.view.SurfaceHolder; -import android.view.SurfaceView; -import android.view.KeyEvent; -import android.view.MotionEvent; - -public class FountainView extends RSSurfaceView { - - public FountainView(Context context) { - super(context); - //setFocusable(true); - } - - private RenderScriptGL mRS; - private FountainRS mRender; - - public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { - super.surfaceChanged(holder, format, w, h); - if (mRS == null) { - RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); - mRS = createRenderScriptGL(sc); - mRS.setSurface(holder, w, h); - mRender = new FountainRS(); - mRender.init(mRS, getResources()); - } - } - - @Override - protected void onDetachedFromWindow() { - if (mRS != null) { - mRS = null; - destroyRenderScriptGL(); - } - } - - - @Override - public boolean onTouchEvent(MotionEvent ev) - { - int act = ev.getActionMasked(); - if (act == ev.ACTION_UP) { - mRender.newTouchPosition(0, 0, 0, ev.getPointerId(0)); - return false; - } else if (act == MotionEvent.ACTION_POINTER_UP) { - // only one pointer going up, we can get the index like this - int pointerIndex = ev.getActionIndex(); - int pointerId = ev.getPointerId(pointerIndex); - mRender.newTouchPosition(0, 0, 0, pointerId); - } - int count = ev.getHistorySize(); - int pcount = ev.getPointerCount(); - - for (int p=0; p < pcount; p++) { - int id = ev.getPointerId(p); - mRender.newTouchPosition(ev.getX(p), - ev.getY(p), - ev.getPressure(p), - id); - - for (int i=0; i < count; i++) { - mRender.newTouchPosition(ev.getHistoricalX(p, i), - ev.getHistoricalY(p, i), - ev.getHistoricalPressure(p, i), - id); - } - } - return true; - } -} - - diff --git a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/fountain.rs b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/fountain.rs deleted file mode 100644 index 151b68977dd1..000000000000 --- a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/fountain.rs +++ /dev/null @@ -1,70 +0,0 @@ -// Fountain test script -#pragma version(1) -#pragma rs_fp_relaxed - -#pragma rs java_package_name(com.example.android.rs.fountain) - -#pragma stateFragment(parent) - -#include "rs_graphics.rsh" - -static int newPart = 0; -rs_mesh partMesh; - -typedef struct __attribute__((packed, aligned(4))) Point { - float2 delta; - float2 position; - uchar4 color; -} Point_t; -Point_t *point; - -int root() { - float dt = min(rsGetDt(), 0.1f); - rsgClearColor(0.f, 0.f, 0.f, 1.f); - const float height = rsgGetHeight(); - const int size = rsAllocationGetDimX(rsGetAllocation(point)); - float dy2 = dt * (10.f); - Point_t * p = point; - for (int ct=0; ct < size; ct++) { - p->delta.y += dy2; - p->position += p->delta; - if ((p->position.y > height) && (p->delta.y > 0)) { - p->delta.y *= -0.3f; - } - p++; - } - - rsgDrawMesh(partMesh); - return 1; -} - -static float4 partColor[10]; -void addParticles(int rate, float x, float y, int index, bool newColor) -{ - if (newColor) { - partColor[index].x = rsRand(0.5f, 1.0f); - partColor[index].y = rsRand(1.0f); - partColor[index].z = rsRand(1.0f); - } - float rMax = ((float)rate) * 0.02f; - int size = rsAllocationGetDimX(rsGetAllocation(point)); - uchar4 c = rsPackColorTo8888(partColor[index]); - - Point_t * np = &point[newPart]; - float2 p = {x, y}; - while (rate--) { - float angle = rsRand(3.14f * 2.f); - float len = rsRand(rMax); - np->delta.x = len * sin(angle); - np->delta.y = len * cos(angle); - np->position = p; - np->color = c; - newPart++; - np++; - if (newPart >= size) { - newPart = 0; - np = &point[newPart]; - } - } -} - diff --git a/tests/RenderScriptTests/FountainFbo/Android.mk b/tests/RenderScriptTests/FountainFbo/Android.mk deleted file mode 100644 index c0f332328ded..000000000000 --- a/tests/RenderScriptTests/FountainFbo/Android.mk +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (C) 2008 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. -# - -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := tests - -LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) - -# TODO: build fails with this set -# LOCAL_SDK_VERSION := current - -LOCAL_PACKAGE_NAME := RsFountainFbo -LOCAL_SDK_VERSION := 14 - -include $(BUILD_PACKAGE) diff --git a/tests/RenderScriptTests/FountainFbo/AndroidManifest.xml b/tests/RenderScriptTests/FountainFbo/AndroidManifest.xml deleted file mode 100644 index 082744b6d8fc..000000000000 --- a/tests/RenderScriptTests/FountainFbo/AndroidManifest.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.example.android.rs.fountainfbo"> - <uses-sdk android:minSdkVersion="14" /> - <application - android:label="RsFountainFbo" - android:hardwareAccelerated="true" - android:icon="@drawable/test_pattern"> - <activity android:name="FountainFbo"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - </application> -</manifest> diff --git a/tests/RenderScriptTests/FountainFbo/_index.html b/tests/RenderScriptTests/FountainFbo/_index.html deleted file mode 100644 index 550865795407..000000000000 --- a/tests/RenderScriptTests/FountainFbo/_index.html +++ /dev/null @@ -1,7 +0,0 @@ -<p>An example that renders many dots on the screen that follow a user's touch. The dots fall -to the bottom of the screen when no touch is detected. This example modifies -the <a href="../Fountain/index.html">Fountain</a> sample to include rendering to a -a framebuffer object as well as the default framebuffer.</p> - - - diff --git a/tests/RenderScriptTests/FountainFbo/res/drawable/test_pattern.png b/tests/RenderScriptTests/FountainFbo/res/drawable/test_pattern.png Binary files differdeleted file mode 100644 index e7d145554c00..000000000000 --- a/tests/RenderScriptTests/FountainFbo/res/drawable/test_pattern.png +++ /dev/null diff --git a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFbo.java b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFbo.java deleted file mode 100644 index d8ba30fd1c89..000000000000 --- a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFbo.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.rs.fountainfbo; - -import android.app.Activity; -import android.os.Bundle; -import android.util.Log; - -public class FountainFbo extends Activity { - private static final String LOG_TAG = "libRS_jni"; - private static final boolean DEBUG = false; - private static final boolean LOG_ENABLED = false; - - private FountainFboView mView; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - /* Create our Preview view and set it as the content of our Activity */ - mView = new FountainFboView(this); - setContentView(mView); - } - - @Override - protected void onResume() { - Log.e("rs", "onResume"); - - /* Ideally a game should implement onResume() and onPause() - to take appropriate action when the activity loses focus */ - super.onResume(); - mView.resume(); - } - - @Override - protected void onPause() { - Log.e("rs", "onPause"); - - /* Ideally a game should implement onResume() and onPause() - to take appropriate action when the activity loses focus */ - super.onPause(); - mView.pause(); - } - - static void log(String message) { - if (LOG_ENABLED) { - Log.v(LOG_TAG, message); - } - } -} - diff --git a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboRS.java b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboRS.java deleted file mode 100644 index 3bf3ff1f3874..000000000000 --- a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboRS.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.rs.fountainfbo; - -import android.content.res.Resources; -import android.renderscript.Allocation; -import android.renderscript.Element; -import android.renderscript.Mesh; -import android.renderscript.ProgramFragment; -import android.renderscript.ProgramFragmentFixedFunction; -import android.renderscript.RenderScriptGL; -import android.renderscript.Type; - -public class FountainFboRS { - public static final int PART_COUNT = 50000; - - public FountainFboRS() { - } - - private Resources mRes; - private RenderScriptGL mRS; - private ScriptC_fountainfbo mScript; - private Allocation mColorBuffer; - private ProgramFragment mProgramFragment; - private ProgramFragment mTextureProgramFragment; - public void init(RenderScriptGL rs, Resources res) { - mRS = rs; - mRes = res; - - ScriptField_Point points = new ScriptField_Point(mRS, PART_COUNT); - - Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS); - smb.addVertexAllocation(points.getAllocation()); - smb.addIndexSetType(Mesh.Primitive.POINT); - Mesh sm = smb.create(); - - mScript = new ScriptC_fountainfbo(mRS, mRes, R.raw.fountainfbo); - mScript.set_partMesh(sm); - mScript.bind_point(points); - - ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs); - pfb.setVaryingColor(true); - mProgramFragment = pfb.create(); - mScript.set_gProgramFragment(mProgramFragment); - - /* Second fragment shader to use a texture (framebuffer object) to draw with */ - pfb.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, - ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); - - /* Set the fragment shader in the Renderscript runtime */ - mTextureProgramFragment = pfb.create(); - mScript.set_gTextureProgramFragment(mTextureProgramFragment); - - /* Create the allocation for the color buffer */ - Type.Builder colorBuilder = new Type.Builder(mRS, Element.RGBA_8888(mRS)); - colorBuilder.setX(256).setY(256); - mColorBuffer = Allocation.createTyped(mRS, colorBuilder.create(), - Allocation.USAGE_GRAPHICS_TEXTURE | - Allocation.USAGE_GRAPHICS_RENDER_TARGET); - - /* Set the allocation in the Renderscript runtime */ - mScript.set_gColorBuffer(mColorBuffer); - - mRS.bindRootScript(mScript); - } - - boolean holdingColor[] = new boolean[10]; - public void newTouchPosition(float x, float y, float pressure, int id) { - if (id >= holdingColor.length) { - return; - } - int rate = (int)(pressure * pressure * 500.f); - if (rate > 500) { - rate = 500; - } - if (rate > 0) { - mScript.invoke_addParticles(rate, x, y, id, !holdingColor[id]); - holdingColor[id] = true; - } else { - holdingColor[id] = false; - } - - } -} - diff --git a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboView.java b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboView.java deleted file mode 100644 index 86367171d9f6..000000000000 --- a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboView.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.rs.fountainfbo; - - -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScriptGL; -import android.content.Context; -import android.view.SurfaceHolder; -import android.view.MotionEvent; - -public class FountainFboView extends RSSurfaceView { - - public FountainFboView(Context context) { - super(context); - } - - private RenderScriptGL mRS; - private FountainFboRS mRender; - - public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { - super.surfaceChanged(holder, format, w, h); - if (mRS == null) { - RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); - mRS = createRenderScriptGL(sc); - mRS.setSurface(holder, w, h); - mRender = new FountainFboRS(); - mRender.init(mRS, getResources()); - } - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - android.util.Log.e("rs", "onDetachedFromWindow"); - if (mRS != null) { - mRS = null; - destroyRenderScriptGL(); - } - } - - - @Override - public boolean onTouchEvent(MotionEvent ev) - { - int act = ev.getActionMasked(); - if (act == ev.ACTION_UP) { - mRender.newTouchPosition(0, 0, 0, ev.getPointerId(0)); - return false; - } else if (act == MotionEvent.ACTION_POINTER_UP) { - // only one pointer going up, we can get the index like this - int pointerIndex = ev.getActionIndex(); - int pointerId = ev.getPointerId(pointerIndex); - mRender.newTouchPosition(0, 0, 0, pointerId); - } - int count = ev.getHistorySize(); - int pcount = ev.getPointerCount(); - - for (int p=0; p < pcount; p++) { - int id = ev.getPointerId(p); - mRender.newTouchPosition(ev.getX(p), - ev.getY(p), - ev.getPressure(p), - id); - - for (int i=0; i < count; i++) { - mRender.newTouchPosition(ev.getHistoricalX(p, i), - ev.getHistoricalY(p, i), - ev.getHistoricalPressure(p, i), - id); - } - } - return true; - } -} - - diff --git a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/fountainfbo.rs b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/fountainfbo.rs deleted file mode 100644 index 763f6bacffb2..000000000000 --- a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/fountainfbo.rs +++ /dev/null @@ -1,106 +0,0 @@ -// Fountain test script -#pragma version(1) - -#pragma rs java_package_name(com.example.android.rs.fountainfbo) - -#pragma stateFragment(parent) - -#include "rs_graphics.rsh" - -static int newPart = 0; -rs_mesh partMesh; -rs_program_vertex gProgramVertex; - -//allocation for color buffer -rs_allocation gColorBuffer; -//fragment shader for rendering without a texture (used for rendering to framebuffer object) -rs_program_fragment gProgramFragment; -//fragment shader for rendering with a texture (used for rendering to default framebuffer) -rs_program_fragment gTextureProgramFragment; - -typedef struct __attribute__((packed, aligned(4))) Point { - float2 delta; - float2 position; - uchar4 color; -} Point_t; -Point_t *point; - -int root() { - float dt = min(rsGetDt(), 0.1f); - rsgClearColor(0.f, 0.f, 0.f, 1.f); - const float height = rsgGetHeight(); - const int size = rsAllocationGetDimX(rsGetAllocation(point)); - float dy2 = dt * (10.f); - Point_t * p = point; - for (int ct=0; ct < size; ct++) { - p->delta.y += dy2; - p->position += p->delta; - if ((p->position.y > height) && (p->delta.y > 0)) { - p->delta.y *= -0.3f; - } - p++; - } - //Tell Renderscript runtime to render to the frame buffer object - rsgBindColorTarget(gColorBuffer, 0); - - //Begin rendering on a white background - rsgClearColor(1.f, 1.f, 1.f, 1.f); - rsgDrawMesh(partMesh); - - //When done, tell Renderscript runtime to stop rendering to framebuffer object - rsgClearAllRenderTargets(); - - //Bind a new fragment shader that declares the framebuffer object to be used as a texture - rsgBindProgramFragment(gTextureProgramFragment); - - //Bind the framebuffer object to the fragment shader at slot 0 as a texture - rsgBindTexture(gTextureProgramFragment, 0, gColorBuffer); - - //Draw a quad using the framebuffer object as the texture - float startX = 10, startY = 10; - float s = 256; - rsgDrawQuadTexCoords(startX, startY, 0, 0, 1, - startX, startY + s, 0, 0, 0, - startX + s, startY + s, 0, 1, 0, - startX + s, startY, 0, 1, 1); - - //Rebind the original fragment shader to render as normal - rsgBindProgramFragment(gProgramFragment); - - //Render the main scene - rsgDrawMesh(partMesh); - - return 1; -} - -static float4 partColor[10]; -void addParticles(int rate, float x, float y, int index, bool newColor) -{ - if (newColor) { - partColor[index].x = rsRand(0.5f, 1.0f); - partColor[index].y = rsRand(1.0f); - partColor[index].z = rsRand(1.0f); - } - float rMax = ((float)rate) * 0.02f; - int size = rsAllocationGetDimX(rsGetAllocation(point)); - uchar4 c = rsPackColorTo8888(partColor[index]); - - Point_t * np = &point[newPart]; - float2 p = {x, y}; - while (rate--) { - float angle = rsRand(3.14f * 2.f); - float len = rsRand(rMax); - np->delta.x = len * sin(angle); - np->delta.y = len * cos(angle); - np->position = p; - np->color = c; - newPart++; - np++; - if (newPart >= size) { - newPart = 0; - np = &point[newPart]; - } - } -} - - diff --git a/tests/RenderScriptTests/Fountain_v11/Android.mk b/tests/RenderScriptTests/Fountain_v11/Android.mk deleted file mode 100644 index ac2690cf546b..000000000000 --- a/tests/RenderScriptTests/Fountain_v11/Android.mk +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (C) 2008 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. -# - -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := tests - -LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) -#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript - -LOCAL_PACKAGE_NAME := Fountain_v11 -LOCAL_SDK_VERSION := 11 - -include $(BUILD_PACKAGE) diff --git a/tests/RenderScriptTests/Fountain_v11/AndroidManifest.xml b/tests/RenderScriptTests/Fountain_v11/AndroidManifest.xml deleted file mode 100644 index fcb4faf5858c..000000000000 --- a/tests/RenderScriptTests/Fountain_v11/AndroidManifest.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.fountain_v11"> - <uses-sdk android:minSdkVersion="11" /> - <application - android:label="Fountain_v11" - android:icon="@drawable/test_pattern"> - <activity android:name="Fountain_v11"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - </application> -</manifest> diff --git a/tests/RenderScriptTests/Fountain_v11/_index.html b/tests/RenderScriptTests/Fountain_v11/_index.html deleted file mode 100644 index 223242f73bc7..000000000000 --- a/tests/RenderScriptTests/Fountain_v11/_index.html +++ /dev/null @@ -1,5 +0,0 @@ -<p>An example that renders many dots on the screen that follow a user's touch. The dots fall -to the bottom of the screen when the user releases the finger.</p> - - - diff --git a/tests/RenderScriptTests/Fountain_v11/res/drawable/test_pattern.png b/tests/RenderScriptTests/Fountain_v11/res/drawable/test_pattern.png Binary files differdeleted file mode 100644 index e7d145554c00..000000000000 --- a/tests/RenderScriptTests/Fountain_v11/res/drawable/test_pattern.png +++ /dev/null diff --git a/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/FountainRS.java b/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/FountainRS.java deleted file mode 100644 index e8581001007e..000000000000 --- a/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/FountainRS.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.fountain_v11; - -import android.content.res.Resources; -import android.renderscript.*; -import android.util.Log; - - -public class FountainRS { - public static final int PART_COUNT = 50000; - - public FountainRS() { - } - - private Resources mRes; - private RenderScriptGL mRS; - private ScriptC_fountain mScript; - public void init(RenderScriptGL rs, Resources res, int width, int height) { - mRS = rs; - mRes = res; - - ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs); - pfb.setVaryingColor(true); - rs.bindProgramFragment(pfb.create()); - - ScriptField_Point points = new ScriptField_Point(mRS, PART_COUNT);// - // Allocation.USAGE_GRAPHICS_VERTEX); - - Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS); - smb.addVertexAllocation(points.getAllocation()); - smb.addIndexSetType(Mesh.Primitive.POINT); - Mesh sm = smb.create(); - - mScript = new ScriptC_fountain(mRS, mRes, R.raw.fountain); - mScript.set_partMesh(sm); - mScript.bind_point(points); - mRS.bindRootScript(mScript); - } - - boolean holdingColor[] = new boolean[10]; - public void newTouchPosition(float x, float y, float pressure, int id) { - if (id >= holdingColor.length) { - return; - } - int rate = (int)(pressure * pressure * 500.f); - if (rate > 500) { - rate = 500; - } - if (rate > 0) { - mScript.invoke_addParticles(rate, x, y, id, !holdingColor[id]); - holdingColor[id] = true; - } else { - holdingColor[id] = false; - } - - } -} diff --git a/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/FountainView.java b/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/FountainView.java deleted file mode 100644 index e82376c4dbb9..000000000000 --- a/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/FountainView.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.fountain_v11; - -import java.io.Writer; -import java.util.ArrayList; -import java.util.concurrent.Semaphore; - -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScript; -import android.renderscript.RenderScriptGL; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.os.Message; -import android.util.AttributeSet; -import android.util.Log; -import android.view.Surface; -import android.view.SurfaceHolder; -import android.view.SurfaceView; -import android.view.KeyEvent; -import android.view.MotionEvent; - -public class FountainView extends RSSurfaceView { - - public FountainView(Context context) { - super(context); - //setFocusable(true); - } - - private RenderScriptGL mRS; - private FountainRS mRender; - - public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { - super.surfaceChanged(holder, format, w, h); - if (mRS == null) { - RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); - mRS = createRenderScriptGL(sc); - mRS.setSurface(holder, w, h); - mRender = new FountainRS(); - mRender.init(mRS, getResources(), w, h); - } - } - - @Override - protected void onDetachedFromWindow() { - if (mRS != null) { - mRS = null; - destroyRenderScriptGL(); - } - } - - - @Override - public boolean onTouchEvent(MotionEvent ev) - { - int act = ev.getActionMasked(); - if (act == ev.ACTION_UP) { - mRender.newTouchPosition(0, 0, 0, ev.getPointerId(0)); - return false; - } else if (act == MotionEvent.ACTION_POINTER_UP) { - // only one pointer going up, we can get the index like this - int pointerIndex = ev.getActionIndex(); - int pointerId = ev.getPointerId(pointerIndex); - mRender.newTouchPosition(0, 0, 0, pointerId); - } - int count = ev.getHistorySize(); - int pcount = ev.getPointerCount(); - - for (int p=0; p < pcount; p++) { - int id = ev.getPointerId(p); - mRender.newTouchPosition(ev.getX(p), - ev.getY(p), - ev.getPressure(p), - id); - - for (int i=0; i < count; i++) { - mRender.newTouchPosition(ev.getHistoricalX(p, i), - ev.getHistoricalY(p, i), - ev.getHistoricalPressure(p, i), - id); - } - } - return true; - } -} - - diff --git a/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/Fountain_v11.java b/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/Fountain_v11.java deleted file mode 100644 index 2c07b27c78df..000000000000 --- a/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/Fountain_v11.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.fountain_v11; - -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScript; - -import android.app.Activity; -import android.content.res.Configuration; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.provider.Settings.System; -import android.util.Config; -import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.Window; -import android.widget.Button; -import android.widget.ListView; - -import java.lang.Runtime; - -public class Fountain_v11 extends Activity { - //EventListener mListener = new EventListener(); - - private static final String LOG_TAG = "libRS_jni"; - private static final boolean DEBUG = false; - private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV; - - private FountainView mView; - - // get the current looper (from your Activity UI thread for instance - - - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - // Create our Preview view and set it as the content of our - // Activity - mView = new FountainView(this); - setContentView(mView); - } - - @Override - protected void onResume() { - Log.e("rs", "onResume"); - - // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity looses focus - super.onResume(); - mView.resume(); - } - - @Override - protected void onPause() { - Log.e("rs", "onPause"); - - // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity looses focus - super.onPause(); - mView.pause(); - - - - //Runtime.getRuntime().exit(0); - } - - - static void log(String message) { - if (LOG_ENABLED) { - Log.v(LOG_TAG, message); - } - } - - -} - diff --git a/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/fountain.rs b/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/fountain.rs deleted file mode 100644 index 3b6c89af8883..000000000000 --- a/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/fountain.rs +++ /dev/null @@ -1,69 +0,0 @@ -// Fountain test script -#pragma version(1) - -#pragma rs java_package_name(com.android.fountain_v11) - -#pragma stateFragment(parent) - -#include "rs_graphics.rsh" - -static int newPart = 0; -rs_mesh partMesh; - -typedef struct __attribute__((packed, aligned(4))) Point { - float2 delta; - float2 position; - uchar4 color; -} Point_t; -Point_t *point; - -int root() { - float dt = min(rsGetDt(), 0.1f); - rsgClearColor(0.f, 0.f, 0.f, 1.f); - const float height = rsgGetHeight(); - const int size = rsAllocationGetDimX(rsGetAllocation(point)); - float dy2 = dt * (10.f); - Point_t * p = point; - for (int ct=0; ct < size; ct++) { - p->delta.y += dy2; - p->position += p->delta; - if ((p->position.y > height) && (p->delta.y > 0)) { - p->delta.y *= -0.3f; - } - p++; - } - - rsgDrawMesh(partMesh); - return 1; -} - -static float4 partColor[10]; -void addParticles(int rate, float x, float y, int index, bool newColor) -{ - if (newColor) { - partColor[index].x = rsRand(0.5f, 1.0f); - partColor[index].y = rsRand(1.0f); - partColor[index].z = rsRand(1.0f); - } - float rMax = ((float)rate) * 0.02f; - int size = rsAllocationGetDimX(rsGetAllocation(point)); - uchar4 c = rsPackColorTo8888(partColor[index]); - - Point_t * np = &point[newPart]; - float2 p = {x, y}; - while (rate--) { - float angle = rsRand(3.14f * 2.f); - float len = rsRand(rMax); - np->delta.x = len * sin(angle); - np->delta.y = len * cos(angle); - np->position = p; - np->color = c; - newPart++; - np++; - if (newPart >= size) { - newPart = 0; - np = &point[newPart]; - } - } -} - diff --git a/tools/layoutlib/.idea/encodings.xml b/tools/layoutlib/.idea/encodings.xml index e206d70d8595..f758959656c7 100644 --- a/tools/layoutlib/.idea/encodings.xml +++ b/tools/layoutlib/.idea/encodings.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <project version="4"> - <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" /> -</project> - + <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false"> + <file url="PROJECT" charset="UTF-8" /> + </component> +</project>
\ No newline at end of file diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java index b67afebf9a89..cdcf0ea1ca76 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java @@ -76,19 +76,18 @@ public class AppCompatActionBar extends BridgeActionBar { Class[] constructorParams = {View.class}; Object[] constructorArgs = {getDecorContent()}; LayoutlibCallback callback = params.getLayoutlibCallback(); - // First try to load the class as was available before appcompat v23.1.1, without - // logging warnings. + + // Check if the old action bar class is present. + String actionBarClass = WINDOW_ACTION_BAR_CLASS; try { - mWindowDecorActionBar = callback.loadClass(WINDOW_ACTION_BAR_CLASS, - constructorParams, constructorArgs); - } catch (ClassNotFoundException ignore) { - } - if (mWindowDecorActionBar == null) { - // If failed, load the new class, while logging warnings. - mWindowDecorActionBar = callback.loadView(WINDOW_ACTION_BAR_CLASS_NEW, - constructorParams, constructorArgs); + callback.findClass(actionBarClass); + } catch (ClassNotFoundException expected) { + // Failed to find the old class, use the newer one. + actionBarClass = WINDOW_ACTION_BAR_CLASS_NEW; } + mWindowDecorActionBar = callback.loadView(actionBarClass, + constructorParams, constructorArgs); mWindowActionBarClass = mWindowDecorActionBar == null ? null : mWindowDecorActionBar.getClass(); setupActionBar(); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java index 42e55e2504de..a6e5fb841bff 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java @@ -33,7 +33,6 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import android.annotation.NonNull; -import android.annotation.Nullable; import android.content.res.ColorStateList; import android.graphics.Bitmap; import android.graphics.Bitmap_Delegate; @@ -228,18 +227,16 @@ abstract class CustomBar extends LinearLayout { * Find the background color for this bar from the theme attributes. Only relevant to StatusBar * and NavigationBar. * <p/> - * Returns null if not found. + * Returns 0 if not found. * * @param colorAttrName the attribute name for the background color * @param translucentAttrName the attribute name for the translucency property of the bar. * * @throws NumberFormatException if color resolved to an invalid string. */ - @Nullable - protected Integer getBarColor(@NonNull String colorAttrName, - @NonNull String translucentAttrName) { + protected int getBarColor(@NonNull String colorAttrName, @NonNull String translucentAttrName) { if (!Config.isGreaterOrEqual(mSimulatedPlatformVersion, LOLLIPOP)) { - return null; + return 0; } RenderResources renderResources = getContext().getRenderResources(); // First check if the bar is translucent. @@ -254,11 +251,10 @@ abstract class CustomBar extends LinearLayout { if (transparent) { return getColor(renderResources, colorAttrName); } - return null; + return 0; } - @Nullable - private static Integer getColor(RenderResources renderResources, String attr) { + private static int getColor(RenderResources renderResources, String attr) { // From ?attr/foo to @color/bar. This is most likely an ItemResourceValue. ResourceValue resource = renderResources.findItemInTheme(attr, true); // Form @color/bar to the #AARRGGBB @@ -279,7 +275,7 @@ abstract class CustomBar extends LinearLayout { } } } - return null; + return 0; } private ResourceValue getResourceValue(String reference) { diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java index d50ce23a0902..9c89bfe2a28f 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java @@ -65,8 +65,8 @@ public class NavigationBar extends CustomBar { super(context, orientation, getShortestWidth(context)>= 600 ? LAYOUT_600DP_XML : LAYOUT_XML, "navigation_bar.xml", simulatedPlatformVersion); - Integer color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT); - setBackgroundColor(color == null ? 0xFF000000 : color); + int color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT); + setBackgroundColor(color == 0 ? 0xFF000000 : color); // Cannot access the inside items through id because no R.id values have been // created for them. diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java index 95a5a58c535f..2dc7c65e2085 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java @@ -71,9 +71,8 @@ public class StatusBar extends CustomBar { // FIXME: use FILL_H? setGravity(Gravity.START | Gravity.TOP | Gravity.RIGHT); - Integer color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT); - setBackgroundColor( - color == null ? Config.getStatusBarColor(simulatedPlatformVersion) : color); + int color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT); + setBackgroundColor(color == 0 ? Config.getStatusBarColor(simulatedPlatformVersion) : color); // Cannot access the inside items through id because no R.id values have been // created for them. diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index 2a4f58381aee..0ffa35733180 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java @@ -421,7 +421,8 @@ public class RenderSessionImpl extends RenderAction<SessionParams> { gc.setComposite(AlphaComposite.Src); gc.setColor(new Color(0x00000000, true)); - gc.fillRect(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight); + gc.fillRect(0, 0, + mMeasuredScreenWidth, mMeasuredScreenHeight); // done gc.dispose(); |