summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/app/INotificationManager.aidl1
-rw-r--r--core/java/android/app/NotificationManager.java12
-rw-r--r--core/java/android/net/IConnectivityManager.aidl3
-rw-r--r--core/java/android/net/INetworkStatsService.aidl4
-rw-r--r--core/java/android/net/NetworkIdentity.java34
-rw-r--r--core/java/android/net/NetworkMisc.java17
-rw-r--r--core/java/android/net/NetworkPolicy.java2
-rw-r--r--core/java/android/net/NetworkState.java7
-rw-r--r--core/java/android/net/NetworkTemplate.java71
-rw-r--r--core/java/android/os/Debug.java5
-rw-r--r--core/java/android/provider/Settings.java10
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java24
-rw-r--r--core/java/android/view/View.java24
-rw-r--r--core/java/android/view/ViewGroup.java105
-rw-r--r--core/java/android/view/accessibility/AccessibilityCache.java1
-rw-r--r--core/java/android/widget/AbsListView.java69
-rw-r--r--core/java/android/widget/HorizontalScrollView.java15
-rw-r--r--core/java/android/widget/ListPopupWindow.java8
-rw-r--r--core/java/android/widget/RadialTimePickerView.java39
-rw-r--r--core/java/android/widget/Switch.java4
-rw-r--r--core/java/com/android/internal/util/ArrayUtils.java15
21 files changed, 356 insertions, 114 deletions
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index bdcff38..88b9080 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -71,6 +71,7 @@ interface INotificationManager
ComponentName getEffectsSuppressor();
boolean matchesCallFilter(in Bundle extras);
+ boolean isSystemConditionProviderEnabled(String path);
ZenModeConfig getZenModeConfig();
boolean setZenModeConfig(in ZenModeConfig config);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 7dc1ad6..cf54107 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -264,5 +264,17 @@ public class NotificationManager
}
}
+ /**
+ * @hide
+ */
+ public boolean isSystemConditionProviderEnabled(String path) {
+ INotificationManager service = getService();
+ try {
+ return service.isSystemConditionProviderEnabled(path);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
private Context mContext;
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 8021210..d9921a6 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -68,9 +68,6 @@ interface IConnectivityManager
boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress);
- /** Policy control over specific {@link NetworkStateTracker}. */
- void setPolicyDataEnable(int networkType, boolean enabled);
-
int tether(String iface);
int untether(String iface);
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index b7b8731..2c3881c 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -40,8 +40,12 @@ interface INetworkStatsService {
/** Mark given UID as being in foreground for stats purposes. */
void setUidForeground(int uid, boolean uidForeground);
+
+ /** Force update of ifaces. */
+ void forceUpdateIfaces();
/** Force update of statistics. */
void forceUpdate();
+
/** Advise persistance threshold; may be overridden internally. */
void advisePersistThreshold(long thresholdBytes);
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index d36707e..a9de23e 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -25,6 +25,7 @@ import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.telephony.TelephonyManager;
+import android.util.Slog;
import java.util.Objects;
@@ -35,10 +36,16 @@ import java.util.Objects;
* @hide
*/
public class NetworkIdentity implements Comparable<NetworkIdentity> {
+ private static final String TAG = "NetworkIdentity";
+
/**
* When enabled, combine all {@link #mSubType} together under
* {@link #SUBTYPE_COMBINED}.
+ *
+ * @deprecated we no longer offer to collect statistics on a per-subtype
+ * basis; this is always disabled.
*/
+ @Deprecated
public static final boolean COMBINE_SUBTYPE_ENABLED = true;
public static final int SUBTYPE_COMBINED = -1;
@@ -133,6 +140,18 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
}
/**
+ * Scrub given IMSI on production builds.
+ */
+ public static String[] scrubSubscriberId(String[] subscriberId) {
+ if (subscriberId == null) return null;
+ final String[] res = new String[subscriberId.length];
+ for (int i = 0; i < res.length; i++) {
+ res[i] = NetworkIdentity.scrubSubscriberId(subscriberId[i]);
+ }
+ return res;
+ }
+
+ /**
* Build a {@link NetworkIdentity} from the given {@link NetworkState},
* assuming that any mobile networks are using the current IMSI.
*/
@@ -140,23 +159,18 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
final int type = state.networkInfo.getType();
final int subType = state.networkInfo.getSubtype();
- // TODO: consider moving subscriberId over to LinkCapabilities, so it
- // comes from an authoritative source.
-
String subscriberId = null;
String networkId = null;
boolean roaming = false;
if (isNetworkTypeMobile(type)) {
- final TelephonyManager telephony = (TelephonyManager) context.getSystemService(
- Context.TELEPHONY_SERVICE);
- roaming = telephony.isNetworkRoaming();
- if (state.subscriberId != null) {
- subscriberId = state.subscriberId;
- } else {
- subscriberId = telephony.getSubscriberId();
+ if (state.subscriberId == null) {
+ Slog.w(TAG, "Active mobile network without subscriber!");
}
+ subscriberId = state.subscriberId;
+ roaming = state.networkInfo.isRoaming();
+
} else if (type == TYPE_WIFI) {
if (state.networkId != null) {
networkId = state.networkId;
diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java
index 5d2a43d..b92c9e3 100644
--- a/core/java/android/net/NetworkMisc.java
+++ b/core/java/android/net/NetworkMisc.java
@@ -20,15 +20,18 @@ import android.os.Parcel;
import android.os.Parcelable;
/**
- * A grab-bag of information (metadata, policies, properties, etc) about a {@link Network}.
+ * A grab-bag of information (metadata, policies, properties, etc) about a
+ * {@link Network}. Since this contains PII, it should not be sent outside the
+ * system.
*
* @hide
*/
public class NetworkMisc implements Parcelable {
/**
- * If the {@link Network} is a VPN, whether apps are allowed to bypass the VPN. This is set by
- * a {@link VpnService} and used by {@link ConnectivityService} when creating a VPN.
+ * If the {@link Network} is a VPN, whether apps are allowed to bypass the
+ * VPN. This is set by a {@link VpnService} and used by
+ * {@link ConnectivityManager} when creating a VPN.
*/
public boolean allowBypass;
@@ -41,6 +44,11 @@ public class NetworkMisc implements Parcelable {
*/
public boolean explicitlySelected;
+ /**
+ * For mobile networks, this is the subscriber ID (such as IMSI).
+ */
+ public String subscriberId;
+
public NetworkMisc() {
}
@@ -48,6 +56,7 @@ public class NetworkMisc implements Parcelable {
if (nm != null) {
allowBypass = nm.allowBypass;
explicitlySelected = nm.explicitlySelected;
+ subscriberId = nm.subscriberId;
}
}
@@ -60,6 +69,7 @@ public class NetworkMisc implements Parcelable {
public void writeToParcel(Parcel out, int flags) {
out.writeInt(allowBypass ? 1 : 0);
out.writeInt(explicitlySelected ? 1 : 0);
+ out.writeString(subscriberId);
}
public static final Creator<NetworkMisc> CREATOR = new Creator<NetworkMisc>() {
@@ -68,6 +78,7 @@ public class NetworkMisc implements Parcelable {
NetworkMisc networkMisc = new NetworkMisc();
networkMisc.allowBypass = in.readInt() != 0;
networkMisc.explicitlySelected = in.readInt() != 0;
+ networkMisc.subscriberId = in.readString();
return networkMisc;
}
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index 10c686b..e88bc26 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -35,7 +35,7 @@ public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
public static final long LIMIT_DISABLED = -1;
public static final long SNOOZE_NEVER = -1;
- public final NetworkTemplate template;
+ public NetworkTemplate template;
public int cycleDay;
public String cycleTimezone;
public long warningBytes;
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index d26c70d..933287f 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -30,16 +30,10 @@ public class NetworkState implements Parcelable {
public final LinkProperties linkProperties;
public final NetworkCapabilities networkCapabilities;
public final Network network;
- /** Currently only used by testing. */
public final String subscriberId;
public final String networkId;
public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties,
- NetworkCapabilities networkCapabilities, Network network) {
- this(networkInfo, linkProperties, networkCapabilities, network, null, null);
- }
-
- public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties,
NetworkCapabilities networkCapabilities, Network network, String subscriberId,
String networkId) {
this.networkInfo = networkInfo;
@@ -85,5 +79,4 @@ public class NetworkState implements Parcelable {
return new NetworkState[size];
}
};
-
}
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index b839e0a..57eef83 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -22,7 +22,6 @@ import static android.net.ConnectivityManager.TYPE_WIFI;
import static android.net.ConnectivityManager.TYPE_WIFI_P2P;
import static android.net.ConnectivityManager.TYPE_WIMAX;
import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED;
-import static android.net.NetworkIdentity.scrubSubscriberId;
import static android.net.wifi.WifiInfo.removeDoubleQuotes;
import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G;
import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G;
@@ -36,7 +35,9 @@ import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+import java.util.Arrays;
import java.util.Objects;
/**
@@ -48,7 +49,9 @@ import java.util.Objects;
public class NetworkTemplate implements Parcelable {
public static final int MATCH_MOBILE_ALL = 1;
+ @Deprecated
public static final int MATCH_MOBILE_3G_LOWER = 2;
+ @Deprecated
public static final int MATCH_MOBILE_4G = 3;
public static final int MATCH_WIFI = 4;
public static final int MATCH_ETHERNET = 5;
@@ -146,17 +149,35 @@ public class NetworkTemplate implements Parcelable {
private final int mMatchRule;
private final String mSubscriberId;
+
+ /**
+ * Ugh, templates are designed to target a single subscriber, but we might
+ * need to match several "merged" subscribers. These are the subscribers
+ * that should be considered to match this template.
+ * <p>
+ * Since the merge set is dynamic, it should <em>not</em> be persisted or
+ * used for determining equality.
+ */
+ private final String[] mMatchSubscriberIds;
+
private final String mNetworkId;
public NetworkTemplate(int matchRule, String subscriberId, String networkId) {
+ this(matchRule, subscriberId, new String[] { subscriberId }, networkId);
+ }
+
+ public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
+ String networkId) {
mMatchRule = matchRule;
mSubscriberId = subscriberId;
+ mMatchSubscriberIds = matchSubscriberIds;
mNetworkId = networkId;
}
private NetworkTemplate(Parcel in) {
mMatchRule = in.readInt();
mSubscriberId = in.readString();
+ mMatchSubscriberIds = in.createStringArray();
mNetworkId = in.readString();
}
@@ -164,6 +185,7 @@ public class NetworkTemplate implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mMatchRule);
dest.writeString(mSubscriberId);
+ dest.writeStringArray(mMatchSubscriberIds);
dest.writeString(mNetworkId);
}
@@ -177,7 +199,12 @@ public class NetworkTemplate implements Parcelable {
final StringBuilder builder = new StringBuilder("NetworkTemplate: ");
builder.append("matchRule=").append(getMatchRuleName(mMatchRule));
if (mSubscriberId != null) {
- builder.append(", subscriberId=").append(scrubSubscriberId(mSubscriberId));
+ builder.append(", subscriberId=").append(
+ NetworkIdentity.scrubSubscriberId(mSubscriberId));
+ }
+ if (mMatchSubscriberIds != null) {
+ builder.append(", matchSubscriberIds=").append(
+ Arrays.toString(NetworkIdentity.scrubSubscriberId(mMatchSubscriberIds)));
}
if (mNetworkId != null) {
builder.append(", networkId=").append(mNetworkId);
@@ -201,6 +228,18 @@ public class NetworkTemplate implements Parcelable {
return false;
}
+ public boolean isMatchRuleMobile() {
+ switch (mMatchRule) {
+ case MATCH_MOBILE_3G_LOWER:
+ case MATCH_MOBILE_4G:
+ case MATCH_MOBILE_ALL:
+ case MATCH_MOBILE_WILDCARD:
+ return true;
+ default:
+ return false;
+ }
+ }
+
public int getMatchRule() {
return mMatchRule;
}
@@ -247,14 +286,16 @@ public class NetworkTemplate implements Parcelable {
// TODO: consider matching against WiMAX subscriber identity
return true;
} else {
- return ((sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType))
- && Objects.equals(mSubscriberId, ident.mSubscriberId));
+ final boolean matchesType = (sForceAllNetworkTypes
+ || contains(DATA_USAGE_NETWORK_TYPES, ident.mType));
+ return matchesType && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId);
}
}
/**
* Check if mobile network classified 3G or lower with matching IMSI.
*/
+ @Deprecated
private boolean matchesMobile3gLower(NetworkIdentity ident) {
ensureSubtypeAvailable();
if (ident.mType == TYPE_WIMAX) {
@@ -273,6 +314,7 @@ public class NetworkTemplate implements Parcelable {
/**
* Check if mobile network classified 4G with matching IMSI.
*/
+ @Deprecated
private boolean matchesMobile4g(NetworkIdentity ident) {
ensureSubtypeAvailable();
if (ident.mType == TYPE_WIMAX) {
@@ -368,6 +410,27 @@ public class NetworkTemplate implements Parcelable {
}
}
+ /**
+ * Examine the given template and normalize if it refers to a "merged"
+ * mobile subscriber. We pick the "lowest" merged subscriber as the primary
+ * for key purposes, and expand the template to match all other merged
+ * subscribers.
+ * <p>
+ * For example, given an incoming template matching B, and the currently
+ * active merge set [A,B], we'd return a new template that primarily matches
+ * A, but also matches B.
+ */
+ public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) {
+ if (template.isMatchRuleMobile() && ArrayUtils.contains(merged, template.mSubscriberId)) {
+ // Requested template subscriber is part of the merge group; return
+ // a template that matches all merged subscribers.
+ return new NetworkTemplate(template.mMatchRule, merged[0], merged,
+ template.mNetworkId);
+ } else {
+ return template;
+ }
+ }
+
public static final Creator<NetworkTemplate> CREATOR = new Creator<NetworkTemplate>() {
@Override
public NetworkTemplate createFromParcel(Parcel in) {
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index a241c3a..a9deaf3 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -168,7 +168,7 @@ public final class Debug
public static final int NUM_OTHER_STATS = 17;
/** @hide */
- public static final int NUM_DVK_STATS = 5;
+ public static final int NUM_DVK_STATS = 8;
/** @hide */
public static final int NUM_CATEGORIES = 7;
@@ -314,6 +314,9 @@ public final class Debug
case 19: return ".LinearAlloc";
case 20: return ".GC";
case 21: return ".JITCache";
+ case 22: return ".Zygote";
+ case 23: return ".NonMoving";
+ case 24: return ".IndirectRef";
default: return "????";
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0c036d51..0062eb2 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4349,6 +4349,16 @@ public final class Settings {
Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS;
/**
+ * The number of milliseconds to hold on to a PendingIntent based request. This delay gives
+ * the receivers of the PendingIntent an opportunity to make a new network request before
+ * the Network satisfying the request is potentially removed.
+ *
+ * @hide
+ */
+ public static final String CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS =
+ "connectivity_release_pending_intent_delay_ms";
+
+ /**
* Whether background data usage is allowed.
*
* @deprecated As of {@link VERSION_CODES#ICE_CREAM_SANDWICH},
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index ce28d0a..979a01b 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -64,7 +64,7 @@ public class ZenModeConfig implements Parcelable {
public static final int[] MINUTE_BUCKETS = new int[] { 15, 30, 45, 60, 120, 180, 240, 480 };
private static final int SECONDS_MS = 1000;
private static final int MINUTES_MS = 60 * SECONDS_MS;
- private static final int ZERO_VALUE_MS = 20 * SECONDS_MS;
+ private static final int ZERO_VALUE_MS = 10 * SECONDS_MS;
private static final boolean DEFAULT_ALLOW_EVENTS = true;
@@ -471,6 +471,8 @@ public class ZenModeConfig implements Parcelable {
downtime.startMinute = sleepStartMinute;
downtime.endHour = sleepEndHour;
downtime.endMinute = sleepEndMinute;
+ downtime.mode = sleepMode;
+ downtime.none = sleepNone;
return downtime;
}
@@ -510,7 +512,7 @@ public class ZenModeConfig implements Parcelable {
public static final String SYSTEM_AUTHORITY = "android";
// Built-in countdown conditions, e.g. condition://android/countdown/1399917958951
- private static final String COUNTDOWN_PATH = "countdown";
+ public static final String COUNTDOWN_PATH = "countdown";
public static Uri toCountdownConditionId(long time) {
return new Uri.Builder().scheme(Condition.SCHEME)
@@ -536,8 +538,9 @@ public class ZenModeConfig implements Parcelable {
return tryParseCountdownConditionId(conditionId) != 0;
}
- // Built-in downtime conditions, e.g. condition://android/downtime?start=10.00&end=7.00
- private static final String DOWNTIME_PATH = "downtime";
+ // Built-in downtime conditions
+ // e.g. condition://android/downtime?start=10.00&end=7.00&mode=days%3A5%2C6&none=false
+ public static final String DOWNTIME_PATH = "downtime";
public static Uri toDowntimeConditionId(DowntimeInfo downtime) {
return new Uri.Builder().scheme(Condition.SCHEME)
@@ -545,6 +548,8 @@ public class ZenModeConfig implements Parcelable {
.appendPath(DOWNTIME_PATH)
.appendQueryParameter("start", downtime.startHour + "." + downtime.startMinute)
.appendQueryParameter("end", downtime.endHour + "." + downtime.endMinute)
+ .appendQueryParameter("mode", downtime.mode)
+ .appendQueryParameter("none", Boolean.toString(downtime.none))
.build();
}
@@ -562,6 +567,8 @@ public class ZenModeConfig implements Parcelable {
downtime.startMinute = start[1];
downtime.endHour = end[0];
downtime.endMinute = end[1];
+ downtime.mode = conditionId.getQueryParameter("mode");
+ downtime.none = Boolean.toString(true).equals(conditionId.getQueryParameter("none"));
return downtime;
}
@@ -583,6 +590,8 @@ public class ZenModeConfig implements Parcelable {
public int startMinute; // 0-59
public int endHour;
public int endMinute;
+ public String mode;
+ public boolean none;
@Override
public int hashCode() {
@@ -596,7 +605,12 @@ public class ZenModeConfig implements Parcelable {
return startHour == other.startHour
&& startMinute == other.startMinute
&& endHour == other.endHour
- && endMinute == other.endMinute;
+ && endMinute == other.endMinute
+ && Objects.equals(mode, other.mode)
+ && none == other.none;
}
}
+
+ // built-in next alarm conditions
+ public static final String NEXT_ALARM_PATH = "next_alarm";
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index b54d462..2bb1ebc 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5938,9 +5938,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* layer.
*
* @param outRects List to which to add clickable areas.
+ *
+ * @hide
*/
- void addClickableRectsForAccessibility(List<RectF> outRects) {
- if (isClickable() || isLongClickable()) {
+ public void addClickableRectsForAccessibility(List<RectF> outRects) {
+ if (isClickable() || isLongClickable()
+ || (mListenerInfo != null && mListenerInfo.mOnTouchListener != null)) {
RectF bounds = new RectF();
bounds.set(0, 0, getWidth(), getHeight());
outRects.add(bounds);
@@ -16059,7 +16062,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* This function is called whenever the view hotspot changes and needs to
- * be propagated to drawables managed by the view.
+ * be propagated to drawables or child views managed by the view.
+ * <p>
+ * Dispatching to child views is handled by
+ * {@link #dispatchDrawableHotspotChanged(float, float)}.
* <p>
* Be sure to call through to the superclass when overriding this function.
*
@@ -16070,6 +16076,18 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (mBackground != null) {
mBackground.setHotspot(x, y);
}
+
+ dispatchDrawableHotspotChanged(x, y);
+ }
+
+ /**
+ * Dispatches drawableHotspotChanged to all of this View's children.
+ *
+ * @param x hotspot x coordinate
+ * @param y hotspot y coordinate
+ * @see #drawableHotspotChanged(float, float)
+ */
+ public void dispatchDrawableHotspotChanged(float x, float y) {
}
/**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 1551504..25a70eb 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -161,6 +161,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
// Used during drag dispatch
private PointF mLocalPoint;
+ // Lazily-created holder for point computations.
+ private float[] mTempPoint;
+
// Layout animation
private LayoutAnimationController mLayoutAnimationController;
private Animation.AnimationListener mAnimationListener;
@@ -880,8 +883,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
return true;
}
+ /**
+ * @hide
+ */
@Override
- void addClickableRectsForAccessibility(List<RectF> outRects) {
+ public void addClickableRectsForAccessibility(List<RectF> outRects) {
int sizeBefore = outRects.size();
super.addClickableRectsForAccessibility(outRects);
@@ -2442,6 +2448,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
|| child.getAnimation() != null;
}
+ private float[] getTempPoint() {
+ if (mTempPoint == null) {
+ mTempPoint = new float[2];
+ }
+ return mTempPoint;
+ }
+
/**
* Returns true if a child view contains the specified point when transformed
* into its coordinate space.
@@ -2450,24 +2463,30 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
protected boolean isTransformedTouchPointInView(float x, float y, View child,
PointF outLocalPoint) {
- float localX = x + mScrollX - child.mLeft;
- float localY = y + mScrollY - child.mTop;
- if (! child.hasIdentityMatrix() && mAttachInfo != null) {
- final float[] localXY = mAttachInfo.mTmpTransformLocation;
- localXY[0] = localX;
- localXY[1] = localY;
- child.getInverseMatrix().mapPoints(localXY);
- localX = localXY[0];
- localY = localXY[1];
- }
- final boolean isInView = child.pointInView(localX, localY);
+ final float[] point = getTempPoint();
+ point[0] = x;
+ point[1] = y;
+ transformPointToViewLocal(point, child);
+ final boolean isInView = child.pointInView(point[0], point[1]);
if (isInView && outLocalPoint != null) {
- outLocalPoint.set(localX, localY);
+ outLocalPoint.set(point[0], point[1]);
}
return isInView;
}
/**
+ * @hide
+ */
+ public void transformPointToViewLocal(float[] point, View child) {
+ point[0] += mScrollX - child.mLeft;
+ point[1] += mScrollY - child.mTop;
+
+ if (!child.hasIdentityMatrix()) {
+ child.getInverseMatrix().mapPoints(point);
+ }
+ }
+
+ /**
* Transforms a motion event into the coordinate space of a particular child view,
* filters out irrelevant pointer ids, and overrides its action if necessary.
* If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
@@ -3606,6 +3625,44 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
}
+ /**
+ * Dispatches drawable hotspot changes to child views that meet at least
+ * one of the following criteria:
+ * <ul>
+ * <li>Returns {@code false} from both {@link View#isClickable()} and
+ * {@link View#isLongClickable()}</li>
+ * <li>Requests duplication of parent state via
+ * {@link View#setDuplicateParentStateEnabled(boolean)}</li>
+ * </ul>
+ *
+ * @param x hotspot x coordinate
+ * @param y hotspot y coordinate
+ * @see #drawableHotspotChanged(float, float)
+ */
+ @Override
+ public void dispatchDrawableHotspotChanged(float x, float y) {
+ final int count = mChildrenCount;
+ if (count == 0) {
+ return;
+ }
+
+ final View[] children = mChildren;
+ for (int i = 0; i < count; i++) {
+ final View child = children[i];
+ // Children that are clickable on their own should not
+ // receive hotspots when their parent view does.
+ final boolean nonActionable = !child.isClickable() && !child.isLongClickable();
+ final boolean duplicatesState = (child.mViewFlags & DUPLICATE_PARENT_STATE) != 0;
+ if (nonActionable || duplicatesState) {
+ final float[] point = getTempPoint();
+ point[0] = x;
+ point[1] = y;
+ transformPointToViewLocal(point, child);
+ child.drawableHotspotChanged(point[0], point[1]);
+ }
+ }
+ }
+
@Override
void dispatchCancelPendingInputEvents() {
super.dispatchCancelPendingInputEvents();
@@ -5961,28 +6018,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
}
@Override
- public void drawableHotspotChanged(float x, float y) {
- super.drawableHotspotChanged(x, y);
-
- if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
- if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
- throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
- + " child has duplicateParentState set to true");
- }
-
- final View[] children = mChildren;
- final int count = mChildrenCount;
-
- for (int i = 0; i < count; i++) {
- final View child = children[i];
- if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
- child.drawableHotspotChanged(x, y);
- }
- }
- }
- }
-
- @Override
protected int[] onCreateDrawableState(int extraSpace) {
if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
return super.onCreateDrawableState(extraSpace);
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java
index a218e4d..52912b1 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -78,6 +78,7 @@ final class AccessibilityCache {
case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED:
case AccessibilityEvent.TYPE_VIEW_SELECTED:
case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
+ case AccessibilityEvent.TYPE_VIEW_CLICKED:
case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: {
refreshCachedNodeLocked(event.getWindowId(), event.getSourceNodeId());
} break;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 6927660..d80ad6a 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
@@ -611,6 +612,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
private final int[] mScrollOffset = new int[2];
private final int[] mScrollConsumed = new int[2];
+ private final float[] mTmpPoint = new float[2];
+
// Used for offsetting MotionEvents that we feed to the VelocityTracker.
// In the future it would be nice to be able to give this to the VelocityTracker
// directly, or alternatively put a VT into absolute-positioning mode that only
@@ -2509,38 +2512,29 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
* Positions the selector in a way that mimics touch.
*/
void positionSelectorLikeTouch(int position, View sel, float x, float y) {
- positionSelectorLikeFocus(position, sel);
-
- if (mSelector != null && position != INVALID_POSITION) {
- mSelector.setHotspot(x, y);
- }
+ positionSelector(position, sel, true, x, y);
}
/**
* Positions the selector in a way that mimics keyboard focus.
*/
void positionSelectorLikeFocus(int position, View sel) {
- // If we're changing position, update the visibility since the selector
- // is technically being detached from the previous selection.
- final Drawable selector = mSelector;
- final boolean manageState = selector != null && mSelectorPosition != position
- && position != INVALID_POSITION;
- if (manageState) {
- selector.setVisible(false, false);
- }
-
- positionSelector(position, sel);
-
- if (manageState) {
+ if (mSelector != null && mSelectorPosition != position && position != INVALID_POSITION) {
final Rect bounds = mSelectorRect;
final float x = bounds.exactCenterX();
final float y = bounds.exactCenterY();
- selector.setVisible(getVisibility() == VISIBLE, false);
- selector.setHotspot(x, y);
+ positionSelector(position, sel, true, x, y);
+ } else {
+ positionSelector(position, sel);
}
}
void positionSelector(int position, View sel) {
+ positionSelector(position, sel, false, -1, -1);
+ }
+
+ private void positionSelector(int position, View sel, boolean manageHotspot, float x, float y) {
+ final boolean positionChanged = position != mSelectorPosition;
if (position != INVALID_POSITION) {
mSelectorPosition = position;
}
@@ -2560,7 +2554,22 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
// Update the selector drawable.
final Drawable selector = mSelector;
if (selector != null) {
+ if (positionChanged) {
+ // Wipe out the current selector state so that we can start
+ // over in the new position with a fresh state.
+ selector.setVisible(false, false);
+ selector.setState(StateSet.NOTHING);
+ }
selector.setBounds(selectorRect);
+ if (positionChanged) {
+ if (getVisibility() == VISIBLE) {
+ selector.setVisible(true, false);
+ }
+ selector.setState(getDrawableState());
+ }
+ if (manageHotspot) {
+ selector.setHotspot(x, y);
+ }
}
final boolean isChildViewEnabled = mIsChildViewEnabled;
@@ -3198,6 +3207,12 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
// get the selector in the right state, but we don't want to press each child.
}
+ @Override
+ public void dispatchDrawableHotspotChanged(float x, float y) {
+ // Don't dispatch hotspot changes to children. We'll manually handle
+ // calling drawableHotspotChanged on the correct child.
+ }
+
/**
* Maps a point to a position in the list.
*
@@ -3256,6 +3271,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mLayoutMode = LAYOUT_NORMAL;
if (!mDataChanged) {
+ final float[] point = mTmpPoint;
+ point[0] = x;
+ point[1] = y;
+ transformPointToViewLocal(point, child);
+ child.drawableHotspotChanged(point[0], point[1]);
child.setPressed(true);
setPressed(true);
layoutChildren();
@@ -3756,10 +3776,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
// Otherwise, check containment within list bounds. If we're
// outside bounds, cancel any active presses.
+ final View motionView = getChildAt(mMotionPosition - mFirstPosition);
final float x = ev.getX(pointerIndex);
if (!pointInView(x, y, mTouchSlop)) {
setPressed(false);
- final View motionView = getChildAt(mMotionPosition - mFirstPosition);
if (motionView != null) {
motionView.setPressed(false);
}
@@ -3767,6 +3787,13 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
mPendingCheckForTap : mPendingCheckForLongPress);
mTouchMode = TOUCH_MODE_DONE_WAITING;
updateSelectorState();
+ } else if (motionView != null) {
+ // Still within bounds, update the hotspot.
+ final float[] point = mTmpPoint;
+ point[0] = x;
+ point[1] = y;
+ transformPointToViewLocal(point, motionView);
+ motionView.drawableHotspotChanged(point[0], point[1]);
}
break;
case TOUCH_MODE_SCROLL:
@@ -6416,6 +6443,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
// Note: We do place AdapterView.ITEM_VIEW_TYPE_IGNORE in active views.
// However, we will NOT place them into scrap views.
activeViews[i] = child;
+ // Remember the position so that setupChild() doesn't reset state.
+ lp.scrappedFromPosition = firstActivePosition + i;
}
}
}
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 0c65c50..371b480 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
@@ -757,10 +758,22 @@ public class HorizontalScrollView extends FrameLayout {
} else {
super.scrollTo(scrollX, scrollY);
}
-
+
awakenScrollBars();
}
+ /**
+ * @hide
+ */
+ @Override
+ public void addClickableRectsForAccessibility(List<RectF> outRects) {
+ // This class always consumes touch events, therefore if it
+ // covers a view we do not want to send a click over it.
+ RectF bounds = new RectF();
+ bounds.set(0, 0, getWidth(), getHeight());
+ outRects.add(bounds);
+ }
+
@Override
public boolean performAccessibilityAction(int action, Bundle arguments) {
if (super.performAccessibilityAction(action, arguments)) {
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index a31d37e..fe8b08b 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -1385,7 +1385,9 @@ public class ListPopupWindow {
clearCallbacks();
final View src = mSrc;
- if (!src.isEnabled()) {
+ if (!src.isEnabled() || src.isLongClickable()) {
+ // Ignore long-press if the view is disabled or has its own
+ // handler.
return;
}
@@ -1394,12 +1396,12 @@ public class ListPopupWindow {
}
// Don't let the parent intercept our events.
- mSrc.getParent().requestDisallowInterceptTouchEvent(true);
+ src.getParent().requestDisallowInterceptTouchEvent(true);
// Make sure we cancel any ongoing source event stream.
final long now = SystemClock.uptimeMillis();
final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0);
- mSrc.onTouchEvent(e);
+ src.onTouchEvent(e);
e.recycle();
mForwarding = true;
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index 04b5616..75c6184 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -1246,37 +1246,40 @@ public class RadialTimePickerView extends View implements View.OnTouchListener {
}
final int[] selectionDegrees = mSelectionDegrees;
- int type = -1;
- int newValue = -1;
+ final int type;
+ final int newValue;
+ final boolean valueChanged;
if (mShowHours) {
final int snapDegrees = snapOnly30s(degrees, 0) % 360;
- if (forceSelection
- || selectionDegrees[HOURS] != snapDegrees
+ valueChanged = selectionDegrees[HOURS] != snapDegrees
|| selectionDegrees[HOURS_INNER] != snapDegrees
- || wasOnInnerCircle != mIsOnInnerCircle) {
- selectionDegrees[HOURS] = snapDegrees;
- selectionDegrees[HOURS_INNER] = snapDegrees;
+ || wasOnInnerCircle != mIsOnInnerCircle;
- type = HOURS;
- newValue = getCurrentHour();
- }
+ selectionDegrees[HOURS] = snapDegrees;
+ selectionDegrees[HOURS_INNER] = snapDegrees;
+ type = HOURS;
+ newValue = getCurrentHour();
} else {
final int snapDegrees = snapPrefer30s(degrees) % 360;
- if (forceSelection || selectionDegrees[MINUTES] != snapDegrees) {
- selectionDegrees[MINUTES] = snapDegrees;
+ valueChanged = selectionDegrees[MINUTES] != snapDegrees;
- type = MINUTES;
- newValue = getCurrentMinute();
- }
+ selectionDegrees[MINUTES] = snapDegrees;
+ type = MINUTES;
+ newValue = getCurrentMinute();
}
- if (newValue != -1) {
+ if (valueChanged || forceSelection || autoAdvance) {
+ // Fire the listener even if we just need to auto-advance.
if (mListener != null) {
mListener.onValueSelected(type, newValue, autoAdvance);
}
- performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
- invalidate();
+
+ // Only provide feedback if the value actually changed.
+ if (valueChanged || forceSelection) {
+ performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
+ invalidate();
+ }
return true;
}
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 4c8aa51..7a22224 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -689,6 +689,10 @@ public class Switch extends CompoundButton {
* @return true if (x, y) is within the target area of the switch thumb
*/
private boolean hitThumb(float x, float y) {
+ if (mThumbDrawable == null) {
+ return false;
+ }
+
// Relies on mTempRect, MUST be called first!
final int thumbOffset = getThumbOffset();
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 8e786da..f908fcb 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -128,6 +128,20 @@ public class ArrayUtils
}
/**
+ * Checks if given array is null or has zero elements.
+ */
+ public static boolean isEmpty(int[] array) {
+ return array == null || array.length == 0;
+ }
+
+ /**
+ * Checks if given array is null or has zero elements.
+ */
+ public static boolean isEmpty(long[] array) {
+ return array == null || array.length == 0;
+ }
+
+ /**
* Checks that value is present as at least one of the elements of the array.
* @param array the array to check in
* @param value the value to check for
@@ -157,6 +171,7 @@ public class ArrayUtils
* Test if all {@code check} items are contained in {@code array}.
*/
public static <T> boolean containsAll(T[] array, T[] check) {
+ if (check == null) return true;
for (T checkItem : check) {
if (!contains(array, checkItem)) {
return false;