Merge "Fix crash with animation specs"
diff --git a/api/current.txt b/api/current.txt
index cca8293..6208640 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4795,7 +4795,7 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 3946d4a..fc11f34 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4913,7 +4913,7 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 0b77be3..b5b77e6 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1466,10 +1466,10 @@
};
}
- private Topic[] topics;
+ private Topic topic;
- public Topic[] getTopics() {
- return topics;
+ public Topic getTopic() {
+ return topic;
}
/**
@@ -1599,7 +1599,9 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
/**
- * 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 @@
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 07b4d39..043c503 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -610,15 +610,39 @@
* 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 @@
dest.writeInt(priorityCategories);
dest.writeInt(priorityCallSenders);
dest.writeInt(priorityMessageSenders);
+ dest.writeInt(suppressedVisualEffects);
}
@Override
@@ -635,7 +660,8 @@
@Override
public int hashCode() {
- return Objects.hash(priorityCategories, priorityCallSenders, priorityMessageSenders);
+ return Objects.hash(priorityCategories, priorityCallSenders, priorityMessageSenders,
+ suppressedVisualEffects);
}
@Override
@@ -645,7 +671,8 @@
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 @@
+ "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 @@
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 b627641..48359d47 100644
--- a/core/java/android/security/net/config/ApplicationConfig.java
+++ b/core/java/android/security/net/config/ApplicationConfig.java
@@ -144,4 +144,18 @@
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 8906f9b..9eab80c 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 @@
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 ca8cdae..ac762ef 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 @@
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 7e7b5fc..ee97e8e 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -108,6 +108,11 @@
* 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 @@
private boolean mIsAmbient;
private boolean mMatchesInterruptionFilter;
private int mVisibilityOverride;
+ private int mSuppressedVisualEffects;
public Ranking() {}
@@ -861,6 +867,14 @@
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 @@
}
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 @@
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 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 @@
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 @@
}
}
+ // 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 6fba900..1282fb1 100644
--- a/core/java/android/service/notification/NotificationRankingUpdate.java
+++ b/core/java/android/service/notification/NotificationRankingUpdate.java
@@ -28,13 +28,15 @@
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 @@
mFirstAmbientIndex = in.readInt();
mInterceptedKeys = in.readStringArray();
mVisibilityOverrides = in.readBundle();
+ mSuppressedVisualEffects = in.readBundle();
}
@Override
@@ -55,6 +58,7 @@
out.writeInt(mFirstAmbientIndex);
out.writeStringArray(mInterceptedKeys);
out.writeBundle(mVisibilityOverrides);
+ out.writeBundle(mSuppressedVisualEffects);
}
public static final Parcelable.Creator<NotificationRankingUpdate> CREATOR
@@ -83,4 +87,8 @@
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 82f1b28..b3399d0 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -77,6 +77,8 @@
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 @@
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 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 @@
automaticRules.put(ids[i], rules[i]);
}
}
+ allowPeek = source.readInt() == 1;
+ allowLights = source.readInt() == 1;
}
@Override
@@ -175,22 +183,26 @@
} 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 @@
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 @@
&& 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 @@
@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 @@
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 @@
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 @@
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 @@
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 88e9a95..b61706e 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -24,6 +24,7 @@
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 @@
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 @@
} 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 @@
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 461506b..de4d439 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6329,8 +6329,8 @@
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 @@
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 db978a6..25df004 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -5114,10 +5114,10 @@
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 @@
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 @@
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 @@
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/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index 2c5e50c..08c7935 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -30,6 +30,9 @@
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 0000000..b101733
--- /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 4f38ff3..077cebc 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.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.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.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.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_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 @@
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 @@
@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 @@
*/
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 @@
if (st != null && st.menu != null && mFeatureId < 0) {
st.menu.close();
}
+
+ if (mWindowResizeCallbacksAdded) {
+ getViewRootImpl().removeWindowCallbacks(this);
+ mWindowResizeCallbacksAdded = false;
+ }
}
@Override
@@ -1483,19 +1524,245 @@
* @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 c427149..6e7e5cf 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.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.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 @@
// 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 @@
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 @@
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 @@
}
}
+ @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 @@
}
}
}
- 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 @@
+ 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 @@
}
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 @@
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 @@
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 @@
}
}
}
-
- /**
- * 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 de6e228..33b8e05 100644
--- a/core/java/com/android/internal/widget/NonClientDecorView.java
+++ b/core/java/com/android/internal/widget/NonClientDecorView.java
@@ -19,26 +19,19 @@
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 @@
* 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 @@
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 @@
// 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 @@
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 @@
* @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 @@
* 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 @@
}
}
- @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();
- }
+ public boolean isShowingDecor() {
+ return mShowDecor;
}
- @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();
- }
-
- /**
- * 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 815d330..65e8058 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -608,15 +608,6 @@
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 @@
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 d04adbf..d7e2c02 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 @@
jfieldID mBitmap;
jfieldID mHotSpotX;
jfieldID mHotSpotY;
+ jfieldID mBitmapFrames;
+ jfieldID mDurationPerFrame;
jmethodID getSystemIcon;
jmethodID load;
} gPointerIconClassInfo;
@@ -84,6 +87,19 @@
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 @@
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 86f288d..ca08085 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 @@
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 @@
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
new file mode 100644
index 0000000..adb7806
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_0.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_1.png b/core/res/res/drawable-mdpi/pointer_wait_1.png
new file mode 100644
index 0000000..fc6b42f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_1.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_10.png b/core/res/res/drawable-mdpi/pointer_wait_10.png
new file mode 100644
index 0000000..02968b5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_10.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_11.png b/core/res/res/drawable-mdpi/pointer_wait_11.png
new file mode 100644
index 0000000..24f866b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_11.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_12.png b/core/res/res/drawable-mdpi/pointer_wait_12.png
new file mode 100644
index 0000000..d1a31bc
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_12.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_13.png b/core/res/res/drawable-mdpi/pointer_wait_13.png
new file mode 100644
index 0000000..b0c6798
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_13.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_14.png b/core/res/res/drawable-mdpi/pointer_wait_14.png
new file mode 100644
index 0000000..721e86d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_14.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_15.png b/core/res/res/drawable-mdpi/pointer_wait_15.png
new file mode 100644
index 0000000..adb0199
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_15.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_16.png b/core/res/res/drawable-mdpi/pointer_wait_16.png
new file mode 100644
index 0000000..3695c18
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_16.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_17.png b/core/res/res/drawable-mdpi/pointer_wait_17.png
new file mode 100644
index 0000000..861605e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_17.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_18.png b/core/res/res/drawable-mdpi/pointer_wait_18.png
new file mode 100644
index 0000000..f5dfdcf
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_18.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_19.png b/core/res/res/drawable-mdpi/pointer_wait_19.png
new file mode 100644
index 0000000..9d51f79
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_19.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_2.png b/core/res/res/drawable-mdpi/pointer_wait_2.png
new file mode 100644
index 0000000..d73a154
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_2.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_20.png b/core/res/res/drawable-mdpi/pointer_wait_20.png
new file mode 100644
index 0000000..81d1d51
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_20.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_21.png b/core/res/res/drawable-mdpi/pointer_wait_21.png
new file mode 100644
index 0000000..331820b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_21.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_22.png b/core/res/res/drawable-mdpi/pointer_wait_22.png
new file mode 100644
index 0000000..2678d32
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_22.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_23.png b/core/res/res/drawable-mdpi/pointer_wait_23.png
new file mode 100644
index 0000000..d54d9eb
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_23.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_24.png b/core/res/res/drawable-mdpi/pointer_wait_24.png
new file mode 100644
index 0000000..442ace7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_24.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_25.png b/core/res/res/drawable-mdpi/pointer_wait_25.png
new file mode 100644
index 0000000..27ce60d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_25.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_26.png b/core/res/res/drawable-mdpi/pointer_wait_26.png
new file mode 100644
index 0000000..8143634
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_26.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_27.png b/core/res/res/drawable-mdpi/pointer_wait_27.png
new file mode 100644
index 0000000..496ab9a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_27.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_28.png b/core/res/res/drawable-mdpi/pointer_wait_28.png
new file mode 100644
index 0000000..a2aab2b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_28.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_29.png b/core/res/res/drawable-mdpi/pointer_wait_29.png
new file mode 100644
index 0000000..646d153
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_29.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_3.png b/core/res/res/drawable-mdpi/pointer_wait_3.png
new file mode 100644
index 0000000..9f45afe
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_3.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_30.png b/core/res/res/drawable-mdpi/pointer_wait_30.png
new file mode 100644
index 0000000..27b3fc4
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_30.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_31.png b/core/res/res/drawable-mdpi/pointer_wait_31.png
new file mode 100644
index 0000000..6dbe184
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_31.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_32.png b/core/res/res/drawable-mdpi/pointer_wait_32.png
new file mode 100644
index 0000000..9f072ef
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_32.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_33.png b/core/res/res/drawable-mdpi/pointer_wait_33.png
new file mode 100644
index 0000000..881ec5f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_33.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_34.png b/core/res/res/drawable-mdpi/pointer_wait_34.png
new file mode 100644
index 0000000..94961e3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_34.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_35.png b/core/res/res/drawable-mdpi/pointer_wait_35.png
new file mode 100644
index 0000000..dfa65d7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_35.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_4.png b/core/res/res/drawable-mdpi/pointer_wait_4.png
new file mode 100644
index 0000000..5d3d652
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_4.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_5.png b/core/res/res/drawable-mdpi/pointer_wait_5.png
new file mode 100644
index 0000000..d440a82
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_5.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_6.png b/core/res/res/drawable-mdpi/pointer_wait_6.png
new file mode 100644
index 0000000..ae65590
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_6.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_7.png b/core/res/res/drawable-mdpi/pointer_wait_7.png
new file mode 100644
index 0000000..cd84aa5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_7.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_8.png b/core/res/res/drawable-mdpi/pointer_wait_8.png
new file mode 100644
index 0000000..0b81a9a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_8.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_9.png b/core/res/res/drawable-mdpi/pointer_wait_9.png
new file mode 100644
index 0000000..c13a90c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_0.png b/core/res/res/drawable-xhdpi/pointer_wait_0.png
new file mode 100644
index 0000000..5396784
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_0.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_1.png b/core/res/res/drawable-xhdpi/pointer_wait_1.png
new file mode 100644
index 0000000..25edbf5
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_1.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_10.png b/core/res/res/drawable-xhdpi/pointer_wait_10.png
new file mode 100644
index 0000000..96d93a9
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_10.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_11.png b/core/res/res/drawable-xhdpi/pointer_wait_11.png
new file mode 100644
index 0000000..cd78675
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_11.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_12.png b/core/res/res/drawable-xhdpi/pointer_wait_12.png
new file mode 100644
index 0000000..1b2c7b2
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_12.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_13.png b/core/res/res/drawable-xhdpi/pointer_wait_13.png
new file mode 100644
index 0000000..3b00f10
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_13.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_14.png b/core/res/res/drawable-xhdpi/pointer_wait_14.png
new file mode 100644
index 0000000..eca5c3f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_14.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_15.png b/core/res/res/drawable-xhdpi/pointer_wait_15.png
new file mode 100644
index 0000000..0fc2085
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_15.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_16.png b/core/res/res/drawable-xhdpi/pointer_wait_16.png
new file mode 100644
index 0000000..db13cf6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_16.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_17.png b/core/res/res/drawable-xhdpi/pointer_wait_17.png
new file mode 100644
index 0000000..9b6fac5
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_17.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_18.png b/core/res/res/drawable-xhdpi/pointer_wait_18.png
new file mode 100644
index 0000000..c56ff6c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_18.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_19.png b/core/res/res/drawable-xhdpi/pointer_wait_19.png
new file mode 100644
index 0000000..22b7c90
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_19.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_2.png b/core/res/res/drawable-xhdpi/pointer_wait_2.png
new file mode 100644
index 0000000..4bdbe3f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_2.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_20.png b/core/res/res/drawable-xhdpi/pointer_wait_20.png
new file mode 100644
index 0000000..6d042fb
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_20.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_21.png b/core/res/res/drawable-xhdpi/pointer_wait_21.png
new file mode 100644
index 0000000..e3ab63f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_21.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_22.png b/core/res/res/drawable-xhdpi/pointer_wait_22.png
new file mode 100644
index 0000000..b25f6b7d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_22.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_23.png b/core/res/res/drawable-xhdpi/pointer_wait_23.png
new file mode 100644
index 0000000..49faba9
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_23.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_24.png b/core/res/res/drawable-xhdpi/pointer_wait_24.png
new file mode 100644
index 0000000..e91c340
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_24.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_25.png b/core/res/res/drawable-xhdpi/pointer_wait_25.png
new file mode 100644
index 0000000..f4785c6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_25.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_26.png b/core/res/res/drawable-xhdpi/pointer_wait_26.png
new file mode 100644
index 0000000..ea902f8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_26.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_27.png b/core/res/res/drawable-xhdpi/pointer_wait_27.png
new file mode 100644
index 0000000..7d628c3
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_27.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_28.png b/core/res/res/drawable-xhdpi/pointer_wait_28.png
new file mode 100644
index 0000000..92d6dc1
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_28.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_29.png b/core/res/res/drawable-xhdpi/pointer_wait_29.png
new file mode 100644
index 0000000..5a8d189
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_29.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_3.png b/core/res/res/drawable-xhdpi/pointer_wait_3.png
new file mode 100644
index 0000000..de4d79c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_3.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_30.png b/core/res/res/drawable-xhdpi/pointer_wait_30.png
new file mode 100644
index 0000000..ba04b5e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_30.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_31.png b/core/res/res/drawable-xhdpi/pointer_wait_31.png
new file mode 100644
index 0000000..3ef8e98
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_31.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_32.png b/core/res/res/drawable-xhdpi/pointer_wait_32.png
new file mode 100644
index 0000000..3297a7d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_32.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_33.png b/core/res/res/drawable-xhdpi/pointer_wait_33.png
new file mode 100644
index 0000000..b0ac3b9
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_33.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_34.png b/core/res/res/drawable-xhdpi/pointer_wait_34.png
new file mode 100644
index 0000000..0eaa386
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_34.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_35.png b/core/res/res/drawable-xhdpi/pointer_wait_35.png
new file mode 100644
index 0000000..73894d8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_35.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_4.png b/core/res/res/drawable-xhdpi/pointer_wait_4.png
new file mode 100644
index 0000000..ea44e85
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_4.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_5.png b/core/res/res/drawable-xhdpi/pointer_wait_5.png
new file mode 100644
index 0000000..46c399d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_5.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_6.png b/core/res/res/drawable-xhdpi/pointer_wait_6.png
new file mode 100644
index 0000000..3b9aff6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_6.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_7.png b/core/res/res/drawable-xhdpi/pointer_wait_7.png
new file mode 100644
index 0000000..a54edc0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_7.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_8.png b/core/res/res/drawable-xhdpi/pointer_wait_8.png
new file mode 100644
index 0000000..2f30732
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_8.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_9.png b/core/res/res/drawable-xhdpi/pointer_wait_9.png
new file mode 100644
index 0000000..f39c7a7
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_9.png
Binary files differ
diff --git a/core/res/res/drawable/pointer_wait.xml b/core/res/res/drawable/pointer_wait.xml
new file mode 100644
index 0000000..8955ce8
--- /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 0000000..d9b03b0
--- /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 90fc22b..0f817f3 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -7631,6 +7631,8 @@
<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 b831df8..eb99077 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1339,6 +1339,7 @@
<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 c31a8b7..8c20ddc 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -101,20 +101,21 @@
*/
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 39b7ecb..4cfbb2a 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 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 b04f16f..96cac7e 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 @@
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 @@
mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
0, 0, viewportWidth, viewportHeight, lightCenter);
- deferImpl(displayList);
+ deferDisplayList(displayList);
}
void OpReorderer::onViewportInitialized() {}
@@ -371,18 +373,99 @@
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 @@
*/
#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 @@
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 @@
// 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 09d5cbc..976f413 100644
--- a/libs/hwui/OpReorderer.h
+++ b/libs/hwui/OpReorderer.h
@@ -190,7 +190,10 @@
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 @@
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 50199db..0736a10 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -276,7 +276,7 @@
}
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 2713f46..716d536 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -524,76 +524,6 @@
}
}
-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 bae5ebe..83d1b58 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -187,9 +187,6 @@
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 0bd5b65..3952798 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -610,7 +610,6 @@
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 a8c9bba..07a1855 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 @@
/**
* 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 @@
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 @@
});
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 @@
OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
createSyncedNodeList(parent), sLightCenter);
-
RenderNodeTestRenderer renderer;
reorderer.replayBakedOps<TestDispatcher>(renderer);
}
@@ -232,7 +229,6 @@
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 @@
});
OpReorderer reorderer(200, 200, *dl, sLightCenter);
-
SaveLayerSimpleTestRenderer renderer;
reorderer.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(4, renderer.getIndex());
@@ -345,7 +340,6 @@
});
OpReorderer reorderer(800, 800, *dl, sLightCenter);
-
SaveLayerNestedTestRenderer renderer;
reorderer.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(10, renderer.getIndex());
@@ -520,7 +514,6 @@
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 @@
});
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
});
}
+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 c9586e4..bd6af78 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -86,6 +86,9 @@
mLocked.pointerIconChanged = false;
mLocked.requestedPointerShape = mPolicy->getDefaultPointerIconId();
+ mLocked.animationFrameIndex = 0;
+ mLocked.lastFrameUpdatedTime = 0;
+
mLocked.buttonState = 0;
loadResources();
@@ -239,7 +242,8 @@
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 @@
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 @@
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 @@
}
}
}
+ return keepAnimating;
+}
- if (keepAnimating) {
- startAnimationLocked();
+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 (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 @@
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 6d840db..b6c01d2 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 @@
SpriteIcon spotAnchor;
};
+struct PointerAnimation {
+ std::vector<SpriteIcon> animationFrames;
+ nsecs_t durationPerFrame;
+};
+
/*
* Pointer controller policy interface.
*
@@ -59,7 +63,8 @@
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 @@
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 @@
bool animationPending;
nsecs_t animationTime;
+ size_t animationFrameIndex;
+ nsecs_t lastFrameUpdatedTime;
+
int32_t displayWidth;
int32_t displayHeight;
int32_t displayOrientation;
@@ -162,7 +170,8 @@
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 @@
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 6bf5721..445ee6f 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 @@
// 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 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 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/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 069279f..d3d9bef 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 @@
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 @@
}
Notification n = notification.getNotification();
+ mNotificationData.updateRanking(ranking);
boolean applyInPlace = !entry.cacheContentViews(mContext, notification.getNotification());
boolean shouldInterrupt = shouldInterrupt(entry, notification);
@@ -2077,7 +2077,6 @@
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 @@
boolean accessibilityForcesLaunch = isFullscreen
&& mAccessibilityManager.isTouchExplorationEnabled();
boolean justLaunchedFullScreenIntent = entry.hasJustLaunchedFullScreenIntent();
-
boolean interrupt = (isFullscreen || (isHighPriority && (isNoisy || hasTicker)))
&& isAllowed
&& !accessibilityForcesLaunch
@@ -2175,7 +2173,8 @@
&& 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 6a90d8e..4328e24 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 @@
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 9ab2a2c..0cddf1d 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 @@
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 c228422..9eb66dd 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -88,6 +88,7 @@
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 @@
}
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/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 025126f..6e6bfb7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17969,7 +17969,7 @@
app.systemNoUi = false;
- final int PROCESS_STATE_TOP = mTopProcessState;
+ final int PROCESS_STATE_CUR_TOP = mTopProcessState;
// Determine the importance of the process, starting with most
// important to least, and assign an appropriate OOM adjustment.
@@ -17984,7 +17984,7 @@
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.adjType = "top-activity";
foregroundActivities = true;
- procState = PROCESS_STATE_TOP;
+ procState = PROCESS_STATE_CUR_TOP;
} else if (app.instrumentationClass != null) {
// Don't want to kill running instrumentation.
adj = ProcessList.FOREGROUND_APP_ADJ;
@@ -18038,8 +18038,8 @@
adj = ProcessList.VISIBLE_APP_ADJ;
app.adjType = "visible";
}
- if (procState > PROCESS_STATE_TOP) {
- procState = PROCESS_STATE_TOP;
+ if (procState > PROCESS_STATE_CUR_TOP) {
+ procState = PROCESS_STATE_CUR_TOP;
}
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.cached = false;
@@ -18057,8 +18057,8 @@
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
app.adjType = "pausing";
}
- if (procState > PROCESS_STATE_TOP) {
- procState = PROCESS_STATE_TOP;
+ if (procState > PROCESS_STATE_CUR_TOP) {
+ procState = PROCESS_STATE_CUR_TOP;
}
schedGroup = Process.THREAD_GROUP_DEFAULT;
app.cached = false;
@@ -18096,7 +18096,8 @@
}
}
- if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+ if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
+ || procState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
if (app.foregroundServices) {
// The user is aware of this app, so make it visible.
adj = ProcessList.PERCEPTIBLE_APP_ADJ;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b84811f..fd1e9dd 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.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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 f37702c..2a7568d 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 @@
private String mGlobalSortKey;
private int mPackageVisibility;
+ private int mSuppressedVisualEffects = 0;
+
@VisibleForTesting
public NotificationRecord(StatusBarNotification sbn, int score)
{
@@ -199,6 +201,7 @@
pw.println(prefix + " mCreationTimeMs=" + mCreationTimeMs);
pw.println(prefix + " mVisibleSinceMs=" + mVisibleSinceMs);
pw.println(prefix + " mUpdateTimeMs=" + mUpdateTimeMs);
+ pw.println(prefix + " mSuppressedVisualEffects= " + mSuppressedVisualEffects);
}
@@ -274,6 +277,14 @@
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 a1f8c41..dbdc3f4 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 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 @@
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 e4dbf65..8fac9da 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 @@
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 64278ed..03fbd19 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 be190cb..b5654ee 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 @@
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 @@
/* --- 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 @@
&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 c743f24..31c3670 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 @@
// 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 @@
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 @@
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 @@
}
}
- 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 0517aef..0000000
--- 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 d19b8c3..0000000
--- 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 223242f..0000000
--- 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
deleted file mode 100644
index e7d1455..0000000
--- a/tests/RenderScriptTests/Fountain/res/drawable/test_pattern.png
+++ /dev/null
Binary files differ
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 311455a..0000000
--- 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 646c807..0000000
--- 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 98cec55..0000000
--- 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 151b689..0000000
--- 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 c0f3323..0000000
--- 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 082744b..0000000
--- 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 5508657..0000000
--- 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
deleted file mode 100644
index e7d1455..0000000
--- a/tests/RenderScriptTests/FountainFbo/res/drawable/test_pattern.png
+++ /dev/null
Binary files differ
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 d8ba30f..0000000
--- 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 3bf3ff1..0000000
--- 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 8636717..0000000
--- 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 763f6ba..0000000
--- 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 ac2690c..0000000
--- 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 fcb4faf..0000000
--- 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 223242f..0000000
--- 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
deleted file mode 100644
index e7d1455..0000000
--- a/tests/RenderScriptTests/Fountain_v11/res/drawable/test_pattern.png
+++ /dev/null
Binary files differ
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 e858100..0000000
--- 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 e82376c..0000000
--- 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 2c07b27..0000000
--- 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 3b6c89a..0000000
--- 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 e206d70..f758959 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 b67afeb..cdcf0ea 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 @@
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 42e55e2..a6e5fb8 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.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 @@
* 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 @@
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 @@
}
}
}
- 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 d50ce23..9c89bfe 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 @@
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 95a5a58..2dc7c65 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 @@
// 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 2a4f583..0ffa357 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 @@
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();