Merge "TIF: Add Builder to TvInputInfo and deprecate createTvInputInfo methods"
diff --git a/Android.mk b/Android.mk
index 53e892f..1d797c4 100644
--- a/Android.mk
+++ b/Android.mk
@@ -417,7 +417,6 @@
telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
wifi/java/android/net/wifi/IWifiManager.aidl \
- wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl \
wifi/java/android/net/wifi/nan/IWifiNanEventListener.aidl \
wifi/java/android/net/wifi/nan/IWifiNanManager.aidl \
wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl \
@@ -430,6 +429,14 @@
core/java/android/service/quicksettings/IQSService.aidl \
core/java/android/service/quicksettings/IQSTileService.aidl \
+# The following are native binders that need to go with the native component
+# at system/update_engine/binder_bindings/. Use relative path to refer to them.
+LOCAL_SRC_FILES += \
+ ../../system/update_engine/binder_bindings/android/os/IUpdateEngine.aidl \
+ ../../system/update_engine/binder_bindings/android/os/IUpdateEngineCallback.aidl \
+
+LOCAL_AIDL_INCLUDES += system/update_engine/binder_bindings
+
# FRAMEWORKS_BASE_JAVA_SRC_DIRS comes from build/core/pathmap.mk
LOCAL_AIDL_INCLUDES += \
$(FRAMEWORKS_BASE_JAVA_SRC_DIRS) \
diff --git a/api/current.txt b/api/current.txt
index 5f8c706..ee69bfa 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -67,7 +67,7 @@
field public static final java.lang.String DUMP = "android.permission.DUMP";
field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
- field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
+ field public static final deprecated java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
@@ -10108,7 +10108,6 @@
method public java.lang.String getQuantityString(int, int, java.lang.Object...) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getQuantityString(int, int) throws android.content.res.Resources.NotFoundException;
method public java.lang.CharSequence getQuantityText(int, int) throws android.content.res.Resources.NotFoundException;
- method public java.util.Locale getResolvedLocale();
method public java.lang.String getResourceEntryName(int) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getResourceName(int) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getResourcePackageName(int) throws android.content.res.Resources.NotFoundException;
@@ -13841,6 +13840,7 @@
field public static final int HOT_PIXEL_MODE_FAST = 1; // 0x1
field public static final int HOT_PIXEL_MODE_HIGH_QUALITY = 2; // 0x2
field public static final int HOT_PIXEL_MODE_OFF = 0; // 0x0
+ field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_3 = 3; // 0x3
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1; // 0x1
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2; // 0x2
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0; // 0x0
@@ -20857,6 +20857,7 @@
field public static final int DEFAULT = 0; // 0x0
field public static final int H263 = 1; // 0x1
field public static final int H264 = 2; // 0x2
+ field public static final int HEVC = 5; // 0x5
field public static final int MPEG_4_SP = 3; // 0x3
field public static final int VP8 = 4; // 0x4
}
@@ -23962,6 +23963,7 @@
method public java.lang.String getAltSubjectMatch();
method public java.lang.String getAnonymousIdentity();
method public java.security.cert.X509Certificate getCaCertificate();
+ method public java.security.cert.X509Certificate[] getCaCertificates();
method public java.security.cert.X509Certificate getClientCertificate();
method public java.lang.String getDomainSuffixMatch();
method public int getEapMethod();
@@ -23974,6 +23976,7 @@
method public void setAltSubjectMatch(java.lang.String);
method public void setAnonymousIdentity(java.lang.String);
method public void setCaCertificate(java.security.cert.X509Certificate);
+ method public void setCaCertificates(java.security.cert.X509Certificate[]);
method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
method public void setDomainSuffixMatch(java.lang.String);
method public void setEapMethod(int);
@@ -35254,6 +35257,7 @@
method public static boolean hasProperty(int, int);
method public boolean hasProperty(int);
method public static java.lang.String propertiesToString(int);
+ field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 4194304; // 0x400000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
field public static final int CAPABILITY_HOLD = 1; // 0x1
@@ -35394,6 +35398,7 @@
method public final void setVideoProvider(android.telecom.Connection.VideoProvider);
method public final void setVideoState(int);
method public static java.lang.String stateToString(int);
+ field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
field public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 524288; // 0x80000
field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
@@ -36408,10 +36413,15 @@
method public int getActiveSubscriptionInfoCountMax();
method public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int);
method public java.util.List<android.telephony.SubscriptionInfo> getActiveSubscriptionInfoList();
+ method public static int getDefaultDataSubscriptionId();
+ method public static int getDefaultSmsSubscriptionId();
+ method public static int getDefaultSubscriptionId();
+ method public static int getDefaultVoiceSubscriptionId();
method public boolean isNetworkRoaming(int);
method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
+ field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff
}
public static class SubscriptionManager.OnSubscriptionsChangedListener {
@@ -36423,32 +36433,49 @@
method public boolean canChangeDtmfToneLength();
method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
method public int getCallState();
+ method public int getCallState(int);
method public android.telephony.CellLocation getCellLocation();
method public int getDataActivity();
+ method public int getDataNetworkType(int);
method public int getDataState();
method public java.lang.String getDeviceId();
method public java.lang.String getDeviceId(int);
method public java.lang.String getDeviceSoftwareVersion();
method public java.lang.String getGroupIdLevel1();
+ method public java.lang.String getGroupIdLevel1(int);
method public java.lang.String getIccSimChallengeResponse(int, java.lang.String);
+ method public java.lang.String getLine1AlphaTag(int);
method public java.lang.String getLine1Number();
+ method public java.lang.String getLine1Number(int);
method public java.lang.String getMmsUAProfUrl();
method public java.lang.String getMmsUserAgent();
method public deprecated java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();
method public java.lang.String getNetworkCountryIso();
+ method public java.lang.String getNetworkCountryIso(int);
method public java.lang.String getNetworkOperator();
+ method public java.lang.String getNetworkOperator(int);
method public java.lang.String getNetworkOperatorName();
+ method public java.lang.String getNetworkOperatorName(int);
method public int getNetworkType();
+ method public int getNetworkType(int);
method public int getPhoneCount();
method public int getPhoneType();
method public java.lang.String getSimCountryIso();
+ method public java.lang.String getSimCountryIso(int);
method public java.lang.String getSimOperator();
+ method public java.lang.String getSimOperator(int);
method public java.lang.String getSimOperatorName();
+ method public java.lang.String getSimOperatorName(int);
method public java.lang.String getSimSerialNumber();
+ method public java.lang.String getSimSerialNumber(int);
method public int getSimState();
method public java.lang.String getSubscriberId();
+ method public java.lang.String getSubscriberId(int);
method public java.lang.String getVoiceMailAlphaTag();
+ method public java.lang.String getVoiceMailAlphaTag(int);
method public java.lang.String getVoiceMailNumber();
+ method public java.lang.String getVoiceMailNumber(int);
+ method public int getVoiceNetworkType(int);
method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle);
method public boolean hasCarrierPrivileges();
method public boolean hasIccCard();
@@ -36459,6 +36486,7 @@
method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
method public boolean isHearingAidCompatibilitySupported();
method public boolean isNetworkRoaming();
+ method public boolean isNetworkRoaming(int);
method public boolean isSmsCapable();
method public boolean isTtyModeSupported();
method public boolean isVoiceCapable();
@@ -36467,9 +36495,11 @@
method public void listen(android.telephony.PhoneStateListener, int);
method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
+ method public boolean setLine1NumberForDisplay(int, java.lang.String, java.lang.String);
method public boolean setOperatorBrandOverride(java.lang.String);
method public boolean setPreferredNetworkTypeToGlobal();
method public boolean setVoiceMailNumber(java.lang.String, java.lang.String);
+ method public boolean setVoiceMailNumber(int, java.lang.String, java.lang.String);
field public static final java.lang.String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
diff --git a/api/system-current.txt b/api/system-current.txt
index d4c3019..0c88a49 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -95,7 +95,7 @@
field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
field public static final java.lang.String FORCE_BACK = "android.permission.FORCE_BACK";
field public static final java.lang.String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
- field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
+ field public static final deprecated java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
field public static final java.lang.String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
field public static final java.lang.String GET_PACKAGE_IMPORTANCE = "android.permission.GET_PACKAGE_IMPORTANCE";
@@ -10504,7 +10504,6 @@
method public java.lang.String getQuantityString(int, int, java.lang.Object...) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getQuantityString(int, int) throws android.content.res.Resources.NotFoundException;
method public java.lang.CharSequence getQuantityText(int, int) throws android.content.res.Resources.NotFoundException;
- method public java.util.Locale getResolvedLocale();
method public java.lang.String getResourceEntryName(int) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getResourceName(int) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getResourcePackageName(int) throws android.content.res.Resources.NotFoundException;
@@ -14242,6 +14241,7 @@
field public static final int HOT_PIXEL_MODE_FAST = 1; // 0x1
field public static final int HOT_PIXEL_MODE_HIGH_QUALITY = 2; // 0x2
field public static final int HOT_PIXEL_MODE_OFF = 0; // 0x0
+ field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_3 = 3; // 0x3
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1; // 0x1
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2; // 0x2
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0; // 0x0
@@ -22206,6 +22206,7 @@
field public static final int DEFAULT = 0; // 0x0
field public static final int H263 = 1; // 0x1
field public static final int H264 = 2; // 0x2
+ field public static final int HEVC = 5; // 0x5
field public static final int MPEG_4_SP = 3; // 0x3
field public static final int VP8 = 4; // 0x4
}
@@ -25849,6 +25850,7 @@
method public java.lang.String getAltSubjectMatch();
method public java.lang.String getAnonymousIdentity();
method public java.security.cert.X509Certificate getCaCertificate();
+ method public java.security.cert.X509Certificate[] getCaCertificates();
method public java.security.cert.X509Certificate getClientCertificate();
method public java.lang.String getDomainSuffixMatch();
method public int getEapMethod();
@@ -25861,6 +25863,7 @@
method public void setAltSubjectMatch(java.lang.String);
method public void setAnonymousIdentity(java.lang.String);
method public void setCaCertificate(java.security.cert.X509Certificate);
+ method public void setCaCertificates(java.security.cert.X509Certificate[]);
method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
method public void setDomainSuffixMatch(java.lang.String);
method public void setEapMethod(int);
@@ -37552,6 +37555,7 @@
method public static boolean hasProperty(int, int);
method public boolean hasProperty(int);
method public static java.lang.String propertiesToString(int);
+ field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 4194304; // 0x400000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
field public static final int CAPABILITY_HOLD = 1; // 0x1
@@ -37703,6 +37707,7 @@
method public final void setVideoProvider(android.telecom.Connection.VideoProvider);
method public final void setVideoState(int);
method public static java.lang.String stateToString(int);
+ field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
field public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 524288; // 0x80000
field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
@@ -38802,10 +38807,15 @@
method public int getActiveSubscriptionInfoCountMax();
method public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int);
method public java.util.List<android.telephony.SubscriptionInfo> getActiveSubscriptionInfoList();
+ method public static int getDefaultDataSubscriptionId();
+ method public static int getDefaultSmsSubscriptionId();
+ method public static int getDefaultSubscriptionId();
+ method public static int getDefaultVoiceSubscriptionId();
method public boolean isNetworkRoaming(int);
method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
+ field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff
}
public static class SubscriptionManager.OnSubscriptionsChangedListener {
@@ -38826,6 +38836,7 @@
method public boolean endCall();
method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
method public int getCallState();
+ method public int getCallState(int);
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
method public java.lang.String getCdmaMdn();
@@ -38838,30 +38849,46 @@
method public int getDataActivity();
method public boolean getDataEnabled();
method public boolean getDataEnabled(int);
+ method public int getDataNetworkType(int);
method public int getDataState();
method public java.lang.String getDeviceId();
method public java.lang.String getDeviceId(int);
method public java.lang.String getDeviceSoftwareVersion();
method public java.lang.String getGroupIdLevel1();
+ method public java.lang.String getGroupIdLevel1(int);
method public java.lang.String getIccSimChallengeResponse(int, java.lang.String);
+ method public java.lang.String getLine1AlphaTag(int);
method public java.lang.String getLine1Number();
+ method public java.lang.String getLine1Number(int);
method public java.lang.String getMmsUAProfUrl();
method public java.lang.String getMmsUserAgent();
method public deprecated java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();
method public java.lang.String getNetworkCountryIso();
+ method public java.lang.String getNetworkCountryIso(int);
method public java.lang.String getNetworkOperator();
+ method public java.lang.String getNetworkOperator(int);
method public java.lang.String getNetworkOperatorName();
+ method public java.lang.String getNetworkOperatorName(int);
method public int getNetworkType();
+ method public int getNetworkType(int);
method public int getPhoneCount();
method public int getPhoneType();
method public java.lang.String getSimCountryIso();
+ method public java.lang.String getSimCountryIso(int);
method public java.lang.String getSimOperator();
+ method public java.lang.String getSimOperator(int);
method public java.lang.String getSimOperatorName();
+ method public java.lang.String getSimOperatorName(int);
method public java.lang.String getSimSerialNumber();
+ method public java.lang.String getSimSerialNumber(int);
method public int getSimState();
method public java.lang.String getSubscriberId();
+ method public java.lang.String getSubscriberId(int);
method public java.lang.String getVoiceMailAlphaTag();
+ method public java.lang.String getVoiceMailAlphaTag(int);
method public java.lang.String getVoiceMailNumber();
+ method public java.lang.String getVoiceMailNumber(int);
+ method public int getVoiceNetworkType(int);
method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle);
method public boolean handlePinMmi(java.lang.String);
method public boolean handlePinMmiForSubscriber(int, java.lang.String);
@@ -38876,6 +38903,7 @@
method public boolean isHearingAidCompatibilitySupported();
method public boolean isIdle();
method public boolean isNetworkRoaming();
+ method public boolean isNetworkRoaming(int);
method public boolean isOffhook();
method public boolean isRadioOn();
method public boolean isRinging();
@@ -38891,11 +38919,13 @@
method public void setDataEnabled(boolean);
method public void setDataEnabled(int, boolean);
method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
+ method public boolean setLine1NumberForDisplay(int, java.lang.String, java.lang.String);
method public boolean setOperatorBrandOverride(java.lang.String);
method public boolean setPreferredNetworkTypeToGlobal();
method public boolean setRadio(boolean);
method public boolean setRadioPower(boolean);
method public boolean setVoiceMailNumber(java.lang.String, java.lang.String);
+ method public boolean setVoiceMailNumber(int, java.lang.String, java.lang.String);
method public void silenceRinger();
method public boolean supplyPin(java.lang.String);
method public int[] supplyPinReportResult(java.lang.String);
diff --git a/api/test-current.txt b/api/test-current.txt
index 221beb8..42a8f1b 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -67,7 +67,7 @@
field public static final java.lang.String DUMP = "android.permission.DUMP";
field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
- field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
+ field public static final deprecated java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
@@ -10116,7 +10116,6 @@
method public java.lang.String getQuantityString(int, int, java.lang.Object...) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getQuantityString(int, int) throws android.content.res.Resources.NotFoundException;
method public java.lang.CharSequence getQuantityText(int, int) throws android.content.res.Resources.NotFoundException;
- method public java.util.Locale getResolvedLocale();
method public java.lang.String getResourceEntryName(int) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getResourceName(int) throws android.content.res.Resources.NotFoundException;
method public java.lang.String getResourcePackageName(int) throws android.content.res.Resources.NotFoundException;
@@ -13849,6 +13848,7 @@
field public static final int HOT_PIXEL_MODE_FAST = 1; // 0x1
field public static final int HOT_PIXEL_MODE_HIGH_QUALITY = 2; // 0x2
field public static final int HOT_PIXEL_MODE_OFF = 0; // 0x0
+ field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_3 = 3; // 0x3
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1; // 0x1
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2; // 0x2
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0; // 0x0
@@ -20865,6 +20865,7 @@
field public static final int DEFAULT = 0; // 0x0
field public static final int H263 = 1; // 0x1
field public static final int H264 = 2; // 0x2
+ field public static final int HEVC = 5; // 0x5
field public static final int MPEG_4_SP = 3; // 0x3
field public static final int VP8 = 4; // 0x4
}
@@ -23970,6 +23971,7 @@
method public java.lang.String getAltSubjectMatch();
method public java.lang.String getAnonymousIdentity();
method public java.security.cert.X509Certificate getCaCertificate();
+ method public java.security.cert.X509Certificate[] getCaCertificates();
method public java.security.cert.X509Certificate getClientCertificate();
method public java.lang.String getDomainSuffixMatch();
method public int getEapMethod();
@@ -23982,6 +23984,7 @@
method public void setAltSubjectMatch(java.lang.String);
method public void setAnonymousIdentity(java.lang.String);
method public void setCaCertificate(java.security.cert.X509Certificate);
+ method public void setCaCertificates(java.security.cert.X509Certificate[]);
method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
method public void setDomainSuffixMatch(java.lang.String);
method public void setEapMethod(int);
@@ -35268,6 +35271,7 @@
method public static boolean hasProperty(int, int);
method public boolean hasProperty(int);
method public static java.lang.String propertiesToString(int);
+ field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 4194304; // 0x400000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
field public static final int CAPABILITY_HOLD = 1; // 0x1
@@ -35408,6 +35412,7 @@
method public final void setVideoProvider(android.telecom.Connection.VideoProvider);
method public final void setVideoState(int);
method public static java.lang.String stateToString(int);
+ field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
field public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 524288; // 0x80000
field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
@@ -36422,10 +36427,15 @@
method public int getActiveSubscriptionInfoCountMax();
method public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int);
method public java.util.List<android.telephony.SubscriptionInfo> getActiveSubscriptionInfoList();
+ method public static int getDefaultDataSubscriptionId();
+ method public static int getDefaultSmsSubscriptionId();
+ method public static int getDefaultSubscriptionId();
+ method public static int getDefaultVoiceSubscriptionId();
method public boolean isNetworkRoaming(int);
method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
+ field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff
}
public static class SubscriptionManager.OnSubscriptionsChangedListener {
@@ -36437,32 +36447,49 @@
method public boolean canChangeDtmfToneLength();
method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
method public int getCallState();
+ method public int getCallState(int);
method public android.telephony.CellLocation getCellLocation();
method public int getDataActivity();
+ method public int getDataNetworkType(int);
method public int getDataState();
method public java.lang.String getDeviceId();
method public java.lang.String getDeviceId(int);
method public java.lang.String getDeviceSoftwareVersion();
method public java.lang.String getGroupIdLevel1();
+ method public java.lang.String getGroupIdLevel1(int);
method public java.lang.String getIccSimChallengeResponse(int, java.lang.String);
+ method public java.lang.String getLine1AlphaTag(int);
method public java.lang.String getLine1Number();
+ method public java.lang.String getLine1Number(int);
method public java.lang.String getMmsUAProfUrl();
method public java.lang.String getMmsUserAgent();
method public deprecated java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();
method public java.lang.String getNetworkCountryIso();
+ method public java.lang.String getNetworkCountryIso(int);
method public java.lang.String getNetworkOperator();
+ method public java.lang.String getNetworkOperator(int);
method public java.lang.String getNetworkOperatorName();
+ method public java.lang.String getNetworkOperatorName(int);
method public int getNetworkType();
+ method public int getNetworkType(int);
method public int getPhoneCount();
method public int getPhoneType();
method public java.lang.String getSimCountryIso();
+ method public java.lang.String getSimCountryIso(int);
method public java.lang.String getSimOperator();
+ method public java.lang.String getSimOperator(int);
method public java.lang.String getSimOperatorName();
+ method public java.lang.String getSimOperatorName(int);
method public java.lang.String getSimSerialNumber();
+ method public java.lang.String getSimSerialNumber(int);
method public int getSimState();
method public java.lang.String getSubscriberId();
+ method public java.lang.String getSubscriberId(int);
method public java.lang.String getVoiceMailAlphaTag();
+ method public java.lang.String getVoiceMailAlphaTag(int);
method public java.lang.String getVoiceMailNumber();
+ method public java.lang.String getVoiceMailNumber(int);
+ method public int getVoiceNetworkType(int);
method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle);
method public boolean hasCarrierPrivileges();
method public boolean hasIccCard();
@@ -36473,6 +36500,7 @@
method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
method public boolean isHearingAidCompatibilitySupported();
method public boolean isNetworkRoaming();
+ method public boolean isNetworkRoaming(int);
method public boolean isSmsCapable();
method public boolean isTtyModeSupported();
method public boolean isVoiceCapable();
@@ -36481,9 +36509,11 @@
method public void listen(android.telephony.PhoneStateListener, int);
method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
+ method public boolean setLine1NumberForDisplay(int, java.lang.String, java.lang.String);
method public boolean setOperatorBrandOverride(java.lang.String);
method public boolean setPreferredNetworkTypeToGlobal();
method public boolean setVoiceMailNumber(java.lang.String, java.lang.String);
+ method public boolean setVoiceMailNumber(int, java.lang.String, java.lang.String);
field public static final java.lang.String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 1d9e3bb..35695c4 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -430,47 +430,46 @@
}
/**
- * Lists all accounts of any type registered on the device.
- * Equivalent to getAccountsByType(null).
+ * List every {@link Account} registered on the device that are managed by
+ * applications whose signatures match the caller.
*
- * <p>It is safe to call this method from the main thread.
+ * <p>This method can be called safely from the main thread. It is
+ * equivalent to calling <code>getAccountsByType(null)</code>.
*
- * <p>Clients of this method that have not been granted the
- * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
- * will only see those accounts managed by AbstractAccountAuthenticators whose
- * signature matches the client.
+ * <p><b>NOTE:</b> Apps declaring a {@code targetSdkVersion<=23} in their
+ * manifests will continue to behave as they did on devices that support
+ * API level 23. In particular the GET_ACCOUNTS permission is required to
+ * see all the Accounts registered with the AccountManager. See docs for
+ * this function in API level 23 for more information.
*
- * @return An array of {@link Account}, one for each account. Empty
- * (never null) if no accounts have been added.
+ * @return Array of Accounts. The array may be empty if no accounts are
+ * available to the caller.
*/
@NonNull
- @RequiresPermission(GET_ACCOUNTS)
public Account[] getAccounts() {
- try {
- return mService.getAccounts(null, mContext.getOpPackageName());
- } catch (RemoteException e) {
- // won't ever happen
- throw new RuntimeException(e);
- }
+ return getAccountsByType(null);
}
/**
* @hide
- * Lists all accounts of any type registered on the device for a given
- * user id. Equivalent to getAccountsByType(null).
+ * List every {@link Account} registered on the device for a specific User
+ * that are managed by applications whose signatures match the caller.
*
- * <p>It is safe to call this method from the main thread.
+ * <p><b>NOTE:</b> Apps declaring a {@code targetSdkVersion<=23} in their
+ * manifests will continue to behave as they did on devices that support
+ * API level 23. In particular the GET_ACCOUNTS permission is required to
+ * see all the Accounts registered with the AccountManager for the
+ * specified userId. See docs for this function in API level 23 for more
+ * information.
*
- * <p>Clients of this method that have not been granted the
- * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
- * will only see those accounts managed by AbstractAccountAuthenticators whose
- * signature matches the client.
+ * <p>This method can be called safely from the main thread.
*
- * @return An array of {@link Account}, one for each account. Empty
- * (never null) if no accounts have been added.
+ * @param int userId associated with the User whose accounts should be
+ * queried.
+ * @return Array of Accounts. The array may be empty if no accounts are
+ * available to the caller.
*/
@NonNull
- @RequiresPermission(GET_ACCOUNTS)
public Account[] getAccountsAsUser(int userId) {
try {
return mService.getAccountsAsUser(null, userId, mContext.getOpPackageName());
@@ -501,10 +500,11 @@
/**
* Returns the accounts visible to the specified package, in an environment where some apps
* are not authorized to view all accounts. This method can only be called by system apps.
+ *
* @param type The type of accounts to return, null to retrieve all accounts
* @param packageName The package name of the app for which the accounts are to be returned
- * @return An array of {@link Account}, one per matching account. Empty
- * (never null) if no accounts of the specified type have been added.
+ * @return Array of Accounts. The array may be empty if no accounts of th
+ * specified type are visible to the caller.
*/
@NonNull
public Account[] getAccountsByTypeForPackage(String type, String packageName) {
@@ -518,29 +518,22 @@
}
/**
- * Lists all accounts of a particular type. The account type is a
- * string token corresponding to the authenticator and useful domain
- * of the account. For example, there are types corresponding to Google
- * and Facebook. The exact string token to use will be published somewhere
- * associated with the authenticator in question.
+ * List every {@link Account} of a specified type managed by applications
+ * whose signatures match the caller.
*
- * <p>It is safe to call this method from the main thread.
+ * <p><b>NOTE:</b> Apps declaring a {@code targetSdkVersion<=23} in their
+ * manifests will continue to behave as they did on devices that support
+ * API level 23. See docs for this function in API level 23 for more
+ * information.
*
- * <p>Clients of this method that have not been granted the
- * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
- * will only see those accounts managed by AbstractAccountAuthenticators whose
- * signature matches the client.
+ * <p>This method can be called safely from the main thread.
*
- * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
- * GET_ACCOUNTS permission is needed for those platforms, irrespective of uid
- * or signature match. See docs for this function in API level 22.
- *
- * @param type The type of accounts to return, null to retrieve all accounts
- * @return An array of {@link Account}, one per matching account. Empty
- * (never null) if no accounts of the specified type have been added.
+ * @param type String denoting the type of the accounts to return,
+ * {@code null} to retrieve all accounts visible to the caller.
+ * @return An array of Accounts. Empty (never null) if no accounts
+ * are available to the caller.
*/
@NonNull
- @RequiresPermission(GET_ACCOUNTS)
public Account[] getAccountsByType(String type) {
return getAccountsByTypeAsUser(type, Process.myUserHandle());
}
@@ -586,6 +579,7 @@
* @return a future containing the label string
* @hide
*/
+ @NonNull
public AccountManagerFuture<String> getAuthTokenLabel(
final String accountType, final String authTokenType,
AccountManagerCallback<String> callback, Handler handler) {
@@ -618,9 +612,13 @@
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#GET_ACCOUNTS} or be a signature
- * match with the AbstractAccountAuthenticator that manages the account.
+ * <p><b>Note:</b>The specified account must be managed by an application
+ * whose signature matches the caller.
+ *
+ * <p><b>Further note:</b>Apps targeting API level 23 or earlier will continue to
+ * behave as they did on devices that support API level 23. In particular
+ * they may still require the GET_ACCOUNTS permission. See docs for this
+ * function in API level 23.
*
* @param account The {@link Account} to test
* @param features An array of the account features to check
@@ -629,9 +627,11 @@
* @param handler {@link Handler} identifying the callback thread,
* null for the main thread
* @return An {@link AccountManagerFuture} which resolves to a Boolean,
- * true if the account exists and has all of the specified features.
+ * true if the account exists and has all of the specified features.
+ * @throws SecurityException if the specified account is managed by an
+ * application whose signature doesn't match the caller's signature.
*/
- @RequiresPermission(GET_ACCOUNTS)
+ @NonNull
public AccountManagerFuture<Boolean> hasFeatures(final Account account,
final String[] features,
AccountManagerCallback<Boolean> callback, Handler handler) {
@@ -654,9 +654,10 @@
/**
* Lists all accounts of a type which have certain features. The account
- * type identifies the authenticator (see {@link #getAccountsByType}).
- * Account features are authenticator-specific string tokens identifying
- * boolean account properties (see {@link #hasFeatures}).
+ * type identifies the authenticator (see {@link #getAccountsByType}). Said
+ * authenticator must be in a package whose signature matches the callers
+ * package signature. Account features are authenticator-specific string tokens
+ * identifying boolean account properties (see {@link #hasFeatures}).
*
* <p>Unlike {@link #getAccountsByType}, this method calls the authenticator,
* which may contact the server or do other work to check account features,
@@ -665,19 +666,14 @@
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>Clients of this method that have not been granted the
- * {@link android.Manifest.permission#GET_ACCOUNTS} permission,
- * will only see those accounts managed by AbstractAccountAuthenticators whose
- * signature matches the client.
+ * <p><b>NOTE:</b> Apps targeting API level 23 or earlier will continue to
+ * behave as they did on devices that support API level 23. In particular
+ * they may still require the GET_ACCOUNTS permission. See docs for this
+ * function in API level 23.
*
* @param type The type of accounts to return, must not be null
* @param features An array of the account features to require,
* may be null or empty
- *
- * <p><b>NOTE:</b> If targeting your app to work on API level 22 and before,
- * GET_ACCOUNTS permission is needed for those platforms, irrespective of uid
- * or signature match. See docs for this function in API level 22.
- *
* @param callback Callback to invoke when the request completes,
* null for no callback
* @param handler {@link Handler} identifying the callback thread,
@@ -686,7 +682,7 @@
* {@link Account}, one per account of the specified type which
* matches the requested features.
*/
- @RequiresPermission(GET_ACCOUNTS)
+ @NonNull
public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
final String type, final String[] features,
AccountManagerCallback<Account[]> callback, Handler handler) {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index dedc8e5..1e7457c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4916,8 +4916,10 @@
/*
* Initialize the default locales in this process for the reasons we set the time zone.
+ *
+ * We do this through ResourcesManager, since we need to do locale negotiation.
*/
- LocaleList.setDefault(data.config.getLocales());
+ mResourcesManager.setDefaultLocalesLocked(data.config.getLocales());
/*
* Update the system configuration since its preloaded and might not
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 368b8ef..3288cd9 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -48,13 +48,12 @@
boolean areNotificationsEnabledForPackage(String pkg, int uid);
ParceledListSlice getTopics(String pkg, int uid);
- void setTopicVisibilityOverride(String pkg, int uid, in Notification.Topic topic, int visibility);
- int getTopicVisibilityOverride(String pkg, int uid, in Notification.Topic topic);
- void setTopicPriority(String pkg, int uid, in Notification.Topic topic, int priority);
- int getTopicPriority(String pkg, int uid, in Notification.Topic topic);
- void setTopicImportance(String pkg, int uid, in Notification.Topic topic, int importance);
- int getTopicImportance(String pkg, int uid, in Notification.Topic topic);
- void setAppImportance(String pkg, int uid, int importance);
+ void setVisibilityOverride(String pkg, int uid, in Notification.Topic topic, int visibility);
+ int getVisibilityOverride(String pkg, int uid, in Notification.Topic topic);
+ void setPriority(String pkg, int uid, in Notification.Topic topic, int priority);
+ int getPriority(String pkg, int uid, in Notification.Topic topic);
+ void setImportance(String pkg, int uid, in Notification.Topic topic, int importance);
+ int getImportance(String pkg, int uid, in Notification.Topic topic);
boolean doesAppUseTopics(String pkg, int uid);
// TODO: Remove this when callers have been migrated to the equivalent
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 260216c..94e584e 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -35,6 +35,9 @@
import android.view.DisplayAdjustments;
import java.lang.ref.WeakReference;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
/** @hide */
public class ResourcesManager {
@@ -42,11 +45,15 @@
private static final boolean DEBUG = false;
private static ResourcesManager sResourcesManager;
- private final ArrayMap<ResourcesKey, WeakReference<Resources> > mActiveResources =
+ private final ArrayMap<ResourcesKey, WeakReference<Resources>> mActiveResources =
new ArrayMap<>();
private final ArrayMap<Pair<Integer, DisplayAdjustments>, WeakReference<Display>> mDisplays =
new ArrayMap<>();
+ private String[] mSystemLocales = {};
+ private final HashSet<String> mNonSystemLocales = new HashSet<String>();
+ private boolean mHasNonSystemLocales = false;
+
CompatibilityInfo mResCompatibilityInfo;
Configuration mResConfiguration;
@@ -165,6 +172,8 @@
? new Configuration(overrideConfiguration) : null;
ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfigCopy, scale);
Resources r;
+ final boolean findSystemLocales;
+ final boolean hasNonSystemLocales;
synchronized (this) {
// Resources is app scale dependent.
if (DEBUG) Slog.w(TAG, "getTopLevelResources: " + resDir + " / " + scale);
@@ -178,6 +187,8 @@
+ " key=" + key + " overrideConfig=" + overrideConfiguration);
return r;
}
+ findSystemLocales = (mSystemLocales.length == 0);
+ hasNonSystemLocales = mHasNonSystemLocales;
}
//if (r != null) {
@@ -243,6 +254,18 @@
if (DEBUG) Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
+ r.getConfiguration() + " appScale=" + r.getCompatibilityInfo().applicationScale);
+ final String[] systemLocales = (
+ findSystemLocales ?
+ AssetManager.getSystem().getLocales() :
+ null);
+ final String[] nonSystemLocales = assets.getNonSystemLocales();
+ // Avoid checking for non-pseudo-locales if we already know there were some from a previous
+ // Resources. The default value (for when hasNonSystemLocales is true) doesn't matter,
+ // since mHasNonSystemLocales will also be true, and thus isPseudoLocalesOnly would not be
+ // able to affect mHasNonSystemLocales.
+ final boolean isPseudoLocalesOnly = hasNonSystemLocales ||
+ LocaleList.isPseudoLocalesOnly(nonSystemLocales);
+
synchronized (this) {
WeakReference<Resources> wr = mActiveResources.get(key);
Resources existing = wr != null ? wr.get() : null;
@@ -255,11 +278,30 @@
// XXX need to remove entries when weak references go away
mActiveResources.put(key, new WeakReference<>(r));
+ if (mSystemLocales.length == 0) {
+ mSystemLocales = systemLocales;
+ }
+ mNonSystemLocales.addAll(Arrays.asList(nonSystemLocales));
+ mHasNonSystemLocales = mHasNonSystemLocales || !isPseudoLocalesOnly;
if (DEBUG) Slog.v(TAG, "mActiveResources.size()=" + mActiveResources.size());
return r;
}
}
+ /* package */ void setDefaultLocalesLocked(LocaleList locales) {
+ final int bestLocale;
+ if (mHasNonSystemLocales) {
+ bestLocale = locales.getFirstMatchIndexWithEnglishSupported(mNonSystemLocales);
+ } else {
+ // We fallback to system locales if there was no locale specifically supported by the
+ // assets. This is to properly support apps that only rely on the shared system assets
+ // and don't need assets of their own.
+ bestLocale = locales.getFirstMatchIndexWithEnglishSupported(mSystemLocales);
+ }
+ // set it for Java, this also affects newly created Resources
+ LocaleList.setDefault(locales, bestLocale);
+ }
+
final boolean applyConfigurationToResourcesLocked(Configuration config,
CompatibilityInfo compat) {
if (mResConfiguration == null) {
@@ -283,13 +325,28 @@
| ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
}
- // set it for java, this also affects newly created Resources
- final LocaleList localeList = config.getLocales();
- if (!localeList.isEmpty()) {
- LocaleList.setDefault(localeList);
+ Configuration localeAdjustedConfig = config;
+ final LocaleList configLocales = config.getLocales();
+ if (!configLocales.isEmpty()) {
+ setDefaultLocalesLocked(configLocales);
+ final LocaleList adjustedLocales = LocaleList.getAdjustedDefault();
+ if (adjustedLocales != configLocales) { // has the same result as .equals() in this case
+ // The first locale in the list was not chosen. So we create a modified
+ // configuration with the adjusted locales (which moves the chosen locale to the
+ // front).
+ localeAdjustedConfig = new Configuration();
+ localeAdjustedConfig.setTo(config);
+ localeAdjustedConfig.setLocales(adjustedLocales);
+ // Also adjust the locale list in mResConfiguration, so that the Resources created
+ // later would have the same locale list.
+ if (!mResConfiguration.getLocales().equals(adjustedLocales)) {
+ mResConfiguration.setLocales(adjustedLocales);
+ changes |= ActivityInfo.CONFIG_LOCALE;
+ }
+ }
}
- Resources.updateSystemConfiguration(config, defaultDisplayMetrics, compat);
+ Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics, compat);
ApplicationPackageManager.configurationChanged();
//Slog.i(TAG, "Configuration changed in " + currentPackageName());
@@ -301,7 +358,7 @@
Resources r = mActiveResources.valueAt(i).get();
if (r != null) {
if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
- + r + " config to: " + config);
+ + r + " config to: " + localeAdjustedConfig);
int displayId = key.mDisplayId;
boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
DisplayMetrics dm = defaultDisplayMetrics;
@@ -310,7 +367,7 @@
if (tmpConfig == null) {
tmpConfig = new Configuration();
}
- tmpConfig.setTo(config);
+ tmpConfig.setTo(localeAdjustedConfig);
if (!isDefaultDisplay) {
dm = getDisplayMetricsLocked(displayId);
applyNonDefaultDisplayMetricsToConfigurationLocked(dm, tmpConfig);
@@ -320,7 +377,7 @@
}
r.updateConfiguration(tmpConfig, dm, compat);
} else {
- r.updateConfiguration(config, dm, compat);
+ r.updateConfiguration(localeAdjustedConfig, dm, compat);
}
//Slog.i(TAG, "Updated app resources " + v.getKey()
// + " " + r + ": " + r.getConfiguration());
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index f3b1175..8035c56 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -82,8 +82,6 @@
import android.net.wifi.nan.WifiNanManager;
import android.net.wifi.p2p.IWifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager;
-import android.net.wifi.passpoint.IWifiPasspointManager;
-import android.net.wifi.passpoint.WifiPasspointManager;
import android.nfc.NfcManager;
import android.os.BatteryManager;
import android.os.DropBoxManager;
@@ -483,15 +481,6 @@
return new WifiManager(ctx.getOuterContext(), service);
}});
- registerService(Context.WIFI_PASSPOINT_SERVICE, WifiPasspointManager.class,
- new CachedServiceFetcher<WifiPasspointManager>() {
- @Override
- public WifiPasspointManager createService(ContextImpl ctx) {
- IBinder b = ServiceManager.getService(Context.WIFI_PASSPOINT_SERVICE);
- IWifiPasspointManager service = IWifiPasspointManager.Stub.asInterface(b);
- return new WifiPasspointManager(ctx.getOuterContext(), service);
- }});
-
registerService(Context.WIFI_P2P_SERVICE, WifiP2pManager.class,
new StaticServiceFetcher<WifiP2pManager>() {
@Override
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 74cb0f6..9cd7d05 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -104,8 +104,6 @@
void getActivityEnergyInfoFromController();
BluetoothActivityEnergyInfo reportActivityInfo();
- // For dumpsys support
- void dump(in ParcelFileDescriptor fd);
void onLeServiceUp();
void onBrEdrDown();
}
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 0b80f8a..6dfefac 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -17,11 +17,14 @@
package android.content;
import static android.content.ContentProvider.maybeAddUserId;
+
+import android.content.pm.PackageManager;
import android.content.res.AssetFileDescriptor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.Process;
import android.os.StrictMode;
import android.text.Html;
import android.text.Spannable;
@@ -462,7 +465,12 @@
// Check to see what data representations the content
// provider supports. We would like HTML text, but if that
// is not possible we'll live with plan text.
- String[] types = context.getContentResolver().getStreamTypes(mUri, "text/*");
+ String[] types = null;
+ try {
+ types = context.getContentResolver().getStreamTypes(mUri, "text/*");
+ } catch (SecurityException e) {
+ // No read permission for mUri, assume empty stream types list.
+ }
boolean hasHtml = false;
boolean hasText = false;
if (types != null) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 48d0196..9df7a28 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2561,7 +2561,6 @@
//@hide: NETWORK_POLICY_SERVICE,
WIFI_SERVICE,
WIFI_NAN_SERVICE,
- WIFI_PASSPOINT_SERVICE,
WIFI_P2P_SERVICE,
WIFI_SCANNING_SERVICE,
//@hide: WIFI_RTT_SERVICE,
@@ -3003,17 +3002,6 @@
/**
* Use with {@link #getSystemService} to retrieve a {@link
- * android.net.wifi.passpoint.WifiPasspointManager} for handling management of
- * Wi-Fi passpoint access.
- *
- * @see #getSystemService
- * @see android.net.wifi.passpoint.WifiPasspointManager
- * @hide
- */
- public static final String WIFI_PASSPOINT_SERVICE = "wifipasspoint";
-
- /**
- * Use with {@link #getSystemService} to retrieve a {@link
* android.net.wifi.p2p.WifiP2pManager} for handling management of
* Wi-Fi peer-to-peer connections.
*
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index ed64ead..e404429 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -162,10 +162,6 @@
private final Configuration mConfiguration = new Configuration();
- // Invariant: mResolvedLocale is the resolved locale of mLocalesForResolved
- private LocaleList mLocalesForResolved = null;
- private Locale mResolvedLocale = null;
-
private PluralRules mPluralRule;
private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
@@ -321,16 +317,6 @@
}
/**
- * Return the Locale resulting from locale negotiation between the Resources and the
- * Configuration objects used to construct the Resources. The locale is used for retrieving
- * resources as well as for determining plural rules.
- */
- @NonNull
- public Locale getResolvedLocale() {
- return mResolvedLocale;
- }
-
- /**
* Return the string value associated with a particular resource ID. The
* returned object will be a String if this is a plain string; it will be
* some other type of CharSequence if it is styled.
@@ -394,7 +380,7 @@
private PluralRules getPluralRule() {
synchronized (sSync) {
if (mPluralRule == null) {
- mPluralRule = PluralRules.forLocale(mResolvedLocale);
+ mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().getPrimary());
}
return mPluralRule;
}
@@ -457,7 +443,7 @@
@NonNull
public String getString(@StringRes int id, Object... formatArgs) throws NotFoundException {
final String raw = getString(id);
- return String.format(mResolvedLocale, raw, formatArgs);
+ return String.format(mConfiguration.getLocales().getPrimary(), raw, formatArgs);
}
/**
@@ -488,7 +474,7 @@
public String getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs)
throws NotFoundException {
String raw = getQuantityText(id, quantity).toString();
- return String.format(mResolvedLocale, raw, formatArgs);
+ return String.format(mConfiguration.getLocales().getPrimary(), raw, formatArgs);
}
/**
@@ -1955,7 +1941,7 @@
LocaleList locales = mConfiguration.getLocales();
if (locales.isEmpty()) {
- locales = LocaleList.getDefault();
+ locales = LocaleList.getAdjustedDefault();
mConfiguration.setLocales(locales);
}
if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
@@ -1983,26 +1969,8 @@
keyboardHidden = mConfiguration.keyboardHidden;
}
- if (locales != mLocalesForResolved) {
- if (locales.size() == 1) {
- // This is an optimization to avoid the JNI call(s) when the result of
- // getFirstMatchWithEnglishSupported() does not depend on the supported locales.
- mResolvedLocale = locales.getPrimary();
- } else {
- String[] supportedLocales = mAssets.getNonSystemLocales();
- if (LocaleList.isPseudoLocalesOnly(supportedLocales)) {
- // We fallback to all locales (including system locales) if there was no
- // locale specifically supported by the assets. This is to properly support
- // apps that only rely on the shared system assets and don't need assets of
- // their own.
- supportedLocales = mAssets.getLocales();
- }
- mResolvedLocale = locales.getFirstMatchWithEnglishSupported(supportedLocales);
- }
- mLocalesForResolved = locales;
- }
mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
- adjustLanguageTag(mResolvedLocale.toLanguageTag()),
+ adjustLanguageTag(locales.getPrimary().toLanguageTag()),
mConfiguration.orientation,
mConfiguration.touchscreen,
mConfiguration.densityDpi, mConfiguration.keyboard,
@@ -2027,7 +1995,7 @@
}
synchronized (sSync) {
if (mPluralRule != null) {
- mPluralRule = PluralRules.forLocale(mResolvedLocale);
+ mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().getPrimary());
}
}
}
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 2695dfd..2aa6af6 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -2787,22 +2787,39 @@
/**
* <p>Generally classifies the overall set of the camera device functionality.</p>
- * <p>Camera devices will come in three flavors: LEGACY, LIMITED and FULL.</p>
- * <p>A FULL device will support below capabilities:</p>
+ * <p>The supported hardware level is a high-level description of the camera device's
+ * capabilities, summarizing several capabilities into one field. Each level adds additional
+ * features to the previous one, and is always a strict superset of the previous level.
+ * The ordering is <code>LEGACY < LIMITED < FULL < LEVEL_3</code>.</p>
+ * <p>Starting from <code>LEVEL_3</code>, the level enumerations are guaranteed to be in increasing
+ * numerical value as well. To check if a given device is at least at a given hardware level,
+ * the following code snippet can be used:</p>
+ * <pre><code>// Returns true if the device supports the required hardware level, or better.
+ * boolean isHardwareLevelSupported(CameraCharacteristics c, int requiredLevel) {
+ * int deviceLevel = c.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL);
+ * if (deviceLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) {
+ * return requiredLevel == deviceLevel;
+ * }
+ * // deviceLevel is not LEGACY, can use numerical sort
+ * return requiredLevel <= deviceLevel;
+ * }
+ * </code></pre>
+ * <p>At a high level, the levels are:</p>
* <ul>
- * <li>BURST_CAPTURE capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains BURST_CAPTURE)</li>
- * <li>Per frame control ({@link CameraCharacteristics#SYNC_MAX_LATENCY android.sync.maxLatency} <code>==</code> PER_FRAME_CONTROL)</li>
- * <li>Manual sensor control ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains MANUAL_SENSOR)</li>
- * <li>Manual post-processing control ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
- * MANUAL_POST_PROCESSING)</li>
- * <li>At least 3 processed (but not stalling) format output streams
- * ({@link CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_PROC android.request.maxNumOutputProc} <code>>=</code> 3)</li>
- * <li>The required stream configurations defined in android.scaler.availableStreamConfigurations</li>
- * <li>The required exposure time range defined in {@link CameraCharacteristics#SENSOR_INFO_EXPOSURE_TIME_RANGE android.sensor.info.exposureTimeRange}</li>
- * <li>The required maxFrameDuration defined in {@link CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION android.sensor.info.maxFrameDuration}</li>
+ * <li><code>LEGACY</code> devices operate in a backwards-compatibility mode for older
+ * Android devices, and have very limited capabilities.</li>
+ * <li><code>LIMITED</code> devices represent the
+ * baseline feature set, and may also include additional capabilities that are
+ * subsets of <code>FULL</code>.</li>
+ * <li><code>FULL</code> devices additionally support per-frame manual control of sensor, flash, lens and
+ * post-processing settings, and image capture at a high rate.</li>
+ * <li><code>LEVEL_3</code> devices additionally support YUV reprocessing and RAW image capture, along
+ * with additional output stream configurations.</li>
* </ul>
- * <p>A LIMITED device may have some or none of the above characteristics.
- * To find out more refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
+ * <p>See the individual level enums for full descriptions of the supported capabilities. The
+ * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} entry describes the device's capabilities at a
+ * finer-grain level, if needed. In addition, many controls have their available settings or
+ * ranges defined in individual {@link android.hardware.camera2.CameraCharacteristics } entries.</p>
* <p>Some features are not part of any particular hardware level or capability and must be
* queried separately. These include:</p>
* <ul>
@@ -2813,19 +2830,12 @@
* ({@link CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION android.lens.info.availableOpticalStabilization},
* {@link CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES android.control.availableVideoStabilizationModes})</li>
* </ul>
- * <p>A LEGACY device does not support per-frame control, manual sensor control, manual
- * post-processing, arbitrary cropping regions, and has relaxed performance constraints.</p>
- * <p>Each higher level supports everything the lower level supports
- * in this order: FULL <code>></code> LIMITED <code>></code> LEGACY.</p>
- * <p>Note:
- * Pre-API level 23, FULL devices also supported arbitrary cropping region
- * ({@link CameraCharacteristics#SCALER_CROPPING_TYPE android.scaler.croppingType} <code>==</code> FREEFORM); this requirement was relaxed in API level 23,
- * and FULL devices may only support CENTERED cropping.</p>
* <p><b>Possible values:</b>
* <ul>
* <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED}</li>
* <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}</li>
* <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY}</li>
+ * <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_3 3}</li>
* </ul></p>
* <p>This key is available on all devices.</p>
*
@@ -2833,16 +2843,12 @@
* @see CameraCharacteristics#LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION
* @see CameraCharacteristics#LENS_INFO_FOCUS_DISTANCE_CALIBRATION
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
- * @see CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_PROC
- * @see CameraCharacteristics#SCALER_CROPPING_TYPE
- * @see CameraCharacteristics#SENSOR_INFO_EXPOSURE_TIME_RANGE
- * @see CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION
* @see CameraCharacteristics#SENSOR_INFO_TIMESTAMP_SOURCE
* @see CameraCharacteristics#STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES
- * @see CameraCharacteristics#SYNC_MAX_LATENCY
* @see #INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED
* @see #INFO_SUPPORTED_HARDWARE_LEVEL_FULL
* @see #INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY
+ * @see #INFO_SUPPORTED_HARDWARE_LEVEL_3
*/
@PublicKey
public static final Key<Integer> INFO_SUPPORTED_HARDWARE_LEVEL =
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 63bcb31..28bb22a 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -314,7 +314,7 @@
* </table><br>
* </p>
*
- * <p>Limited-capability ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
+ * <p>Limited-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
* {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED}) devices
* support at least the following stream combinations in addition to those for
* {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY} devices:
@@ -332,13 +332,13 @@
* </table><br>
* </p>
*
- * <p>FULL-capability ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
+ * <p>FULL-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
* {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}) devices
* support at least the following stream combinations in addition to those for
* {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices:
*
* <table>
- * <tr><th colspan="7">FULL-capability additional guaranteed configurations</th></tr>
+ * <tr><th colspan="7">FULL-level additional guaranteed configurations</th></tr>
* <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th> <th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
* <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td colspan="2" id="rb"></td> <td>Maximum-resolution GPU processing with preview.</td> </tr>
@@ -389,6 +389,22 @@
* </table><br>
* </p>
*
+ * <p>LEVEL-3 ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
+ * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_3 LEVEL_3})
+ * support at least the following stream combinations in addition to the combinations for
+ * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL} and for
+ * RAW capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES} includes
+ * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_RAW RAW}):
+ *
+ * <table>
+ * <tr><th colspan="11">LEVEL-3 additional guaranteed configurations</th></tr>
+ * <tr><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th rowspan="2">Sample use case(s)</th> </tr>
+ * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th> </tr>
+ * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code 640x480}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td> <td>In-app viewfinder analysis with dynamic selection of output format.</td> </tr>
+ * <tr> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code 640x480}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td> <td>In-app viewfinder analysis with dynamic selection of output format.</td> </tr>
+ * </table><br>
+ * </p>
+ *
* <p>Since the capabilities of camera devices vary greatly, a given camera device may support
* target combinations with sizes outside of these guarantees, but this can only be tested for
* by attempting to create a session with such targets.</p>
@@ -501,7 +517,7 @@
* #rb { border-right-width: thick; }
* </style>
*
- * <p>Limited-capability ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
+ * <p>LIMITED-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
* {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED}) devices
* support at least the following stream combinations for creating a reprocessable capture
* session in addition to those listed in {@link #createCaptureSession createCaptureSession} for
@@ -518,14 +534,14 @@
* </table><br>
* </p>
*
- * <p>FULL-capability ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
+ * <p>FULL-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
* {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}) devices
* support at least the following stream combinations for creating a reprocessable capture
* session in addition to those for
* {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED} devices:
*
* <table>
- * <tr><th colspan="11">FULL-capability additional guaranteed configurations for creating a reprocessable capture session<br>({@code PRIV} input is guaranteed only if PRIVATE reprocessing is supported. {@code YUV} input is guaranteed only if YUV reprocessing is supported)</th></tr>
+ * <tr><th colspan="11">FULL-level additional guaranteed configurations for creating a reprocessable capture session<br>({@code PRIV} input is guaranteed only if PRIVATE reprocessing is supported. {@code YUV} input is guaranteed only if YUV reprocessing is supported)</th></tr>
* <tr><th colspan="2" id="rb">Input</th><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th rowspan="2">Sample use case(s)</th> </tr>
* <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
* <tr> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td></td><td id="rb"></td> <td></td><td id="rb"></td> <td>Maximum-resolution multi-frame image fusion in-app processing with regular preview.</td> </tr>
@@ -555,6 +571,22 @@
* </table><br>
* </p>
*
+ * <p>LEVEL-3 ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
+ * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_3 LEVEL_3}) devices
+ * support at least the following stream combinations for creating a reprocessable capture
+ * session in addition to those for
+ * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL} devices. Note that targets in the "Reprocess-only target" column may only be
+ * used as an output target for a reprocess capture request, not as an output to a regular capture request.
+ *
+ * <table>
+ * <tr><th colspan="13">LEVEL-3 additional guaranteed configurations for creating a reprocessable capture session<br>({@code PRIV} input is guaranteed only if PRIVATE reprocessing is supported. {@code YUV} input is always guaranteed.</th></tr>
+ * <tr><th colspan="2" id="rb">Input</th><th colspan="2" id="rb">Target 1</th><th colspan="2" id="rb">Target 2</th><th colspan="2" id="rb">Target 3</th><th colspan="2" id="rb">Target 4</th><th colspan="2" id="rb">Reprocess-only target</th><th rowspan="2">Sample use case(s)</th> </tr>
+ * <tr><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th><th>Type</th><th id="rb">Max size</th></tr>
+ * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code 640x480}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td> <td></td><td id="rb"></td> <td>In-app viewfinder analysis with ZSL and RAW.</td> </tr>
+ * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code 640x480}</td> <td>{@code RAW}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td><td>In-app viewfinder analysis with ZSL, RAW, and JPEG reprocessing output.</td> </tr>
+ * </table><br>
+ * </p>
+ *
* @param inputConfig The configuration for the input {@link Surface}
* @param outputs The new set of Surfaces that should be made available as
* targets for captured image data.
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index f61892e..d58ad22 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -964,23 +964,102 @@
//
/**
- * <p>This camera device has only limited capabilities.</p>
+ * <p>This camera device does not have enough capabilities to qualify as a <code>FULL</code> device or
+ * better.</p>
+ * <p>Only the stream configurations listed in the <code>LEGACY</code> and <code>LIMITED</code> tables in the
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession createCaptureSession} documentation are guaranteed to be supported.</p>
+ * <p>All <code>LIMITED</code> devices support the <code>BACKWARDS_COMPATIBLE</code> capability, indicating basic
+ * support for color image capture. The only exception is that the device may
+ * alternatively support only the <code>DEPTH_OUTPUT</code> capability, if it can only output depth
+ * measurements and not color images.</p>
+ * <p><code>LIMITED</code> devices and above require the use of {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger}
+ * to lock exposure metering (and calculate flash power, for cameras with flash) before
+ * capturing a high-quality still image.</p>
+ * <p>A <code>LIMITED</code> device that only lists the <code>BACKWARDS_COMPATIBLE</code> capability is only
+ * required to support full-automatic operation and post-processing (<code>OFF</code> is not
+ * supported for {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode}, {@link CaptureRequest#CONTROL_AF_MODE android.control.afMode}, or
+ * {@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode})</p>
+ * <p>Additional capabilities may optionally be supported by a <code>LIMITED</code>-level device, and
+ * can be checked for in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
+ *
+ * @see CaptureRequest#CONTROL_AE_MODE
+ * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
+ * @see CaptureRequest#CONTROL_AF_MODE
+ * @see CaptureRequest#CONTROL_AWB_MODE
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
*/
public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0;
/**
* <p>This camera device is capable of supporting advanced imaging applications.</p>
+ * <p>The stream configurations listed in the <code>FULL</code>, <code>LEGACY</code> and <code>LIMITED</code> tables in the
+ * {@link android.hardware.camera2.CameraDevice#createCaptureSession createCaptureSession} documentation are guaranteed to be supported.</p>
+ * <p>A <code>FULL</code> device will support below capabilities:</p>
+ * <ul>
+ * <li><code>BURST_CAPTURE</code> capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
+ * <code>BURST_CAPTURE</code>)</li>
+ * <li>Per frame control ({@link CameraCharacteristics#SYNC_MAX_LATENCY android.sync.maxLatency} <code>==</code> PER_FRAME_CONTROL)</li>
+ * <li>Manual sensor control ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains <code>MANUAL_SENSOR</code>)</li>
+ * <li>Manual post-processing control ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
+ * <code>MANUAL_POST_PROCESSING</code>)</li>
+ * <li>The required exposure time range defined in {@link CameraCharacteristics#SENSOR_INFO_EXPOSURE_TIME_RANGE android.sensor.info.exposureTimeRange}</li>
+ * <li>The required maxFrameDuration defined in {@link CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION android.sensor.info.maxFrameDuration}</li>
+ * </ul>
+ * <p>Note:
+ * Pre-API level 23, FULL devices also supported arbitrary cropping region
+ * ({@link CameraCharacteristics#SCALER_CROPPING_TYPE android.scaler.croppingType} <code>== FREEFORM</code>); this requirement was relaxed in API level
+ * 23, and <code>FULL</code> devices may only support <code>CENTERED</code> cropping.</p>
+ *
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ * @see CameraCharacteristics#SCALER_CROPPING_TYPE
+ * @see CameraCharacteristics#SENSOR_INFO_EXPOSURE_TIME_RANGE
+ * @see CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION
+ * @see CameraCharacteristics#SYNC_MAX_LATENCY
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
*/
public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1;
/**
* <p>This camera device is running in backward compatibility mode.</p>
+ * <p>Only the stream configurations listed in the <code>LEGACY</code> table in the {@link android.hardware.camera2.CameraDevice#createCaptureSession createCaptureSession}
+ * documentation are supported.</p>
+ * <p>A <code>LEGACY</code> device does not support per-frame control, manual sensor control, manual
+ * post-processing, arbitrary cropping regions, and has relaxed performance constraints.
+ * No additional capabilities beyond <code>BACKWARD_COMPATIBLE</code> will ever be listed by a
+ * <code>LEGACY</code> device in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities}.</p>
+ * <p>In addition, the {@link CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER android.control.aePrecaptureTrigger} is not functional on <code>LEGACY</code>
+ * devices. Instead, every request that includes a JPEG-format output target is treated
+ * as triggering a still capture, internally executing a precapture trigger. This may
+ * fire the flash for flash power metering during precapture, and then fire the flash
+ * for the final capture, if a flash is available on the device and the AE mode is set to
+ * enable the flash.</p>
+ *
+ * @see CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
*/
public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2;
+ /**
+ * <p>This camera device is capable of YUV reprocessing and RAW data capture, in addition to
+ * FULL-level capabilities.</p>
+ * <p>The stream configurations listed in the <code>LEVEL_3</code>, <code>RAW</code>, <code>FULL</code>, <code>LEGACY</code> and
+ * <code>LIMITED</code> tables in the {@link android.hardware.camera2.CameraDevice#createCaptureSession createCaptureSession}
+ * documentation are guaranteed to be supported.</p>
+ * <p>The following additional capabilities are guaranteed to be supported:</p>
+ * <ul>
+ * <li><code>YUV_REPROCESSING</code> capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
+ * <code>YUV_REPROCESSING</code>)</li>
+ * <li><code>RAW</code> capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
+ * <code>RAW</code>)</li>
+ * </ul>
+ *
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
+ * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+ */
+ public static final int INFO_SUPPORTED_HARDWARE_LEVEL_3 = 3;
+
//
// Enumeration values for CameraCharacteristics#SYNC_MAX_LATENCY
//
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index c3cae65..79eff4f 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1599,13 +1599,13 @@
* <p>This key is optional. Applications can assume there is no boost applied
* after RAW is captured if this key is not available.
* When this key is available, the sensitivity boost value must be within
- * {@link CaptureRequest#CONTROL_POST_RAW_SENSITIVITY_BOOST android.control.postRawSensitivityBoost}.</p>
+ * {@link CameraCharacteristics#CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE android.control.postRawSensitivityBoostRange}.</p>
* <p>If the camera device cannot apply the exact boost requested, it will reduce the
* boost to the nearest supported value.
* The final boost value used will be available in the output capture result.</p>
* <p>For devices that support post RAW sensitivity boost, the YUV/JPEG output images
* of such device will have the total sensitivity of
- * <code>{@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} * android.control.ispSensitivity / 100</code>
+ * <code>{@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} * {@link CaptureRequest#CONTROL_POST_RAW_SENSITIVITY_BOOST android.control.postRawSensitivityBoost} / 100</code>
* The sensitivity of RAW format images will always be <code>{@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}</code></p>
* <p>This control is only effective if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} or {@link CaptureRequest#CONTROL_MODE android.control.mode} is set to
* OFF; otherwise the auto-exposure algorithm will override this value.</p>
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 7b9d1a3..5748726 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2106,13 +2106,13 @@
* <p>This key is optional. Applications can assume there is no boost applied
* after RAW is captured if this key is not available.
* When this key is available, the sensitivity boost value must be within
- * {@link CaptureRequest#CONTROL_POST_RAW_SENSITIVITY_BOOST android.control.postRawSensitivityBoost}.</p>
+ * {@link CameraCharacteristics#CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE android.control.postRawSensitivityBoostRange}.</p>
* <p>If the camera device cannot apply the exact boost requested, it will reduce the
* boost to the nearest supported value.
* The final boost value used will be available in the output capture result.</p>
* <p>For devices that support post RAW sensitivity boost, the YUV/JPEG output images
* of such device will have the total sensitivity of
- * <code>{@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} * android.control.ispSensitivity / 100</code>
+ * <code>{@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity} * {@link CaptureRequest#CONTROL_POST_RAW_SENSITIVITY_BOOST android.control.postRawSensitivityBoost} / 100</code>
* The sensitivity of RAW format images will always be <code>{@link CaptureRequest#SENSOR_SENSITIVITY android.sensor.sensitivity}</code></p>
* <p>This control is only effective if {@link CaptureRequest#CONTROL_AE_MODE android.control.aeMode} or {@link CaptureRequest#CONTROL_MODE android.control.mode} is set to
* OFF; otherwise the auto-exposure algorithm will override this value.</p>
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 7cb086f..92c721b 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1611,7 +1611,7 @@
if (b != null) {
try {
ITelephony it = ITelephony.Stub.asInterface(b);
- int subId = SubscriptionManager.getDefaultDataSubId();
+ int subId = SubscriptionManager.getDefaultDataSubscriptionId();
Log.d("ConnectivityManager", "getMobileDataEnabled()+ subId=" + subId);
boolean retVal = it.getDataEnabled(subId);
Log.d("ConnectivityManager", "getMobileDataEnabled()- subId=" + subId
diff --git a/core/java/android/print/PrintJob.java b/core/java/android/print/PrintJob.java
index 777baab..66181e0 100644
--- a/core/java/android/print/PrintJob.java
+++ b/core/java/android/print/PrintJob.java
@@ -19,6 +19,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import java.util.Objects;
+
/**
* This class represents a print job from the perspective of an
* application. It contains behavior methods for performing operations
@@ -30,11 +32,11 @@
*/
public final class PrintJob {
- private final PrintManager mPrintManager;
+ private final @NonNull PrintManager mPrintManager;
- private PrintJobInfo mCachedInfo;
+ private @NonNull PrintJobInfo mCachedInfo;
- PrintJob(PrintJobInfo info, PrintManager printManager) {
+ PrintJob(@NonNull PrintJobInfo info, @NonNull PrintManager printManager) {
mCachedInfo = info;
mPrintManager = printManager;
}
@@ -44,7 +46,7 @@
*
* @return The id.
*/
- public @NonNull PrintJobId getId() {
+ public @Nullable PrintJobId getId() {
return mCachedInfo.getId();
}
@@ -58,7 +60,7 @@
*
* @return The print job info.
*/
- public @Nullable PrintJobInfo getInfo() {
+ public @NonNull PrintJobInfo getInfo() {
if (isInImmutableState()) {
return mCachedInfo;
}
@@ -193,11 +195,17 @@
return false;
}
PrintJob other = (PrintJob) obj;
- return mCachedInfo.getId().equals(other.mCachedInfo.getId());
+ return Objects.equals(mCachedInfo.getId(), other.mCachedInfo.getId());
}
@Override
public int hashCode() {
- return mCachedInfo.getId().hashCode();
+ PrintJobId printJobId = mCachedInfo.getId();
+
+ if (printJobId == null) {
+ return 0;
+ } else {
+ return printJobId.hashCode();
+ }
}
}
diff --git a/core/java/android/print/PrintJobId.java b/core/java/android/print/PrintJobId.java
index a2ee02b..186ae9b 100644
--- a/core/java/android/print/PrintJobId.java
+++ b/core/java/android/print/PrintJobId.java
@@ -19,7 +19,8 @@
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
-import android.text.TextUtils;
+
+import com.android.internal.util.Preconditions;
import java.util.UUID;
@@ -27,7 +28,7 @@
* This class represents the id of a print job.
*/
public final class PrintJobId implements Parcelable {
- private final String mValue;
+ private final @NonNull String mValue;
/**
* Creates a new instance.
@@ -45,7 +46,7 @@
*
* @hide
*/
- public PrintJobId(String value) {
+ public PrintJobId(@NonNull String value) {
mValue = value;
}
@@ -53,7 +54,7 @@
public int hashCode() {
final int prime = 31;
int result = 1;
- result = prime * result + ((mValue != null) ? mValue.hashCode() : 0);
+ result = prime * result + mValue.hashCode();
return result;
}
@@ -69,7 +70,7 @@
return false;
}
PrintJobId other = (PrintJobId) obj;
- if (!TextUtils.equals(mValue, other.mValue)) {
+ if (!mValue.equals(other.mValue)) {
return false;
}
return true;
@@ -104,7 +105,7 @@
*
* @hide
*/
- public static PrintJobId unflattenFromString(String string) {
+ public static @NonNull PrintJobId unflattenFromString(@NonNull String string) {
return new PrintJobId(string);
}
@@ -112,7 +113,7 @@
new Parcelable.Creator<PrintJobId>() {
@Override
public PrintJobId createFromParcel(Parcel parcel) {
- return new PrintJobId(parcel.readString());
+ return new PrintJobId(Preconditions.checkNotNull(parcel.readString()));
}
@Override
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index 21836b3..7e3a72f 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -244,7 +244,7 @@
*
* @return The id.
*/
- public @NonNull PrintJobId getId() {
+ public @Nullable PrintJobId getId() {
return mId;
}
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 3eb4874..58f260c 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -535,7 +535,10 @@
return new PrinterDiscoverySession(mService, mContext, mUserId);
}
- private static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub
+ /**
+ * @hide
+ */
+ public static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub
implements ActivityLifecycleCallbacks {
private final Object mLock = new Object();
@@ -1061,7 +1064,10 @@
}
}
- private static final class PrintJobStateChangeListenerWrapper extends
+ /**
+ * @hide
+ */
+ public static final class PrintJobStateChangeListenerWrapper extends
IPrintJobStateChangeListener.Stub {
private final WeakReference<PrintJobStateChangeListener> mWeakListener;
private final WeakReference<Handler> mWeakHandler;
diff --git a/core/java/android/print/PrinterDiscoverySession.java b/core/java/android/print/PrinterDiscoverySession.java
index abb441b..c587edd 100644
--- a/core/java/android/print/PrinterDiscoverySession.java
+++ b/core/java/android/print/PrinterDiscoverySession.java
@@ -16,6 +16,8 @@
package android.print;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.os.Handler;
@@ -72,7 +74,7 @@
}
}
- public final void startPrinterDiscovery(List<PrinterId> priorityList) {
+ public final void startPrinterDiscovery(@Nullable List<PrinterId> priorityList) {
if (isDestroyed()) {
Log.w(LOG_TAG, "Ignoring start printers discovery - session destroyed");
return;
@@ -102,7 +104,7 @@
}
}
- public final void startPrinterStateTracking(PrinterId printerId) {
+ public final void startPrinterStateTracking(@NonNull PrinterId printerId) {
if (isDestroyed()) {
Log.w(LOG_TAG, "Ignoring start printer state tracking - session destroyed");
return;
@@ -114,7 +116,7 @@
}
}
- public final void stopPrinterStateTracking(PrinterId printerId) {
+ public final void stopPrinterStateTracking(@NonNull PrinterId printerId) {
if (isDestroyed()) {
Log.w(LOG_TAG, "Ignoring stop printer state tracking - session destroyed");
return;
@@ -285,7 +287,7 @@
}
}
- private static final class PrinterDiscoveryObserver extends IPrinterDiscoveryObserver.Stub {
+ public static final class PrinterDiscoveryObserver extends IPrinterDiscoveryObserver.Stub {
private final WeakReference<PrinterDiscoverySession> mWeakSession;
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index 3104492..62d214e 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -16,6 +16,7 @@
package android.printservice;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Service;
import android.content.ComponentName;
@@ -346,7 +347,7 @@
* @param localId A locally unique id in the context of your print service.
* @return Global printer id.
*/
- public final PrinterId generatePrinterId(String localId) {
+ public @NonNull final PrinterId generatePrinterId(String localId) {
throwIfNotCalledOnMainThread();
localId = Preconditions.checkNotNull(localId, "localId cannot be null");
return new PrinterId(new ComponentName(getPackageName(),
diff --git a/core/java/android/security/net/config/CertificateSource.java b/core/java/android/security/net/config/CertificateSource.java
index 7e3601e..f3272e4 100644
--- a/core/java/android/security/net/config/CertificateSource.java
+++ b/core/java/android/security/net/config/CertificateSource.java
@@ -16,12 +16,13 @@
package android.security.net.config;
-import java.util.Set;
import java.security.cert.X509Certificate;
+import java.util.Set;
/** @hide */
public interface CertificateSource {
Set<X509Certificate> getCertificates();
X509Certificate findBySubjectAndPublicKey(X509Certificate cert);
X509Certificate findByIssuerAndSignature(X509Certificate cert);
+ Set<X509Certificate> findAllByIssuerAndSignature(X509Certificate cert);
}
diff --git a/core/java/android/security/net/config/CertificatesEntryRef.java b/core/java/android/security/net/config/CertificatesEntryRef.java
index ff728ef..742d430 100644
--- a/core/java/android/security/net/config/CertificatesEntryRef.java
+++ b/core/java/android/security/net/config/CertificatesEntryRef.java
@@ -17,8 +17,8 @@
package android.security.net.config;
import android.util.ArraySet;
-import java.util.Set;
import java.security.cert.X509Certificate;
+import java.util.Set;
/** @hide */
public final class CertificatesEntryRef {
@@ -60,4 +60,8 @@
return new TrustAnchor(foundCert, mOverridesPins);
}
+
+ public Set<X509Certificate> findAllCertificatesByIssuerAndSignature(X509Certificate cert) {
+ return mSource.findAllByIssuerAndSignature(cert);
+ }
}
diff --git a/core/java/android/security/net/config/DirectoryCertificateSource.java b/core/java/android/security/net/config/DirectoryCertificateSource.java
index bf29efa..b2c068c 100644
--- a/core/java/android/security/net/config/DirectoryCertificateSource.java
+++ b/core/java/android/security/net/config/DirectoryCertificateSource.java
@@ -29,6 +29,7 @@
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
+import java.util.Collections;
import java.util.Set;
import libcore.io.IoUtils;
@@ -110,10 +111,50 @@
});
}
+ @Override
+ public Set<X509Certificate> findAllByIssuerAndSignature(final X509Certificate cert) {
+ return findCerts(cert.getIssuerX500Principal(), new CertSelector() {
+ @Override
+ public boolean match(X509Certificate ca) {
+ try {
+ cert.verify(ca.getPublicKey());
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+ });
+ }
+
private static interface CertSelector {
boolean match(X509Certificate cert);
}
+ private Set<X509Certificate> findCerts(X500Principal subj, CertSelector selector) {
+ String hash = getHash(subj);
+ Set<X509Certificate> certs = null;
+ for (int index = 0; index >= 0; index++) {
+ String fileName = hash + "." + index;
+ if (!new File(mDir, fileName).exists()) {
+ break;
+ }
+ if (isCertMarkedAsRemoved(fileName)) {
+ continue;
+ }
+ X509Certificate cert = readCertificate(fileName);
+ if (!subj.equals(cert.getSubjectX500Principal())) {
+ continue;
+ }
+ if (selector.match(cert)) {
+ if (certs == null) {
+ certs = new ArraySet<X509Certificate>();
+ }
+ certs.add(cert);
+ }
+ }
+ return certs != null ? certs : Collections.<X509Certificate>emptySet();
+ }
+
private X509Certificate findCert(X500Principal subj, CertSelector selector) {
String hash = getHash(subj);
for (int index = 0; index >= 0; index++) {
diff --git a/core/java/android/security/net/config/KeyStoreCertificateSource.java b/core/java/android/security/net/config/KeyStoreCertificateSource.java
index b6105cd..ba5dd83 100644
--- a/core/java/android/security/net/config/KeyStoreCertificateSource.java
+++ b/core/java/android/security/net/config/KeyStoreCertificateSource.java
@@ -21,6 +21,7 @@
import java.security.KeyStoreException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
+import java.util.Collections;
import java.util.Enumeration;
import java.util.Set;
@@ -90,4 +91,18 @@
}
return anchor.getTrustedCert();
}
+
+ @Override
+ public Set<X509Certificate> findAllByIssuerAndSignature(X509Certificate cert) {
+ ensureInitialized();
+ Set<java.security.cert.TrustAnchor> anchors = mIndex.findAllByIssuerAndSignature(cert);
+ if (anchors.isEmpty()) {
+ return Collections.<X509Certificate>emptySet();
+ }
+ Set<X509Certificate> certs = new ArraySet<X509Certificate>(anchors.size());
+ for (java.security.cert.TrustAnchor anchor : anchors) {
+ certs.add(anchor.getTrustedCert());
+ }
+ return certs;
+ }
}
diff --git a/core/java/android/security/net/config/NetworkSecurityConfig.java b/core/java/android/security/net/config/NetworkSecurityConfig.java
index 0a2edff..ebe14691 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfig.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfig.java
@@ -145,6 +145,15 @@
return null;
}
+ /** @hide */
+ public Set<X509Certificate> findAllCertificatesByIssuerAndSignature(X509Certificate cert) {
+ Set<X509Certificate> certs = new ArraySet<X509Certificate>();
+ for (CertificatesEntryRef ref : mCertificatesEntryRefs) {
+ certs.addAll(ref.findAllCertificatesByIssuerAndSignature(cert));
+ }
+ return certs;
+ }
+
/**
* Return a {@link Builder} for the default {@code NetworkSecurityConfig}.
*
diff --git a/core/java/android/security/net/config/ResourceCertificateSource.java b/core/java/android/security/net/config/ResourceCertificateSource.java
index e489c2c..8803c4b 100644
--- a/core/java/android/security/net/config/ResourceCertificateSource.java
+++ b/core/java/android/security/net/config/ResourceCertificateSource.java
@@ -25,6 +25,7 @@
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Collection;
+import java.util.Collections;
import java.util.Set;
import com.android.org.conscrypt.TrustedCertificateIndex;
@@ -100,4 +101,18 @@
}
return anchor.getTrustedCert();
}
+
+ @Override
+ public Set<X509Certificate> findAllByIssuerAndSignature(X509Certificate cert) {
+ ensureInitialized();
+ Set<java.security.cert.TrustAnchor> anchors = mIndex.findAllByIssuerAndSignature(cert);
+ if (anchors.isEmpty()) {
+ return Collections.<X509Certificate>emptySet();
+ }
+ Set<X509Certificate> certs = new ArraySet<X509Certificate>(anchors.size());
+ for (java.security.cert.TrustAnchor anchor : anchors) {
+ certs.add(anchor.getTrustedCert());
+ }
+ return certs;
+ }
}
diff --git a/core/java/android/security/net/config/TrustedCertificateStoreAdapter.java b/core/java/android/security/net/config/TrustedCertificateStoreAdapter.java
index 4a90f82..c2f29be 100644
--- a/core/java/android/security/net/config/TrustedCertificateStoreAdapter.java
+++ b/core/java/android/security/net/config/TrustedCertificateStoreAdapter.java
@@ -42,6 +42,11 @@
}
@Override
+ public Set<X509Certificate> findAllIssuers(X509Certificate cert) {
+ return mConfig.findAllCertificatesByIssuerAndSignature(cert);
+ }
+
+ @Override
public X509Certificate getTrustAnchor(X509Certificate cert) {
TrustAnchor anchor = mConfig.findTrustAnchorBySubjectAndPublicKey(cert);
if (anchor == null) {
diff --git a/core/java/android/util/LocaleList.java b/core/java/android/util/LocaleList.java
index 8a2d015..90a20bc 100644
--- a/core/java/android/util/LocaleList.java
+++ b/core/java/android/util/LocaleList.java
@@ -26,6 +26,8 @@
import com.android.internal.annotations.GuardedBy;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.HashSet;
import java.util.Locale;
@@ -317,55 +319,72 @@
return supportedScr.equals(desiredScr) ? 1 : 0;
}
+ private int findFirstMatchIndex(Locale supportedLocale) {
+ for (int idx = 0; idx < mList.length; idx++) {
+ final int score = matchScore(supportedLocale, mList[idx]);
+ if (score > 0) {
+ return idx;
+ }
+ }
+ return Integer.MAX_VALUE;
+ }
+
private static final Locale EN_LATN = Locale.forLanguageTag("en-Latn");
- private Locale computeFirstMatch(String[] supportedLocales, boolean assumeEnglishIsSupported) {
+ private int computeFirstMatchIndex(Collection<String> supportedLocales,
+ boolean assumeEnglishIsSupported) {
if (mList.length == 1) { // just one locale, perhaps the most common scenario
- return mList[0];
+ return 0;
}
if (mList.length == 0) { // empty locale list
- return null;
+ return -1;
}
+
int bestIndex = Integer.MAX_VALUE;
- final int numSupportedLocales =
- supportedLocales.length + (assumeEnglishIsSupported ? 1 : 0);
- for (int i = 0; i < numSupportedLocales; i++) {
- final Locale supportedLocale;
- if (assumeEnglishIsSupported) {
- // Try English first, so we can return early if it's in the LocaleList
- supportedLocale = (i == 0) ? EN_LATN : Locale.forLanguageTag(supportedLocales[i-1]);
- } else {
- supportedLocale = Locale.forLanguageTag(supportedLocales[i]);
+ // Try English first, so we can return early if it's in the LocaleList
+ if (assumeEnglishIsSupported) {
+ final int idx = findFirstMatchIndex(EN_LATN);
+ if (idx == 0) { // We have a match on the first locale, which is good enough
+ return 0;
+ } else if (idx < bestIndex) {
+ bestIndex = idx;
}
+ }
+ for (String languageTag : supportedLocales) {
+ final Locale supportedLocale = Locale.forLanguageTag(languageTag);
// We expect the average length of locale lists used for locale resolution to be
// smaller than three, so it's OK to do this as an O(mn) algorithm.
- for (int idx = 0; idx < mList.length; idx++) {
- final int score = matchScore(supportedLocale, mList[idx]);
- if (score > 0) {
- if (idx == 0) { // We have a match on the first locale, which is good enough
- return mList[0];
- } else if (idx < bestIndex) {
- bestIndex = idx;
- }
- }
+ final int idx = findFirstMatchIndex(supportedLocale);
+ if (idx == 0) { // We have a match on the first locale, which is good enough
+ return 0;
+ } else if (idx < bestIndex) {
+ bestIndex = idx;
}
}
- if (bestIndex == Integer.MAX_VALUE) { // no match was found
- return mList[0];
+ if (bestIndex == Integer.MAX_VALUE) {
+ // no match was found, so we fall back to the first locale in the locale list
+ return 0;
} else {
- return mList[bestIndex];
+ return bestIndex;
}
}
+ private Locale computeFirstMatch(Collection<String> supportedLocales,
+ boolean assumeEnglishIsSupported) {
+ int bestIndex = computeFirstMatchIndex(supportedLocales, assumeEnglishIsSupported);
+ return bestIndex == -1 ? null : mList[bestIndex];
+ }
+
/**
* Returns the first match in the locale list given an unordered array of supported locales
- * in BCP47 format.
+ * in BCP 47 format.
*
* If the locale list is empty, null would be returned.
*/
@Nullable
public Locale getFirstMatch(String[] supportedLocales) {
- return computeFirstMatch(supportedLocales, false /* assume English is not supported */);
+ return computeFirstMatch(Arrays.asList(supportedLocales),
+ false /* assume English is not supported */);
}
/**
@@ -374,11 +393,26 @@
*/
@Nullable
public Locale getFirstMatchWithEnglishSupported(String[] supportedLocales) {
- return computeFirstMatch(supportedLocales, true /* assume English is supported */);
+ return computeFirstMatch(Arrays.asList(supportedLocales),
+ true /* assume English is supported */);
}
/**
- * Returns true if the array of locale tags only contains empty locales and pseudolocales.
+ * {@hide}
+ */
+ public int getFirstMatchIndexWithEnglishSupported(Collection<String> supportedLocales) {
+ return computeFirstMatchIndex(supportedLocales, true /* assume English is supported */);
+ }
+
+ /**
+ * {@hide}
+ */
+ public int getFirstMatchIndexWithEnglishSupported(String[] supportedLocales) {
+ return getFirstMatchIndexWithEnglishSupported(Arrays.asList(supportedLocales));
+ }
+
+ /**
+ * Returns true if the collection of locale tags only contains empty locales and pseudolocales.
* Assumes that there is no repetition in the input.
* {@hide}
*/
@@ -386,7 +420,7 @@
if (supportedLocales.length > NUM_PSEUDO_LOCALES + 1) {
// This is for optimization. Since there's no repetition in the input, if we have more
// than the number of pseudo-locales plus one for the empty string, it's guaranteed
- // that we have some meaninful locale in the list, so the list is not "practically
+ // that we have some meaninful locale in the collection, so the list is not "practically
// empty".
return false;
}
@@ -405,6 +439,8 @@
@GuardedBy("sLock")
private static LocaleList sDefaultLocaleList = null;
@GuardedBy("sLock")
+ private static LocaleList sDefaultAdjustedLocaleList = null;
+ @GuardedBy("sLock")
private static Locale sLastDefaultLocale = null;
/**
@@ -415,8 +451,8 @@
* secondary preference is.
*
* Note that the default LocaleList would change if Locale.setDefault() is called. This method
- * takes that into account by always checking the output of Locale.getDefault() and adjusting
- * the default LocaleList if needed.
+ * takes that into account by always checking the output of Locale.getDefault() and
+ * recalculating the default LocaleList if needed.
*/
@NonNull @Size(min=1)
public static LocaleList getDefault() {
@@ -426,7 +462,7 @@
sLastDefaultLocale = defaultLocale;
// It's either the first time someone has asked for the default locale list, or
// someone has called Locale.setDefault() since we last set or adjusted the default
- // locale list. So let's adjust the locale list.
+ // locale list. So let's recalculate the locale list.
if (sDefaultLocaleList != null
&& defaultLocale.equals(sDefaultLocaleList.getPrimary())) {
// The default Locale has changed, but it happens to be the first locale in the
@@ -434,6 +470,7 @@
return sDefaultLocaleList;
}
sDefaultLocaleList = new LocaleList(defaultLocale, sLastExplicitlySetLocaleList);
+ sDefaultAdjustedLocaleList = sDefaultLocaleList;
}
// sDefaultLocaleList can't be null, since it can't be set to null by
// LocaleList.setDefault(), and if getDefault() is called before a call to
@@ -444,6 +481,20 @@
}
/**
+ * Returns the default locale list, adjusted by moving the default locale to its first
+ * position.
+ *
+ * {@hide}
+ */
+ @NonNull @Size(min=1)
+ public static LocaleList getAdjustedDefault() {
+ getDefault(); // to recalculate the default locale list, if necessary
+ synchronized (sLock) {
+ return sDefaultAdjustedLocaleList;
+ }
+ }
+
+ /**
* Also sets the default locale by calling Locale.setDefault() with the first locale in the
* list.
*
@@ -474,6 +525,12 @@
Locale.setDefault(sLastDefaultLocale);
sLastExplicitlySetLocaleList = locales;
sDefaultLocaleList = locales;
+ if (localeIndex == 0) {
+ sDefaultAdjustedLocaleList = sDefaultLocaleList;
+ } else {
+ sDefaultAdjustedLocaleList = new LocaleList(
+ sLastDefaultLocale, sDefaultLocaleList);
+ }
}
}
}
diff --git a/core/java/android/view/DropPermissions.java b/core/java/android/view/DropPermissions.java
index 8c948a9..5411dad 100644
--- a/core/java/android/view/DropPermissions.java
+++ b/core/java/android/view/DropPermissions.java
@@ -16,6 +16,7 @@
package android.view;
+import android.app.ActivityManagerNative;
import android.os.IBinder;
import android.os.RemoteException;
import com.android.internal.view.IDropPermissions;
@@ -41,6 +42,8 @@
private final IDropPermissions mDropPermissions;
+ private IBinder mPermissionOwnerToken;
+
private final CloseGuard mCloseGuard = CloseGuard.get();
/**
@@ -80,11 +83,29 @@
}
/**
+ * Take the permissions. Must call {@link #release} explicitly.
+ * @return True if permissions are successfully taken.
+ * @hide
+ */
+ public boolean takeTransient() {
+ try {
+ mPermissionOwnerToken = ActivityManagerNative.getDefault().
+ newUriPermissionOwner("drop");
+ mDropPermissions.takeTransient(mPermissionOwnerToken);
+ } catch (RemoteException e) {
+ return false;
+ }
+ mCloseGuard.open("release");
+ return true;
+ }
+
+ /**
* Revoke permissions explicitly.
*/
public void release() {
try {
mDropPermissions.release();
+ mPermissionOwnerToken = null;
} catch (RemoteException e) {
}
mCloseGuard.close();
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 67473c6..617d3dd 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -77,6 +77,7 @@
import android.view.ContextMenu;
import android.view.DisplayListCanvas;
import android.view.DragEvent;
+import android.view.DropPermissions;
import android.view.Gravity;
import android.view.InputDevice;
import android.view.LayoutInflater;
@@ -2298,11 +2299,24 @@
void onDrop(DragEvent event) {
StringBuilder content = new StringBuilder("");
- ClipData clipData = event.getClipData();
- final int itemCount = clipData.getItemCount();
- for (int i=0; i < itemCount; i++) {
- Item item = clipData.getItemAt(i);
- content.append(item.coerceToStyledText(mTextView.getContext()));
+
+ final DropPermissions dropPermissions = DropPermissions.obtain(event);
+ if (dropPermissions != null) {
+ dropPermissions.takeTransient();
+ }
+
+ try {
+ ClipData clipData = event.getClipData();
+ final int itemCount = clipData.getItemCount();
+ for (int i=0; i < itemCount; i++) {
+ Item item = clipData.getItemAt(i);
+ content.append(item.coerceToStyledText(mTextView.getContext()));
+ }
+ }
+ finally {
+ if (dropPermissions != null) {
+ dropPermissions.release();
+ }
}
final int offset = mTextView.getOffsetForPosition(event.getX(), event.getY());
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index 381e71f..2f26e92 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -42,6 +42,23 @@
* @return the string reference that was validated
* @throws IllegalArgumentException if {@code string} is empty
*/
+ public static @NonNull String checkStringNotEmpty(final String string) {
+ if (TextUtils.isEmpty(string)) {
+ throw new IllegalArgumentException();
+ }
+ return string;
+ }
+
+ /**
+ * Ensures that an string reference passed as a parameter to the calling
+ * method is not empty.
+ *
+ * @param string an string reference
+ * @param errorMessage the exception message to use if the check fails; will
+ * be converted to a string using {@link String#valueOf(Object)}
+ * @return the string reference that was validated
+ * @throws IllegalArgumentException if {@code string} is empty
+ */
public static @NonNull String checkStringNotEmpty(final String string,
final Object errorMessage) {
if (TextUtils.isEmpty(string)) {
@@ -301,8 +318,8 @@
*
* @throws NullPointerException if the {@code value} or any of its elements were {@code null}
*/
- public static <T> Collection<T> checkCollectionElementsNotNull(final Collection<T> value,
- final String valueName) {
+ public static @NonNull <C extends Collection<T>, T> C checkCollectionElementsNotNull(
+ final C value, final String valueName) {
if (value == null) {
throw new NullPointerException(valueName + " must not be null");
}
diff --git a/core/java/com/android/internal/view/IDropPermissions.aidl b/core/java/com/android/internal/view/IDropPermissions.aidl
index 2438bda..74ff4b4 100644
--- a/core/java/com/android/internal/view/IDropPermissions.aidl
+++ b/core/java/com/android/internal/view/IDropPermissions.aidl
@@ -24,5 +24,6 @@
*/
interface IDropPermissions {
void take(IBinder activityToken);
+ void takeTransient(IBinder permissionOwnerToken);
void release();
}
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 61dc6e4..2018e76 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -18,6 +18,8 @@
#include <stdio.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
@@ -34,6 +36,8 @@
// ----------------------------------------------------------------------------
+#define EGL_QCOM_PROTECTED_CONTENT 0x32E0
+
namespace android {
static const char* const OutOfResourcesException =
@@ -55,6 +59,28 @@
return android_atomic_inc(&globalCounter);
}
+// Check whether the current EGL context is protected.
+static bool isProtectedContext() {
+ EGLDisplay dpy = eglGetCurrentDisplay();
+ EGLContext ctx = eglGetCurrentContext();
+
+ if (dpy == EGL_NO_DISPLAY) {
+ ALOGE("isProtectedSurface: invalid current EGLDisplay");
+ return false;
+ }
+
+ if (ctx == EGL_NO_CONTEXT) {
+ ALOGE("isProtectedSurface: invalid current EGLContext");
+ return false;
+ }
+
+ EGLint isProtected = EGL_FALSE;
+ // TODO: Change the enum value below when an extension is ratified.
+ eglQueryContext(dpy, ctx, EGL_QCOM_PROTECTED_CONTENT, &isProtected);
+
+ return isProtected;
+}
+
// ----------------------------------------------------------------------------
static void SurfaceTexture_setSurfaceTexture(JNIEnv* env, jobject thiz,
@@ -263,6 +289,11 @@
getpid(),
createProcessUniqueId()));
+ // If the current context is protected, inform the producer.
+ if (isProtectedContext()) {
+ consumer->setConsumerUsageBits(GRALLOC_USAGE_PROTECTED);
+ }
+
SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);
SurfaceTexture_setProducer(env, thiz, producer);
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3d4b8b4..56c3fc8 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -383,6 +383,7 @@
<protected-broadcast android:name="android.security.STORAGE_CHANGED" />
<protected-broadcast android:name="android.telecom.action.PHONE_ACCOUNT_REGISTERED" />
<protected-broadcast android:name="android.telecom.action.PHONE_ACCOUNT_UNREGISTERED" />
+ <protected-broadcast android:name="android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION" />
<protected-broadcast android:name="android.telephony.action.CARRIER_CONFIG_CHANGED" />
<protected-broadcast android:name="com.android.bluetooth.btservice.action.ALARM_WAKEUP" />
@@ -1207,7 +1208,8 @@
<eat-comment />
<!-- Allows access to the list of accounts in the Accounts Service.
- <p>Protection level: normal
+ <p>Protection level: dangerous
+ @deprecated Not operative for apps apps with targetSdkVersion >= 24.
-->
<permission android:name="android.permission.GET_ACCOUNTS"
android:permissionGroup="android.permission-group.CONTACTS"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 2f2c5e4..a276854 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4185,4 +4185,9 @@
<string name="suspended_package_title">%1$s disabled</string>
<!-- Message for dialog displayed when a packge is suspended by device admin. [CHAR LIMIT=NONE] -->
<string name="suspended_package_message">Disabled by %1$s administrator. Contact them to learn more.</string>
+
+ <!-- Notification title shown when new SMS/MMS is received while the device is locked [CHAR LIMIT=NONE] -->
+ <string name="new_sms_notification_title">You have new messages</string>
+ <!-- Notification content shown when new SMS/MMS is received while the device is locked [CHAR LIMIT=NONE] -->
+ <string name="new_sms_notification_content">Open SMS app to view</string>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1f2c6e1..e59c935 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2499,4 +2499,8 @@
<java-symbol type="string" name="work_mode_turn_on" />
<java-symbol type="string" name="suspended_package_title" />
<java-symbol type="string" name="suspended_package_message" />
+
+ <!-- New SMS notification while phone is locked. -->
+ <java-symbol type="string" name="new_sms_notification_title" />
+ <java-symbol type="string" name="new_sms_notification_content" />
</resources>
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index ee8921e..eb055de 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -32,7 +32,8 @@
littlemock \
android-support-test \
mockito-target \
- espresso-core
+ espresso-core \
+ ub-uiautomator
LOCAL_JAVA_LIBRARIES := android.test.runner conscrypt telephony-common org.apache.http.legacy
LOCAL_PACKAGE_NAME := FrameworksCoreTests
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index eb0075b..bfa2b10 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1295,6 +1295,26 @@
</intent-filter>
</activity>
+ <activity android:name="android.print.PrintTestActivity"/>
+
+ <service
+ android:name="android.print.mockservice.MockPrintService"
+ android:permission="android.permission.BIND_PRINT_SERVICE">
+ <intent-filter>
+ <action android:name="android.printservice.PrintService" />
+ </intent-filter>
+ <meta-data
+ android:name="android.printservice"
+ android:resource="@xml/printservice">
+ </meta-data>
+ </service>
+
+ <activity
+ android:name="android.print.mockservice.SettingsActivity"
+ android:permission="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"
+ android:exported="true">
+ </activity>
+
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/core/tests/coretests/res/xml/printservice.xml b/core/tests/coretests/res/xml/printservice.xml
new file mode 100644
index 0000000..abbebda
--- /dev/null
+++ b/core/tests/coretests/res/xml/printservice.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<print-service xmlns:android="http://schemas.android.com/apk/res/android"
+ android:settingsActivity="android.print.mockservice.SettingsActivity"/>
diff --git a/core/tests/coretests/src/android/content/res/ResourcesLocaleResolutionTest.java b/core/tests/coretests/src/android/content/res/ResourcesLocaleResolutionTest.java
deleted file mode 100644
index 55c0031..0000000
--- a/core/tests/coretests/src/android/content/res/ResourcesLocaleResolutionTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-* 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 android.content.res;
-
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.DisplayMetrics;
-import android.util.LocaleList;
-
-import java.util.Arrays;
-import java.util.Locale;
-
-public class ResourcesLocaleResolutionTest extends AndroidTestCase {
- @SmallTest
- public void testGetResolvedLocale_englishIsAlwaysConsideredSupported() {
- // First make sure English has no explicit assets other than the default assets
- final AssetManager assets = getContext().getAssets();
- final String supportedLocales[] = assets.getNonSystemLocales();
- for (String languageTag : supportedLocales) {
- if ("en-XA".equals(languageTag)) {
- continue;
- }
- assertFalse(
- "supported locales: " + Arrays.toString(supportedLocales),
- "en".equals(Locale.forLanguageTag(languageTag).getLanguage()));
- }
-
- final DisplayMetrics dm = new DisplayMetrics();
- dm.setToDefaults();
- final Configuration cfg = new Configuration();
- cfg.setToDefaults();
- // Avestan and English have no assets, but Persian does.
- cfg.setLocales(LocaleList.forLanguageTags("ae,en,fa"));
- Resources res = new Resources(assets, dm, cfg);
- // We should get English, because it is always considered supported.
- assertEquals("en", res.getResolvedLocale().toLanguageTag());
- }
-}
-
diff --git a/core/tests/coretests/src/android/print/BasePrintTest.java b/core/tests/coretests/src/android/print/BasePrintTest.java
new file mode 100644
index 0000000..19ce44a
--- /dev/null
+++ b/core/tests/coretests/src/android/print/BasePrintTest.java
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.ParcelFileDescriptor;
+import android.os.SystemClock;
+import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintManager;
+import android.print.PrinterId;
+import android.print.mockservice.PrintServiceCallbacks;
+import android.print.mockservice.PrinterDiscoverySessionCallbacks;
+import android.print.mockservice.StubbablePrinterDiscoverySession;
+import android.printservice.CustomPrinterIconCallback;
+import android.printservice.PrintJob;
+import android.printservice.PrintService;
+import android.test.InstrumentationTestCase;
+import android.util.DisplayMetrics;
+import android.util.LocaleList;
+
+import org.mockito.stubbing.Answer;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * This is the base class for print tests.
+ */
+public abstract class BasePrintTest extends InstrumentationTestCase {
+
+ private static final long OPERATION_TIMEOUT = 30000;
+ private static final String PRINT_SPOOLER_PACKAGE_NAME = "com.android.printspooler";
+ private static final String PM_CLEAR_SUCCESS_OUTPUT = "Success";
+ private static final String COMMAND_LIST_ENABLED_IME_COMPONENTS = "ime list -s";
+ private static final String COMMAND_PREFIX_ENABLE_IME = "ime enable ";
+ private static final String COMMAND_PREFIX_DISABLE_IME = "ime disable ";
+ private static final int CURRENT_USER_ID = -2; // Mirrors UserHandle.USER_CURRENT
+
+ private PrintTestActivity mActivity;
+ private android.print.PrintJob mPrintJob;
+
+ private LocaleList mOldLocale;
+
+ private CallCounter mStartCallCounter;
+ private CallCounter mStartSessionCallCounter;
+
+ private String[] mEnabledImes;
+
+ private String[] getEnabledImes() throws IOException {
+ List<String> imeList = new ArrayList<>();
+
+ ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation()
+ .executeShellCommand(COMMAND_LIST_ENABLED_IME_COMPONENTS);
+ try (BufferedReader reader = new BufferedReader(
+ new InputStreamReader(new FileInputStream(pfd.getFileDescriptor())))) {
+
+ String line;
+ while ((line = reader.readLine()) != null) {
+ imeList.add(line);
+ }
+ }
+
+ String[] imeArray = new String[imeList.size()];
+ imeList.toArray(imeArray);
+
+ return imeArray;
+ }
+
+ private void disableImes() throws Exception {
+ mEnabledImes = getEnabledImes();
+ for (String ime : mEnabledImes) {
+ String disableImeCommand = COMMAND_PREFIX_DISABLE_IME + ime;
+ runShellCommand(getInstrumentation(), disableImeCommand);
+ }
+ }
+
+ private void enableImes() throws Exception {
+ for (String ime : mEnabledImes) {
+ String enableImeCommand = COMMAND_PREFIX_ENABLE_IME + ime;
+ runShellCommand(getInstrumentation(), enableImeCommand);
+ }
+ mEnabledImes = null;
+ }
+
+ @Override
+ protected void runTest() throws Throwable {
+ // Do nothing if the device does not support printing.
+ if (supportsPrinting()) {
+ super.runTest();
+ }
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ if (!supportsPrinting()) {
+ return;
+ }
+
+ // Make sure we start with a clean slate.
+ clearPrintSpoolerData();
+ disableImes();
+
+ // Workaround for dexmaker bug: https://code.google.com/p/dexmaker/issues/detail?id=2
+ // Dexmaker is used by mockito.
+ System.setProperty("dexmaker.dexcache", getInstrumentation()
+ .getTargetContext().getCacheDir().getPath());
+
+ // Set to US locale.
+ Resources resources = getInstrumentation().getTargetContext().getResources();
+ Configuration oldConfiguration = resources.getConfiguration();
+ if (!oldConfiguration.getLocales().getPrimary().equals(Locale.US)) {
+ mOldLocale = oldConfiguration.getLocales();
+ DisplayMetrics displayMetrics = resources.getDisplayMetrics();
+ Configuration newConfiguration = new Configuration(oldConfiguration);
+ newConfiguration.setLocale(Locale.US);
+ resources.updateConfiguration(newConfiguration, displayMetrics);
+ }
+
+ // Initialize the latches.
+ mStartCallCounter = new CallCounter();
+ mStartSessionCallCounter = new CallCounter();
+
+ // Create the activity for the right locale.
+ createActivity();
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ if (!supportsPrinting()) {
+ return;
+ }
+
+ // Done with the activity.
+ getActivity().finish();
+ enableImes();
+
+ // Restore the locale if needed.
+ if (mOldLocale != null) {
+ Resources resources = getInstrumentation().getTargetContext().getResources();
+ DisplayMetrics displayMetrics = resources.getDisplayMetrics();
+ Configuration newConfiguration = new Configuration(resources.getConfiguration());
+ newConfiguration.setLocales(mOldLocale);
+ mOldLocale = null;
+ resources.updateConfiguration(newConfiguration, displayMetrics);
+ }
+
+ // Make sure the spooler is cleaned, this also un-approves all services
+ clearPrintSpoolerData();
+
+ super.tearDown();
+ }
+
+ protected android.print.PrintJob print(@NonNull final PrintDocumentAdapter adapter,
+ final PrintAttributes attributes) {
+ // Initiate printing as if coming from the app.
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ PrintManager printManager = (PrintManager) getActivity()
+ .getSystemService(Context.PRINT_SERVICE);
+ mPrintJob = printManager.print("Print job", adapter, attributes);
+ }
+ });
+
+ return mPrintJob;
+ }
+
+ protected void onStartCalled() {
+ mStartCallCounter.call();
+ }
+
+ protected void onPrinterDiscoverySessionStartCalled() {
+ mStartSessionCallCounter.call();
+ }
+
+ protected void waitForPrinterDiscoverySessionStartCallbackCalled() {
+ waitForCallbackCallCount(mStartSessionCallCounter, 1,
+ "Did not get expected call to onStartPrinterDiscoverySession.");
+ }
+
+ protected void waitForStartAdapterCallbackCalled() {
+ waitForCallbackCallCount(mStartCallCounter, 1, "Did not get expected call to start.");
+ }
+
+ private void waitForCallbackCallCount(CallCounter counter, int count, String message) {
+ try {
+ counter.waitForCount(count, OPERATION_TIMEOUT);
+ } catch (TimeoutException te) {
+ fail(message);
+ }
+ }
+
+ protected PrintTestActivity getActivity() {
+ return mActivity;
+ }
+
+ protected void createActivity() {
+ mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
+ PrintTestActivity.class, null);
+ }
+
+ public static String runShellCommand(Instrumentation instrumentation, String cmd)
+ throws IOException {
+ ParcelFileDescriptor pfd = instrumentation.getUiAutomation().executeShellCommand(cmd);
+ byte[] buf = new byte[512];
+ int bytesRead;
+ FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+ StringBuffer stdout = new StringBuffer();
+ while ((bytesRead = fis.read(buf)) != -1) {
+ stdout.append(new String(buf, 0, bytesRead));
+ }
+ fis.close();
+ return stdout.toString();
+ }
+
+ protected void clearPrintSpoolerData() throws Exception {
+ assertTrue("failed to clear print spooler data",
+ runShellCommand(getInstrumentation(), String.format(
+ "pm clear --user %d %s", CURRENT_USER_ID, PRINT_SPOOLER_PACKAGE_NAME))
+ .contains(PM_CLEAR_SUCCESS_OUTPUT));
+ }
+
+ @SuppressWarnings("unchecked")
+ protected PrinterDiscoverySessionCallbacks createMockPrinterDiscoverySessionCallbacks(
+ Answer<Void> onStartPrinterDiscovery, Answer<Void> onStopPrinterDiscovery,
+ Answer<Void> onValidatePrinters, Answer<Void> onStartPrinterStateTracking,
+ Answer<Void> onRequestCustomPrinterIcon, Answer<Void> onStopPrinterStateTracking,
+ Answer<Void> onDestroy) {
+ PrinterDiscoverySessionCallbacks callbacks = mock(PrinterDiscoverySessionCallbacks.class);
+
+ doCallRealMethod().when(callbacks).setSession(any(StubbablePrinterDiscoverySession.class));
+ when(callbacks.getSession()).thenCallRealMethod();
+
+ if (onStartPrinterDiscovery != null) {
+ doAnswer(onStartPrinterDiscovery).when(callbacks).onStartPrinterDiscovery(
+ any(List.class));
+ }
+ if (onStopPrinterDiscovery != null) {
+ doAnswer(onStopPrinterDiscovery).when(callbacks).onStopPrinterDiscovery();
+ }
+ if (onValidatePrinters != null) {
+ doAnswer(onValidatePrinters).when(callbacks).onValidatePrinters(
+ any(List.class));
+ }
+ if (onStartPrinterStateTracking != null) {
+ doAnswer(onStartPrinterStateTracking).when(callbacks).onStartPrinterStateTracking(
+ any(PrinterId.class));
+ }
+ if (onRequestCustomPrinterIcon != null) {
+ doAnswer(onRequestCustomPrinterIcon).when(callbacks).onRequestCustomPrinterIcon(
+ any(PrinterId.class), any(CustomPrinterIconCallback.class));
+ }
+ if (onStopPrinterStateTracking != null) {
+ doAnswer(onStopPrinterStateTracking).when(callbacks).onStopPrinterStateTracking(
+ any(PrinterId.class));
+ }
+ if (onDestroy != null) {
+ doAnswer(onDestroy).when(callbacks).onDestroy();
+ }
+
+ return callbacks;
+ }
+
+ protected PrintServiceCallbacks createMockPrintServiceCallbacks(
+ Answer<PrinterDiscoverySessionCallbacks> onCreatePrinterDiscoverySessionCallbacks,
+ Answer<Void> onPrintJobQueued, Answer<Void> onRequestCancelPrintJob) {
+ final PrintServiceCallbacks service = mock(PrintServiceCallbacks.class);
+
+ doCallRealMethod().when(service).setService(any(PrintService.class));
+ when(service.getService()).thenCallRealMethod();
+
+ if (onCreatePrinterDiscoverySessionCallbacks != null) {
+ doAnswer(onCreatePrinterDiscoverySessionCallbacks).when(service)
+ .onCreatePrinterDiscoverySessionCallbacks();
+ }
+ if (onPrintJobQueued != null) {
+ doAnswer(onPrintJobQueued).when(service).onPrintJobQueued(any(PrintJob.class));
+ }
+ if (onRequestCancelPrintJob != null) {
+ doAnswer(onRequestCancelPrintJob).when(service).onRequestCancelPrintJob(
+ any(PrintJob.class));
+ }
+
+ return service;
+ }
+
+ protected final class CallCounter {
+ private final Object mLock = new Object();
+
+ private int mCallCount;
+
+ public void call() {
+ synchronized (mLock) {
+ mCallCount++;
+ mLock.notifyAll();
+ }
+ }
+
+ public int getCallCount() {
+ synchronized (mLock) {
+ return mCallCount;
+ }
+ }
+
+ public void waitForCount(int count, long timeoutMillis) throws TimeoutException {
+ synchronized (mLock) {
+ final long startTimeMillis = SystemClock.uptimeMillis();
+ while (mCallCount < count) {
+ try {
+ final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+ final long remainingTimeMillis = timeoutMillis - elapsedTimeMillis;
+ if (remainingTimeMillis <= 0) {
+ throw new TimeoutException();
+ }
+ mLock.wait(timeoutMillis);
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ }
+ }
+ }
+ }
+
+ protected boolean supportsPrinting() {
+ return getInstrumentation().getContext().getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_PRINTING);
+ }
+}
diff --git a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
new file mode 100644
index 0000000..5179b42
--- /dev/null
+++ b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
@@ -0,0 +1,669 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print;
+
+import android.annotation.NonNull;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.print.IPrintDocumentAdapter;
+import android.print.IPrintJobStateChangeListener;
+import android.print.IPrintManager;
+import android.print.IPrinterDiscoveryObserver;
+import android.print.PageRange;
+import android.print.PrintAttributes;
+import android.print.PrintAttributes.Margins;
+import android.print.PrintAttributes.MediaSize;
+import android.print.PrintAttributes.Resolution;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintJob;
+import android.print.PrintJobId;
+import android.print.PrintJobInfo;
+import android.print.PrintManager;
+import android.print.PrinterCapabilitiesInfo;
+import android.print.PrinterDiscoverySession;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.printservice.PrintServiceInfo;
+
+import android.print.mockservice.MockPrintService;
+import android.print.mockservice.PrintServiceCallbacks;
+import android.print.mockservice.PrinterDiscoverySessionCallbacks;
+import android.print.mockservice.StubbablePrinterDiscoverySession;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * tests feeding all possible parameters to the IPrintManager Binder.
+ */
+public class IPrintManagerParametersTest extends BasePrintTest {
+
+ private final int BAD_APP_ID = 0xffffffff;
+
+ private final int mAppId;
+ private final int mUserId;
+ private final PrintJobId mBadPrintJobId;
+
+ private PrintJob mGoodPrintJob;
+ private PrinterId mBadPrinterId;
+ private PrinterId mGoodPrinterId;
+ private ComponentName mGoodComponentName;
+ private ComponentName mBadComponentName;
+
+ private IPrintManager mIPrintManager;
+
+ /**
+ * Create a new IPrintManagerParametersTest and setup basic fields.
+ */
+ public IPrintManagerParametersTest() {
+ super();
+
+ mAppId = UserHandle.getAppId(Process.myUid());
+ mUserId = UserHandle.myUserId();
+ mBadPrintJobId = new PrintJobId();
+ mBadComponentName = new ComponentName("bad", "bad");
+ }
+
+ /**
+ * Create a mock PrintDocumentAdapter.
+ *
+ * @return The adapter
+ */
+ private @NonNull PrintDocumentAdapter createMockAdapter() {
+ return new PrintDocumentAdapter() {
+ @Override
+ public void onStart() {
+ onStartCalled();
+ }
+
+ @Override
+ public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
+ CancellationSignal cancellationSignal, LayoutResultCallback callback,
+ Bundle extras) {
+ }
+
+ @Override
+ public void onWrite(PageRange[] pages, ParcelFileDescriptor destination,
+ CancellationSignal cancellationSignal, WriteResultCallback callback) {
+ }
+ };
+ }
+
+ /**
+ * Create mock print service callbacks.
+ *
+ * @return the callbacks
+ */
+ private PrintServiceCallbacks createMockCallbacks() {
+ return createMockPrintServiceCallbacks(
+ new Answer<PrinterDiscoverySessionCallbacks>() {
+ @Override
+ public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+ return createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ // Get the session.
+ StubbablePrinterDiscoverySession session =
+ ((PrinterDiscoverySessionCallbacks) invocation
+ .getMock()).getSession();
+
+ if (session.getPrinters().isEmpty()) {
+ final String PRINTER_NAME = "good printer";
+ List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
+
+ // Add the printer.
+ mGoodPrinterId = session.getService()
+ .generatePrinterId(PRINTER_NAME);
+
+ PrinterCapabilitiesInfo capabilities =
+ new PrinterCapabilitiesInfo.Builder(mGoodPrinterId)
+ .setMinMargins(
+ new Margins(200, 200, 200, 200))
+ .addMediaSize(MediaSize.ISO_A4, true)
+ .addResolution(new Resolution("300x300",
+ "300x300", 300, 300),
+ true)
+ .setColorModes(
+ PrintAttributes.COLOR_MODE_COLOR,
+ PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+
+ PrinterInfo printer = new PrinterInfo.Builder(
+ mGoodPrinterId,
+ PRINTER_NAME,
+ PrinterInfo.STATUS_IDLE)
+ .setCapabilities(capabilities)
+ .build();
+ printers.add(printer);
+
+ session.addPrinters(printers);
+ }
+ onPrinterDiscoverySessionStartCalled();
+ return null;
+ }
+ }, null, null, null, null, null, null);
+ }
+ },
+ null, null);
+ }
+
+ /**
+ * Create a IPrintJobStateChangeListener object.
+ *
+ * @return the object
+ * @throws Exception if the object could not be created.
+ */
+ private IPrintJobStateChangeListener createMockIPrintJobStateChangeListener() throws Exception {
+ return new PrintManager.PrintJobStateChangeListenerWrapper(null,
+ new Handler(Looper.getMainLooper()));
+ }
+
+ /**
+ * Create a IPrinterDiscoveryObserver object.
+ *
+ * @return the object
+ * @throws Exception if the object could not be created.
+ */
+ private IPrinterDiscoveryObserver createMockIPrinterDiscoveryObserver() throws Exception {
+ return new PrinterDiscoverySession.PrinterDiscoveryObserver(null);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ MockPrintService.setCallbacks(createMockCallbacks());
+
+ mGoodComponentName = getActivity().getComponentName();
+
+ mGoodPrintJob = print(createMockAdapter(), null);
+
+ mIPrintManager = IPrintManager.Stub
+ .asInterface(ServiceManager.getService(Context.PRINT_SERVICE));
+
+ // Generate dummy printerId which is a valid PrinterId object, but does not correspond to a
+ // printer
+ mBadPrinterId = new PrinterId(mGoodComponentName, "dummy printer");
+
+ // Wait for PrintActivity to be ready
+ waitForStartAdapterCallbackCalled();
+
+ // Wait for printer discovery session to be ready
+ waitForPrinterDiscoverySessionStartCallbackCalled();
+ }
+
+ /**
+ * {@link Runnable} that can throw and {@link Exception}
+ */
+ private interface Invokable {
+ /**
+ * Execute the {@link Invokable}
+ *
+ * @throws Exception
+ */
+ public void run() throws Exception;
+ }
+
+ /**
+ * Assert that the invokable throws an expectedException
+ *
+ * @param invokable The {@link Invokable} to run
+ * @param expectedClass The {@link Exception} that is supposed to be thrown
+ */
+ public void assertException(Invokable invokable, Class<? extends Exception> expectedClass)
+ throws Exception {
+ try {
+ invokable.run();
+ } catch (Exception e) {
+ if (e.getClass().isAssignableFrom(expectedClass)) {
+ return;
+ } else {
+ throw new AssertionError("Expected: " + expectedClass.getName() + ", got: "
+ + e.getClass().getName());
+ }
+ }
+
+ throw new AssertionError("No exception thrown");
+ }
+
+ /**
+ * test IPrintManager.getPrintJobInfo
+ */
+ public void testGetPrintJobInfo() throws Exception {
+ assertEquals(mGoodPrintJob.getId(), mIPrintManager.getPrintJobInfo(mGoodPrintJob.getId(),
+ mAppId, mUserId).getId());
+ assertEquals(null, mIPrintManager.getPrintJobInfo(mBadPrintJobId, mAppId, mUserId));
+ assertEquals(null, mIPrintManager.getPrintJobInfo(null, mAppId, mUserId));
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.getPrintJobInfo(mGoodPrintJob.getId(), BAD_APP_ID, mUserId);
+ }
+ }, SecurityException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.getPrintJobInfos
+ */
+ public void testGetPrintJobInfos() throws Exception {
+ List<PrintJobInfo> infos = mIPrintManager.getPrintJobInfos(mAppId, mUserId);
+
+ boolean foundPrintJob = false;
+ for (PrintJobInfo info : infos) {
+ if (info.getId().equals(mGoodPrintJob.getId())) {
+ assertEquals(PrintJobInfo.STATE_CREATED, info.getState());
+ foundPrintJob = true;
+ }
+ }
+ assertTrue(foundPrintJob);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.getPrintJobInfos(BAD_APP_ID, mUserId);
+ }
+ }, SecurityException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.print
+ */
+ public void testPrint() throws Exception {
+ final String name = "dummy print job";
+
+ final IPrintDocumentAdapter adapter = new PrintManager
+ .PrintDocumentAdapterDelegate(getActivity(), createMockAdapter());
+
+ // Valid parameters are tested in setUp()
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.print(null, adapter, null, mGoodComponentName.getPackageName(),
+ mAppId, mUserId);
+ }
+ }, IllegalArgumentException.class);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.print(name, null, null, mGoodComponentName.getPackageName(),
+ mAppId, mUserId);
+ }
+ }, NullPointerException.class);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.print(name, adapter, null, null, mAppId, mUserId);
+ }
+ }, IllegalArgumentException.class);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.print(name, adapter, null, mBadComponentName.getPackageName(),
+ mAppId, mUserId);
+ }
+ }, IllegalArgumentException.class);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.print(name, adapter, null, mGoodComponentName.getPackageName(),
+ BAD_APP_ID, mUserId);
+ }
+ }, SecurityException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.cancelPrintJob
+ */
+ public void testCancelPrintJob() throws Exception {
+ // Invalid print jobs IDs do not produce an exception
+ mIPrintManager.cancelPrintJob(mBadPrintJobId, mAppId, mUserId);
+ mIPrintManager.cancelPrintJob(null, mAppId, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.cancelPrintJob(mGoodPrintJob.getId(), BAD_APP_ID, mUserId);
+ }
+ }, SecurityException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+
+ // Must be last as otherwise mGoodPrintJob will not be good anymore
+ mIPrintManager.cancelPrintJob(mGoodPrintJob.getId(), mAppId, mUserId);
+ }
+
+ /**
+ * test IPrintManager.restartPrintJob
+ */
+ public void testRestartPrintJob() throws Exception {
+ mIPrintManager.restartPrintJob(mGoodPrintJob.getId(), mAppId, mUserId);
+
+ // Invalid print jobs IDs do not produce an exception
+ mIPrintManager.restartPrintJob(mBadPrintJobId, mAppId, mUserId);
+ mIPrintManager.restartPrintJob(null, mAppId, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.restartPrintJob(mGoodPrintJob.getId(), BAD_APP_ID, mUserId);
+ }
+ }, SecurityException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.addPrintJobStateChangeListener
+ */
+ public void testAddPrintJobStateChangeListener() throws Exception {
+ final IPrintJobStateChangeListener listener = createMockIPrintJobStateChangeListener();
+
+ mIPrintManager.addPrintJobStateChangeListener(listener, mAppId, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.addPrintJobStateChangeListener(null, mAppId, mUserId);
+ }
+ }, NullPointerException.class);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.addPrintJobStateChangeListener(listener, BAD_APP_ID, mUserId);
+ }
+ }, SecurityException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.removePrintJobStateChangeListener
+ */
+ public void testRemovePrintJobStateChangeListener() throws Exception {
+ final IPrintJobStateChangeListener listener = createMockIPrintJobStateChangeListener();
+
+ mIPrintManager.addPrintJobStateChangeListener(listener, mAppId, mUserId);
+ mIPrintManager.removePrintJobStateChangeListener(listener, mUserId);
+
+ // Removing unknown listeners is a no-op
+ mIPrintManager.removePrintJobStateChangeListener(listener, mUserId);
+
+ mIPrintManager.addPrintJobStateChangeListener(listener, mAppId, mUserId);
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.removePrintJobStateChangeListener(null, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.getInstalledPrintServices
+ */
+ public void testGetInstalledPrintServices() throws Exception {
+ List<PrintServiceInfo> printServices = mIPrintManager.getInstalledPrintServices(mUserId);
+ assertTrue(printServices.size() >= 2);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.getEnabledPrintServices
+ */
+ public void testGetEnabledPrintServices() throws Exception {
+ List<PrintServiceInfo> printServices = mIPrintManager.getEnabledPrintServices(mUserId);
+ assertTrue(printServices.size() >= 2);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.createPrinterDiscoverySession
+ */
+ public void testCreatePrinterDiscoverySession() throws Exception {
+ final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
+
+ mIPrintManager.createPrinterDiscoverySession(listener, mUserId);
+
+ try {
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.createPrinterDiscoverySession(null, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ } finally {
+ // Remove discovery session so that the next test create a new one. Usually a leaked
+ // session is removed on the next call from the print service. But in this case we want
+ // to force a new call to onPrinterDiscoverySessionStart in the next test.
+ mIPrintManager.destroyPrinterDiscoverySession(listener, mUserId);
+ }
+ }
+
+ /**
+ * test IPrintManager.startPrinterDiscovery
+ */
+ public void testStartPrinterDiscovery() throws Exception {
+ final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
+ final List<PrinterId> goodPrinters = new ArrayList<>();
+ goodPrinters.add(mGoodPrinterId);
+
+ final List<PrinterId> badPrinters = new ArrayList<>();
+ badPrinters.add(mBadPrinterId);
+
+ final List<PrinterId> emptyPrinters = new ArrayList<>();
+
+ final List<PrinterId> nullPrinters = new ArrayList<>();
+ nullPrinters.add(null);
+
+ mIPrintManager.startPrinterDiscovery(listener, goodPrinters, mUserId);
+
+ // Bad or no printers do no cause exceptions
+ mIPrintManager.startPrinterDiscovery(listener, badPrinters, mUserId);
+ mIPrintManager.startPrinterDiscovery(listener, emptyPrinters, mUserId);
+ mIPrintManager.startPrinterDiscovery(listener, null, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.startPrinterDiscovery(listener, nullPrinters, mUserId);
+ }
+ }, NullPointerException.class);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.startPrinterDiscovery(null, goodPrinters, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.stopPrinterDiscovery
+ */
+ public void testStopPrinterDiscovery() throws Exception {
+ final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
+
+ mIPrintManager.startPrinterDiscovery(listener, null, mUserId);
+ mIPrintManager.stopPrinterDiscovery(listener, mUserId);
+
+ // Stopping an already stopped session is a no-op
+ mIPrintManager.stopPrinterDiscovery(listener, mUserId);
+
+ mIPrintManager.startPrinterDiscovery(listener, null, mUserId);
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.stopPrinterDiscovery(null, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.validatePrinters
+ */
+ public void testValidatePrinters() throws Exception {
+ final List<PrinterId> goodPrinters = new ArrayList<>();
+ goodPrinters.add(mGoodPrinterId);
+
+ final List<PrinterId> badPrinters = new ArrayList<>();
+ badPrinters.add(mBadPrinterId);
+
+ final List<PrinterId> emptyPrinters = new ArrayList<>();
+
+ final List<PrinterId> nullPrinters = new ArrayList<>();
+ nullPrinters.add(null);
+
+ mIPrintManager.validatePrinters(goodPrinters, mUserId);
+
+ // Bad or empty list of printers do no cause exceptions
+ mIPrintManager.validatePrinters(badPrinters, mUserId);
+ mIPrintManager.validatePrinters(emptyPrinters, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.validatePrinters(null, mUserId);
+ }
+ }, NullPointerException.class);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.validatePrinters(nullPrinters, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.startPrinterStateTracking
+ */
+ public void testStartPrinterStateTracking() throws Exception {
+ mIPrintManager.startPrinterStateTracking(mGoodPrinterId, mUserId);
+
+ // Bad printers do no cause exceptions
+ mIPrintManager.startPrinterStateTracking(mBadPrinterId, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.startPrinterStateTracking(null, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.getCustomPrinterIcon
+ */
+ public void testGetCustomPrinterIcon() throws Exception {
+ mIPrintManager.getCustomPrinterIcon(mGoodPrinterId, mUserId);
+
+ // Bad printers do no cause exceptions
+ mIPrintManager.getCustomPrinterIcon(mBadPrinterId, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.getCustomPrinterIcon(null, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.stopPrinterStateTracking
+ */
+ public void testStopPrinterStateTracking() throws Exception {
+ mIPrintManager.startPrinterStateTracking(mGoodPrinterId, mUserId);
+ mIPrintManager.stopPrinterStateTracking(mGoodPrinterId, mUserId);
+
+ // Stop to track a non-tracked printer is a no-op
+ mIPrintManager.stopPrinterStateTracking(mGoodPrinterId, mUserId);
+
+ // Bad printers do no cause exceptions
+ mIPrintManager.startPrinterStateTracking(mBadPrinterId, mUserId);
+ mIPrintManager.stopPrinterStateTracking(mBadPrinterId, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.stopPrinterStateTracking(null, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.destroyPrinterDiscoverySession
+ */
+ public void testDestroyPrinterDiscoverySession() throws Exception {
+ final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
+
+ mIPrintManager.createPrinterDiscoverySession(listener, mUserId);
+ mIPrintManager.destroyPrinterDiscoverySession(listener, mUserId);
+
+ // Destroying already destroyed session is a no-op
+ mIPrintManager.destroyPrinterDiscoverySession(listener, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.destroyPrinterDiscoverySession(null, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+}
diff --git a/core/tests/coretests/src/android/print/PrintTestActivity.java b/core/tests/coretests/src/android/print/PrintTestActivity.java
new file mode 100644
index 0000000..86074a6
--- /dev/null
+++ b/core/tests/coretests/src/android/print/PrintTestActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public class PrintTestActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+ }
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/MockPrintService.java b/core/tests/coretests/src/android/print/mockservice/MockPrintService.java
new file mode 100644
index 0000000..9c11c22
--- /dev/null
+++ b/core/tests/coretests/src/android/print/mockservice/MockPrintService.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.mockservice;
+
+public class MockPrintService extends StubbablePrintService {
+
+ private static final Object sLock = new Object();
+
+ private static PrintServiceCallbacks sCallbacks;
+
+ public static void setCallbacks(PrintServiceCallbacks callbacks) {
+ synchronized (sLock) {
+ sCallbacks = callbacks;
+ }
+ }
+
+ @Override
+ protected PrintServiceCallbacks getCallbacks() {
+ synchronized (sLock) {
+ if (sCallbacks != null) {
+ sCallbacks.setService(this);
+ }
+ return sCallbacks;
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/PrintServiceCallbacks.java b/core/tests/coretests/src/android/print/mockservice/PrintServiceCallbacks.java
new file mode 100644
index 0000000..4e89207
--- /dev/null
+++ b/core/tests/coretests/src/android/print/mockservice/PrintServiceCallbacks.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.mockservice;
+
+import android.printservice.PrintJob;
+import android.printservice.PrintService;
+
+public abstract class PrintServiceCallbacks {
+
+ private PrintService mService;
+
+ public PrintService getService() {
+ return mService;
+ }
+
+ public void setService(PrintService service) {
+ mService = service;
+ }
+
+ public abstract PrinterDiscoverySessionCallbacks onCreatePrinterDiscoverySessionCallbacks();
+
+ public abstract void onRequestCancelPrintJob(PrintJob printJob);
+
+ public abstract void onPrintJobQueued(PrintJob printJob);
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java b/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java
new file mode 100644
index 0000000..26b7cae
--- /dev/null
+++ b/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.mockservice;
+
+import android.print.PrinterId;
+import android.printservice.CustomPrinterIconCallback;
+
+import java.util.List;
+
+public abstract class PrinterDiscoverySessionCallbacks {
+
+ private StubbablePrinterDiscoverySession mSession;
+
+ public void setSession(StubbablePrinterDiscoverySession session) {
+ mSession = session;
+ }
+
+ public StubbablePrinterDiscoverySession getSession() {
+ return mSession;
+ }
+
+ public abstract void onStartPrinterDiscovery(List<PrinterId> priorityList);
+
+ public abstract void onStopPrinterDiscovery();
+
+ public abstract void onValidatePrinters(List<PrinterId> printerIds);
+
+ public abstract void onStartPrinterStateTracking(PrinterId printerId);
+
+ public abstract void onRequestCustomPrinterIcon(PrinterId printerId,
+ CustomPrinterIconCallback callback);
+
+ public abstract void onStopPrinterStateTracking(PrinterId printerId);
+
+ public abstract void onDestroy();
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/SettingsActivity.java b/core/tests/coretests/src/android/print/mockservice/SettingsActivity.java
new file mode 100644
index 0000000..fb76e67
--- /dev/null
+++ b/core/tests/coretests/src/android/print/mockservice/SettingsActivity.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.mockservice;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class SettingsActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/StubbablePrintService.java b/core/tests/coretests/src/android/print/mockservice/StubbablePrintService.java
new file mode 100644
index 0000000..b58b2735
--- /dev/null
+++ b/core/tests/coretests/src/android/print/mockservice/StubbablePrintService.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.mockservice;
+
+import android.printservice.PrintJob;
+import android.printservice.PrintService;
+import android.printservice.PrinterDiscoverySession;
+
+public abstract class StubbablePrintService extends PrintService {
+
+ @Override
+ public PrinterDiscoverySession onCreatePrinterDiscoverySession() {
+ PrintServiceCallbacks callbacks = getCallbacks();
+ if (callbacks != null) {
+ return new StubbablePrinterDiscoverySession(this,
+ getCallbacks().onCreatePrinterDiscoverySessionCallbacks());
+ }
+ return null;
+ }
+
+ @Override
+ public void onRequestCancelPrintJob(PrintJob printJob) {
+ PrintServiceCallbacks callbacks = getCallbacks();
+ if (callbacks != null) {
+ callbacks.onRequestCancelPrintJob(printJob);
+ }
+ }
+
+ @Override
+ public void onPrintJobQueued(PrintJob printJob) {
+ PrintServiceCallbacks callbacks = getCallbacks();
+ if (callbacks != null) {
+ callbacks.onPrintJobQueued(printJob);
+ }
+ }
+
+ protected abstract PrintServiceCallbacks getCallbacks();
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java b/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java
new file mode 100644
index 0000000..04683f2
--- /dev/null
+++ b/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print.mockservice;
+
+import android.print.PrinterId;
+import android.printservice.CustomPrinterIconCallback;
+import android.printservice.PrintService;
+import android.printservice.PrinterDiscoverySession;
+
+import java.util.List;
+
+public class StubbablePrinterDiscoverySession extends PrinterDiscoverySession {
+ private final PrintService mService;
+ private final PrinterDiscoverySessionCallbacks mCallbacks;
+
+ public StubbablePrinterDiscoverySession(PrintService service,
+ PrinterDiscoverySessionCallbacks callbacks) {
+ mService = service;
+ mCallbacks = callbacks;
+ if (mCallbacks != null) {
+ mCallbacks.setSession(this);
+ }
+ }
+
+ public PrintService getService() {
+ return mService;
+ }
+
+ @Override
+ public void onStartPrinterDiscovery(List<PrinterId> priorityList) {
+ if (mCallbacks != null) {
+ mCallbacks.onStartPrinterDiscovery(priorityList);
+ }
+ }
+
+ @Override
+ public void onStopPrinterDiscovery() {
+ if (mCallbacks != null) {
+ mCallbacks.onStopPrinterDiscovery();
+ }
+ }
+
+ @Override
+ public void onValidatePrinters(List<PrinterId> printerIds) {
+ if (mCallbacks != null) {
+ mCallbacks.onValidatePrinters(printerIds);
+ }
+ }
+
+ @Override
+ public void onStartPrinterStateTracking(PrinterId printerId) {
+ if (mCallbacks != null) {
+ mCallbacks.onStartPrinterStateTracking(printerId);
+ }
+ }
+
+ @Override
+ public void onRequestCustomPrinterIcon(PrinterId printerId,
+ CustomPrinterIconCallback callback) {
+ if (mCallbacks != null) {
+ mCallbacks.onRequestCustomPrinterIcon(printerId, callback);
+ }
+ }
+
+ @Override
+ public void onStopPrinterStateTracking(PrinterId printerId) {
+ if (mCallbacks != null) {
+ mCallbacks.onStopPrinterStateTracking(printerId);
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ if (mCallbacks != null) {
+ mCallbacks.onDestroy();
+ }
+ }
+}
diff --git a/docs/html/preview/support.jd b/docs/html/preview/support.jd
index cfd9467..8c392aa 100644
--- a/docs/html/preview/support.jd
+++ b/docs/html/preview/support.jd
@@ -160,20 +160,21 @@
still perform BTLE and WiFi scans, but only when they are in the foreground. While in the background, those apps will get no results from BTLE and WiFi scans.</li>
</ul>
</li>
- <li>Permission changes
+ <li>Accessing accounts
<ul>
- <li>Updated the user interface for permissions and enhanced some of the permissions
- behaviors.</li>
- <li>The {@link android.Manifest.permission#GET_ACCOUNTS} permission is now a member of the
- {@link android.Manifest.permission_group#CONTACTS} permission group and it has a
- {@code android:protectionLevel} of {@code dangerous}. This change means that when
- targeting Android 6.0 (API level 23), you must check for and request this permission if
- your app requires it.
+ <li>Updated the behavior of {@link android.accounts.AccountManager} account
+ discovery methods.
</li>
-
- <li>The {@code android.permission.READ_PROFILE} and {@code android.permission.WRITE_PROFILE}
- permissions have been removed from the {@link android.Manifest.permission_group#CONTACTS}
- permission group.
+ <li>The GET_ACCOUNTS permission has been deprecated.
+ </li>
+ <li>Apps targeting API level 24 should start the intent returned by
+ newChooseAccountIntent(...) and await the result to acquire a reference
+ to the user's selected account. AccountManager methods like getAccounts and
+ related methods will only return those accounts managed by
+ authenticators that match the signatures of the calling app.
+ </li>
+ <li>Apps targeting API level 23 or earlier will continue to behave as
+ before.
</li>
</ul>
</li>
diff --git a/docs/html/training/id-auth/identify.jd b/docs/html/training/id-auth/identify.jd
index db9ab3a..4c399f9 100644
--- a/docs/html/training/id-auth/identify.jd
+++ b/docs/html/training/id-auth/identify.jd
@@ -15,8 +15,7 @@
<ol>
<li><a href="#ForYou">Determine if AccountManager is for You</a></li>
<li><a href="#TaskTwo">Decide What Type of Account to Use</a></li>
- <li><a href="#GetPermission">Request GET_ACCOUNT permission</a></li>
- <li><a href="#TaskFive">Query AccountManager for a List of Accounts</a></li>
+ <li><a href="#QueryAccounts">Query the user for an Account</a></li>
<li><a href="#IdentifyUser">Use the Account Object to Personalize Your App</a></li>
<li><a href="#IdIsEnough">Decide Whether an Account Name is Enough</a></li>
</ol>
@@ -71,48 +70,46 @@
<h2 id="TaskTwo">Decide What Type of Account to Use</h2>
<p>Android devices can store multiple accounts from many different providers.
-When you query {@link android.accounts.AccountManager} for account names, you can choose to filter
-by
-account type. The account type is a string that uniquely identifies the entity
-that issued the account. For instance, Google accounts have type "com.google,"
-while Twitter uses "com.twitter.android.auth.login."</p>
+When you query {@link android.accounts.AccountManager} for account names, you
+can choose to filter by account type. The account type is a string that
+uniquely identifies the entity that issued the account. For instance, Google
+accounts have type "com.google," while Twitter uses
+"com.twitter.android.auth.login."</p>
+<h2 id="QueryAccounts">Query the user for an Account</h2>
-<h2 id="GetPermission">Request GET_ACCOUNT permission</h2>
-
-<p>In order to get a list of accounts on the device, your app needs the {@link
-android.Manifest.permission#GET_ACCOUNTS}
-permission. Add a <a href="{@docRoot}guide/topics/manifest/uses-permission-element.html">{@code
-<uses-permission>}</a> tag in your manifest file to request
-this permission:</p>
+<p>Once an account type has been determined, you can prompt the user with an
+account chooser as follows:
<pre>
-<manifest ... >
- <uses-permission android:name="android.permission.GET_ACCOUNTS" />
- ...
-</manifest>
+AccountManager am = AccountManager.get(this); // "this" reference the current Context
+Intent chooserIntent = am.newChooseAccountIntent(
+ null, // currently select account
+ null, // list of accounts that are allowed to be shown
+ new String[] { "com.google" }, // Only allow the user to select Google accounts
+ false,
+ null, // description text
+ null, // add account auth token type
+ null, // required features for added accounts
+ null); // options for adding an account
+this.startActivityForResult(chooserIntent, MY_REQUEST_CODE);
</pre>
-
-<h2 id="TaskFive">Query AccountManager for a List of Accounts</h2>
-
-<p>Once you decide what account type you're interested in, you need to query for accounts of that
-type. Get an instance of {@link android.accounts.AccountManager} by calling {@link
-android.accounts.AccountManager#get(android.content.Context) AccountManager.get()}. Then use that
-instance to call {@link android.accounts.AccountManager#getAccountsByType(java.lang.String)
-getAccountsByType()}.</p>
+<p>Once the chooser intent is started, the user will be presented with a list of
+appropriately typed accounts. From this list they will select one which will be
+returned to your app upon onActivityResult as follows:
<pre>
-AccountManager am = AccountManager.get(this); // "this" references the current Context
-
-Account[] accounts = am.getAccountsByType("com.google");
+protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == MY_REQUEST_CODE && resultCode == RESULT_OK) {
+ String name = data.getStringExtra(AccountManage.KEY_ACCOUNT_NAME);
+ String type = data.getStringExtra(AccountManage.KEY_ACCOUNT_TYPE);
+ Account selectedAccount = new Account(name, type);
+ doSomethingWithSelectedAccount(selectedAccount);
+ }
+}
</pre>
-<p>This returns an array of {@link android.accounts.Account} objects. If there's more than one
-{@link android.accounts.Account} in
-the array, you should present a dialog asking the user to select one.</p>
-
-
<h2 id="IdentifyUser">Use the Account Object to Personalize Your App</h2>
<p>The {@link android.accounts.Account} object contains an account name, which for Google accounts
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 84ca546..1857345 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -19,7 +19,6 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.Animator.AnimatorListener;
-import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.ColorStateList;
@@ -141,15 +140,6 @@
/** Local, mutable animator set. */
private final AnimatorSet mAnimatorSet = new AnimatorSet();
-
- private final ValueAnimator.AnimatorUpdateListener mUpdateListener =
- new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- invalidateSelf();
- }
- };
-
/**
* The resources against which this drawable was created. Used to attempt
* to inflate animators if applyTheme() doesn't get called.
@@ -211,6 +201,9 @@
@Override
public void draw(Canvas canvas) {
mAnimatedVectorState.mVectorDrawable.draw(canvas);
+ if (isStarted()) {
+ invalidateSelf();
+ }
}
@Override
@@ -493,7 +486,6 @@
* animators, or {@code null} if not available
*/
public void prepareLocalAnimators(@NonNull AnimatorSet animatorSet,
- @NonNull ValueAnimator.AnimatorUpdateListener updateListener,
@Nullable Resources res) {
// Check for uninflated animators. We can remove this after we add
// support for Animator.applyTheme(). See comments in inflate().
@@ -519,17 +511,6 @@
final Animator nextAnim = prepareLocalAnimator(i);
builder.with(nextAnim);
}
-
- // Setup a value animator to get animation update callbacks.
- long totalDuration = animatorSet.getTotalDuration();
- ValueAnimator updateAnim = ValueAnimator.ofFloat(0f, 1f);
- if (totalDuration == ValueAnimator.DURATION_INFINITE) {
- updateAnim.setRepeatCount(ValueAnimator.INFINITE);
- } else {
- updateAnim.setDuration(totalDuration);
- }
- updateAnim.addUpdateListener(updateListener);
- builder.with(updateAnim);
}
}
@@ -622,7 +603,7 @@
@NonNull
private void ensureAnimatorSet() {
if (!mHasAnimatorSet) {
- mAnimatedVectorState.prepareLocalAnimators(mAnimatorSet, mUpdateListener, mRes);
+ mAnimatedVectorState.prepareLocalAnimators(mAnimatorSet, mRes);
mHasAnimatorSet = true;
mRes = null;
}
diff --git a/libs/hwui/BufferPool.h b/libs/hwui/BufferPool.h
index 9bda233..005b399 100644
--- a/libs/hwui/BufferPool.h
+++ b/libs/hwui/BufferPool.h
@@ -16,8 +16,9 @@
#pragma once
-#include <utils/RefBase.h>
-#include <utils/Log.h>
+#include "utils/RefBase.h"
+#include "utils/Log.h"
+#include "utils/Macros.h"
#include <atomic>
#include <stdint.h>
@@ -37,6 +38,7 @@
class BufferPool : public VirtualLightRefBase {
public:
class Buffer {
+ PREVENT_COPY_AND_ASSIGN(Buffer);
public:
int64_t* getBuffer() { return mBuffer.get(); }
size_t getSize() { return mSize; }
@@ -57,14 +59,17 @@
return refs - 1;
}
+ bool isUniqueRef() {
+ return mRefs.load() == 1;
+ }
+
private:
friend class BufferPool;
- Buffer(BufferPool* pool, size_t size) {
+ Buffer(BufferPool* pool, size_t size) : mRefs(1) {
mSize = size;
mBuffer.reset(new int64_t[size]);
mPool = pool;
- mRefs++;
}
void setPool(BufferPool* pool) {
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 3e37a05..a457212 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -33,6 +33,15 @@
FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
uint32_t viewportWidth, uint32_t viewportHeight,
const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter)
+ : FrameBuilder(layers, clip, viewportWidth, viewportHeight, nodes, lightCenter,
+ Rect(0, 0, 0, 0)) {
+}
+
+
+FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
+ uint32_t viewportWidth, uint32_t viewportHeight,
+ const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter,
+ const Rect &contentDrawBounds)
: mCanvasState(*this) {
ATRACE_NAME("prepare drawing commands");
@@ -72,14 +81,56 @@
}
}
- // Defer Fbo0
+ // It there are multiple render nodes, they are laid out as follows:
+ // #0 - backdrop (content + caption)
+ // #1 - content (positioned at (0,0) and clipped to - its bounds mContentDrawBounds)
+ // #2 - additional overlay nodes
+ // Usually the backdrop cannot be seen since it will be entirely covered by the content. While
+ // resizing however it might become partially visible. The following render loop will crop the
+ // backdrop against the content and draw the remaining part of it. It will then draw the content
+ // cropped to the backdrop (since that indicates a shrinking of the window).
+ //
+ // Additional nodes will be drawn on top with no particular clipping semantics.
+
+ // The bounds of the backdrop against which the content should be clipped.
+ Rect backdropBounds = contentDrawBounds;
+ // Usually the contents bounds should be mContentDrawBounds - however - we will
+ // move it towards the fixed edge to give it a more stable appearance (for the moment).
+ // If there is no content bounds we ignore the layering as stated above and start with 2.
+ int layer = (contentDrawBounds.isEmpty() || nodes.size() == 1) ? 2 : 0;
+
for (const sp<RenderNode>& node : nodes) {
if (node->nothingToDraw()) continue;
node->computeOrdering();
-
int count = mCanvasState.save(SaveFlags::MatrixClip);
+
+ if (layer == 0) {
+ const RenderProperties& properties = node->properties();
+ Rect targetBounds(properties.getLeft(), properties.getTop(),
+ properties.getRight(), properties.getBottom());
+ // Move the content bounds towards the fixed corner of the backdrop.
+ const int x = targetBounds.left;
+ const int y = targetBounds.top;
+ // Remember the intersection of the target bounds and the intersection bounds against
+ // which we have to crop the content.
+ backdropBounds.set(x, y, x + backdropBounds.getWidth(), y + backdropBounds.getHeight());
+ backdropBounds.doIntersect(targetBounds);
+ } else if (layer == 1) {
+ // We shift and clip the content to match its final location in the window.
+ const float left = contentDrawBounds.left;
+ const float top = contentDrawBounds.top;
+ const float dx = backdropBounds.left - left;
+ const float dy = backdropBounds.top - top;
+ const float width = backdropBounds.getWidth();
+ const float height = backdropBounds.getHeight();
+ mCanvasState.translate(dx, dy);
+ // It gets cropped against the bounds of the backdrop to stay inside.
+ mCanvasState.clipRect(left, top, left + width, top + height, SkRegion::kIntersect_Op);
+ }
+
deferNodePropsAndOps(*node);
mCanvasState.restoreToCount(count);
+ layer++;
}
}
diff --git a/libs/hwui/FrameBuilder.h b/libs/hwui/FrameBuilder.h
index 4fd39be..dea9934 100644
--- a/libs/hwui/FrameBuilder.h
+++ b/libs/hwui/FrameBuilder.h
@@ -59,6 +59,11 @@
uint32_t viewportWidth, uint32_t viewportHeight,
const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter);
+ FrameBuilder(const LayerUpdateQueue& layers, const SkRect& clip,
+ uint32_t viewportWidth, uint32_t viewportHeight,
+ const std::vector< sp<RenderNode> >& nodes, const Vector3& lightCenter,
+ const Rect &contentDrawBounds);
+
virtual ~FrameBuilder() {}
/**
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 7148c4b..e7cf3ec 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -345,7 +345,7 @@
#if HWUI_NEW_OPS
FrameBuilder frameBuilder(mLayerUpdateQueue, dirty, frame.width(), frame.height(),
- mRenderNodes, mLightCenter);
+ mRenderNodes, mLightCenter, mContentDrawBounds);
mLayerUpdateQueue.clear();
BakedOpRenderer renderer(Caches::getInstance(), mRenderThread.renderState(),
mOpaque, mLightInfo);
diff --git a/libs/hwui/tests/unit/BufferPoolTests.cpp b/libs/hwui/tests/unit/BufferPoolTests.cpp
index 09bd302..44e6d3a 100644
--- a/libs/hwui/tests/unit/BufferPoolTests.cpp
+++ b/libs/hwui/tests/unit/BufferPoolTests.cpp
@@ -36,6 +36,7 @@
ASSERT_EQ(bufferCount - i, pool->getAvailableBufferCount());
acquiredBuffers[i] = pool->acquire();
ASSERT_NE(nullptr, acquiredBuffers[i]);
+ ASSERT_TRUE(acquiredBuffers[i]->isUniqueRef());
}
for (size_t i = 0; i < bufferCount; i++) {
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index b75724c..618df14 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -215,7 +215,8 @@
<< "Expect number of ops = 2 * loop count";
}
-TEST(FrameBuilder, clippedMerging) {
+// TODO: Disabled due to b/26793764
+TEST(FrameBuilder, DISABLED_clippedMerging) {
class ClippedMergingTestRenderer : public TestRendererBase {
public:
void onMergedBitmapOps(const MergedBakedOpList& opList) override {
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 504c6d0..9517387 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -389,6 +389,7 @@
public static final int H264 = 2;
public static final int MPEG_4_SP = 3;
public static final int VP8 = 4;
+ public static final int HEVC = 5;
}
/**
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 9c01f4f..f37ec58 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -1291,6 +1291,7 @@
boolean createGlInterface = false;
boolean lostEglContext = false;
boolean sizeChanged = false;
+ boolean wantRenderNotification = false;
boolean doRenderNotification = false;
boolean askedToReleaseEglContext = false;
int w = 0;
@@ -1448,6 +1449,9 @@
}
mRequestRender = false;
sGLThreadManager.notifyAll();
+ if (mWantRenderNotification) {
+ wantRenderNotification = true;
+ }
break;
}
}
@@ -1574,8 +1578,9 @@
break;
}
- if (mWantRenderNotification) {
+ if (wantRenderNotification) {
doRenderNotification = true;
+ wantRenderNotification = false;
}
}
@@ -1625,11 +1630,21 @@
public void requestRenderAndWait() {
synchronized(sGLThreadManager) {
+ // If we are already on the GL thread, this means a client callback
+ // has caused reentrancy, for example via updating the SurfaceView parameters.
+ // We will return to the client rendering code, so here we don't need to
+ // do anything.
+ if (Thread.currentThread() == this) {
+ return;
+ }
+
mWantRenderNotification = true;
mRequestRender = true;
mRenderComplete = false;
+
sGLThreadManager.notifyAll();
- while (!mExited && !mPaused && mRenderComplete == false) {
+
+ while (!mExited && !mPaused && !mRenderComplete && ableToDraw()) {
try {
sGLThreadManager.wait();
} catch (InterruptedException ex) {
@@ -1726,6 +1741,16 @@
mSizeChanged = true;
mRequestRender = true;
mRenderComplete = false;
+
+ // If we are already on the GL thread, this means a client callback
+ // has caused reentrancy, for example via updating the SurfaceView parameters.
+ // We need to process the size change eventually though and update our EGLSurface.
+ // So we set the parameters and return so they can be processed on our
+ // next iteration.
+ if (Thread.currentThread() == this) {
+ return;
+ }
+
sGLThreadManager.notifyAll();
// Wait for thread to react to resize and render a frame
diff --git a/packages/DocumentsUI/res/layout/item_dir_grid.xml b/packages/DocumentsUI/res/layout/item_dir_grid.xml
index a08e029..b0331be 100644
--- a/packages/DocumentsUI/res/layout/item_dir_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_dir_grid.xml
@@ -17,7 +17,7 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:layout_margin="@dimen/grid_item_margin"
android:background="@color/item_doc_background"
android:elevation="5dp"
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index f43b81c..ad8b0d1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -107,6 +107,8 @@
? icicle.<State>getParcelable(EXTRA_STATE)
: buildState();
+ Metrics.logActivityLaunch(this, mState, getIntent());
+
setContentView(mLayoutId);
mRoots = DocumentsApplication.getRootsCache(this);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index 58537ee..5abe7f6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -282,6 +282,7 @@
}
private void createNewWindow() {
+ Metrics.logMultiWindow(this);
Intent intent = LauncherActivity.createLaunchIntent(this);
intent.putExtra(Shared.EXTRA_STACK, (Parcelable) mState.stack);
startActivity(intent);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Metrics.java b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
new file mode 100644
index 0000000..eb90b75
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/Metrics.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import static com.android.documentsui.Shared.DEBUG;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.provider.DocumentsContract;
+import android.util.Log;
+
+import com.android.documentsui.model.RootInfo;
+import com.android.internal.logging.MetricsLogger;
+
+/** @hide */
+public final class Metrics {
+ private static final String TAG = "Metrics";
+
+ // These are the native provider authorities that the metrics code is capable of recognizing and
+ // explicitly counting.
+ private static final String AUTHORITY_MEDIA = "com.android.providers.media.documents";
+ private static final String AUTHORITY_STORAGE = "com.android.externalstorage.documents";
+ private static final String AUTHORITY_DOWNLOADS = "com.android.providers.downloads.documents";
+
+ // These strings have to be whitelisted in tron. Do not change them.
+ private static final String COUNT_LAUNCH_ACTION = "docsui_launch_action";
+ private static final String COUNT_ROOT_VISITED = "docsui_root_visited";
+ private static final String COUNT_OPEN_MIME = "docsui_open_mime";
+ private static final String COUNT_CREATE_MIME = "docsui_create_mime";
+ private static final String COUNT_GET_CONTENT_MIME = "docsui_get_content_mime";
+ private static final String COUNT_BROWSE_ROOT = "docsui_browse_root";
+ private static final String COUNT_MANAGE_ROOT = "docsui_manage_root";
+ private static final String COUNT_MULTI_WINDOW = "docsui_multi_window";
+
+ // Indices for bucketing roots in the roots histogram. "Other" is the catch-all index for any
+ // root that is not explicitly recognized by the Metrics code (see {@link
+ // #getSanitizedRootIndex}). Apps are also bucketed in this histogram using negative indices
+ // (see below).
+ private static final int ROOT_NONE = 0;
+ private static final int ROOT_OTHER = 1;
+ private static final int ROOT_AUDIO = 2;
+ private static final int ROOT_DEVICE_STORAGE = 3;
+ private static final int ROOT_DOWNLOADS = 4;
+ private static final int ROOT_HOME = 5;
+ private static final int ROOT_IMAGES = 6;
+ private static final int ROOT_RECENTS = 7;
+ private static final int ROOT_VIDEOS = 8;
+ // Apps aren't really "roots", but they are treated as such in the roots fragment UI and so they
+ // are logged analogously to roots. Use negative numbers to identify apps.
+ private static final int ROOT_THIRD_PARTY_APP = -1;
+
+ // Indices for bucketing mime types.
+ private static final int MIME_OTHER = -2; // anything not enumerated below
+ private static final int MIME_NONE = -1; // null mime
+ private static final int MIME_ANY = 0; // */*
+ private static final int MIME_APPLICATION = 1; // application/*
+ private static final int MIME_AUDIO = 2; // audio/*
+ private static final int MIME_IMAGE = 3; // image/*
+ private static final int MIME_MESSAGE = 4; // message/*
+ private static final int MIME_MULTIPART = 5; // multipart/*
+ private static final int MIME_TEXT = 6; // text/*
+ private static final int MIME_VIDEO = 7; // video/*
+
+ /**
+ * Logs when DocumentsUI is started, and how. Call this when DocumentsUI first starts up.
+ *
+ * @param context
+ * @param state
+ * @param intent
+ */
+ public static void logActivityLaunch(Context context, State state, Intent intent) {
+ // Log the launch action.
+ logHistogram(context, COUNT_LAUNCH_ACTION, state.action);
+ // Then log auxiliary data (roots/mime types) associated with some actions.
+ Uri uri = intent.getData();
+ switch (state.action) {
+ case State.ACTION_OPEN:
+ logHistogram(context, COUNT_OPEN_MIME, sanitizeMime(intent.getType()));
+ break;
+ case State.ACTION_CREATE:
+ logHistogram(context, COUNT_CREATE_MIME, sanitizeMime(intent.getType()));
+ break;
+ case State.ACTION_GET_CONTENT:
+ logHistogram(context, COUNT_GET_CONTENT_MIME, sanitizeMime(intent.getType()));
+ break;
+ case State.ACTION_MANAGE:
+ logHistogram(context, COUNT_MANAGE_ROOT, sanitizeRoot(uri));
+ break;
+ case State.ACTION_BROWSE:
+ logHistogram(context, COUNT_BROWSE_ROOT, sanitizeRoot(uri));
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Logs a root visited event. Call this when the user clicks on a root in the RootsFragment.
+ *
+ * @param context
+ * @param info
+ */
+ public static void logRootVisited(Context context, RootInfo info) {
+ logHistogram(context, COUNT_ROOT_VISITED, sanitizeRoot(info));
+ }
+
+ /**
+ * Logs an app visited event. Call this when the user clicks on an app in the RootsFragment.
+ *
+ * @param context
+ * @param info
+ */
+ public static void logAppVisited(Context context, ResolveInfo info) {
+ logHistogram(context, COUNT_ROOT_VISITED, sanitizeRoot(info));
+ }
+
+ /**
+ * Logs a multi-window start. Call this when the user spawns a new DocumentsUI window.
+ *
+ * @param context
+ */
+ public static void logMultiWindow(Context context) {
+ logCount(context, COUNT_MULTI_WINDOW);
+ }
+
+ /**
+ * Internal method for making a MetricsLogger.count call. Increments the given counter by 1.
+ *
+ * @param context
+ * @param name The counter to increment.
+ */
+ private static void logCount(Context context, String name) {
+ if (DEBUG) Log.d(TAG, name + ": " + 1);
+ MetricsLogger.count(context, name, 1);
+ }
+
+ /**
+ * Internal method for making a MetricsLogger.histogram call.
+ *
+ * @param context
+ * @param name The name of the histogram.
+ * @param bucket The bucket to increment.
+ */
+ private static void logHistogram(Context context, String name, int bucket) {
+ if (DEBUG) Log.d(TAG, name + ": " + bucket);
+ MetricsLogger.histogram(context, name, bucket);
+ }
+
+ /**
+ * Generates an integer identifying the given root. For privacy, this function only recognizes a
+ * small set of hard-coded roots (ones provided by the system). Other roots are all grouped into
+ * a single ROOT_OTHER bucket.
+ */
+ private static int sanitizeRoot(Uri uri) {
+ if (LauncherActivity.isLaunchUri(uri)) {
+ return ROOT_NONE;
+ }
+
+ switch (uri.getAuthority()) {
+ case AUTHORITY_MEDIA:
+ switch (DocumentsContract.getRootId(uri)) {
+ case "audio_root":
+ return ROOT_AUDIO;
+ case "images_root":
+ return ROOT_IMAGES;
+ case "videos_root":
+ return ROOT_VIDEOS;
+ default:
+ return ROOT_OTHER;
+ }
+ case AUTHORITY_STORAGE:
+ if ("home".equals(DocumentsContract.getRootId(uri))) {
+ return ROOT_HOME;
+ } else {
+ return ROOT_DEVICE_STORAGE;
+ }
+ case AUTHORITY_DOWNLOADS:
+ return ROOT_DOWNLOADS;
+ default:
+ return ROOT_OTHER;
+ }
+ }
+
+ /** @see #sanitizeRoot(Uri) */
+ private static int sanitizeRoot(RootInfo root) {
+ if (root.isRecents()) {
+ // Recents root is special and only identifiable via this method call. Other roots are
+ // identified by URI.
+ return ROOT_RECENTS;
+ } else {
+ return sanitizeRoot(root.getUri());
+ }
+ }
+
+ /** @see #sanitizeRoot(Uri) */
+ private static int sanitizeRoot(ResolveInfo info) {
+ // Log all apps under a single bucket in the roots histogram.
+ return ROOT_THIRD_PARTY_APP;
+ }
+
+ /**
+ * Generates an int identifying a mime type. For privacy, this function only recognizes a small
+ * set of hard-coded types. For any other type, this function returns "other".
+ *
+ * @param mimeType
+ * @return
+ */
+ private static int sanitizeMime(String mimeType) {
+ if (mimeType == null) {
+ return MIME_NONE;
+ } else if ("*/*".equals(mimeType)) {
+ return MIME_ANY;
+ } else {
+ String type = mimeType.substring(0, mimeType.indexOf('/'));
+ switch (type) {
+ case "application":
+ return MIME_APPLICATION;
+ case "audio":
+ return MIME_AUDIO;
+ case "image":
+ return MIME_IMAGE;
+ case "message":
+ return MIME_MESSAGE;
+ case "multipart":
+ return MIME_MULTIPART;
+ case "text":
+ return MIME_TEXT;
+ case "video":
+ return MIME_VIDEO;
+ }
+ }
+ // Bucket all other types into one bucket.
+ return MIME_OTHER;
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index beff196..c2aeb86 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -180,10 +180,14 @@
Item item = mAdapter.getItem(position);
if (item instanceof RootItem) {
BaseActivity activity = BaseActivity.get(RootsFragment.this);
- activity.onRootPicked(((RootItem) item).root);
+ RootInfo info = ((RootItem) item).root;
+ Metrics.logRootVisited(getActivity(), info);
+ activity.onRootPicked(info);
} else if (item instanceof AppItem) {
DocumentsActivity activity = DocumentsActivity.get(RootsFragment.this);
- activity.onAppPicked(((AppItem) item).info);
+ ResolveInfo info = ((AppItem) item).info;
+ Metrics.logAppVisited(getActivity(), info);
+ activity.onAppPicked(info);
} else if (item instanceof SpacerItem) {
if (DEBUG) Log.d(TAG, "Ignoring click on spacer item.");
} else {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 809db31..74fa8d0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -385,6 +385,7 @@
FileOperations.start(
getActivity(),
getDisplayState().selectedDocumentsForCopy,
+ getDisplayState().stack.peek(),
(DocumentStack) data.getParcelableExtra(Shared.EXTRA_STACK),
operationType);
}
@@ -782,20 +783,21 @@
private void deleteDocuments(final Selection selected) {
- checkArgument(!selected.isEmpty());
- new GetDocumentsTask() {
- @Override
- void onDocumentsReady(List<DocumentInfo> docs) {
- // Hide the files in the UI.
- final SparseArray<String> hidden = mAdapter.hide(selected.getAll());
+ checkArgument(!selected.isEmpty());
+ final DocumentInfo srcParent = getDisplayState().stack.peek();
+ new GetDocumentsTask() {
+ @Override
+ void onDocumentsReady(List<DocumentInfo> docs) {
+ // Hide the files in the UI.
+ final SparseArray<String> hidden = mAdapter.hide(selected.getAll());
- checkState(DELETE_JOB_DELAY > DELETE_UNDO_TIMEOUT);
- String operationId = FileOperations.delete(
- getActivity(), docs, getDisplayState().stack,
- DELETE_JOB_DELAY);
- showDeleteSnackbar(hidden, operationId);
- }
- }.execute(selected);
+ checkState(DELETE_JOB_DELAY > DELETE_UNDO_TIMEOUT);
+ String operationId = FileOperations.delete(
+ getActivity(), docs, srcParent, getDisplayState().stack,
+ DELETE_JOB_DELAY);
+ showDeleteSnackbar(hidden, operationId);
+ }
+ }.execute(selected);
}
private void showDeleteSnackbar(final SparseArray<String> hidden, final String jobId) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
index f3195a7..1d8eba5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
@@ -199,7 +199,7 @@
"Copying " + srcInfo.displayName + " (" + srcInfo.derivedUri + ")"
+ " to " + dstInfo.displayName + " (" + dstInfo.derivedUri + ")");
- processDocument(srcInfo, dstInfo);
+ processDocument(srcInfo, null, dstInfo);
}
}
@@ -220,11 +220,15 @@
* Copies a the given document to the given location.
*
* @param src DocumentInfos for the documents to copy.
+ * @param srcParent DocumentInfo for the parent of the document to process.
* @param dstDirInfo The destination directory.
* @return True on success, false on failure.
* @throws RemoteException
+ *
+ * TODO: Stop passing srcParent, as it's not used for copy, but for move only.
*/
- boolean processDocument(DocumentInfo src, DocumentInfo dstDirInfo) throws RemoteException {
+ boolean processDocument(DocumentInfo src, DocumentInfo srcParent,
+ DocumentInfo dstDirInfo) throws RemoteException {
// TODO: When optimized copy kicks in, we'll not making any progress updates.
// For now. Local storage isn't using optimized copy.
@@ -332,7 +336,7 @@
cursor = getClient(srcDir).query(queryUri, queryColumns, null, null, null);
while (cursor.moveToNext() && !isCanceled()) {
DocumentInfo src = DocumentInfo.fromCursor(cursor, srcDir.authority);
- success &= processDocument(src, destDir);
+ success &= processDocument(src, srcDir, destDir);
}
} finally {
IoUtils.closeQuietly(cursor);
@@ -509,7 +513,7 @@
.append("CopyJob")
.append("{")
.append("id=" + id)
- .append("srcs=" + mSrcs)
+ .append(", srcs=" + mSrcs)
.append(", destination=" + stack)
.append("}")
.toString();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
index 6a2a794..eef696a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/DeleteJob.java
@@ -35,6 +35,7 @@
private static final String TAG = "DeleteJob";
private List<DocumentInfo> mSrcs;
+ final DocumentInfo mSrcParent;
/**
* Moves files to a destination identified by {@code destination}.
@@ -43,12 +44,14 @@
*
* @see @link {@link Job} constructor for most param descriptions.
*
- * @param srcs List of files to delete
+ * @param srcs List of files to delete.
+ * @param srcParent Parent of all source files.
*/
DeleteJob(Context service, Context appContext, Listener listener,
- String id, DocumentStack stack, List<DocumentInfo> srcs) {
+ String id, DocumentStack stack, List<DocumentInfo> srcs, DocumentInfo srcParent) {
super(service, appContext, listener, OPERATION_DELETE, id, stack);
this.mSrcs = srcs;
+ this.mSrcParent = srcParent;
}
@Override
@@ -75,6 +78,8 @@
void start() throws RemoteException {
for (DocumentInfo doc : mSrcs) {
if (DEBUG) Log.d(TAG, "Deleting document @ " + doc.derivedUri);
+ // TODO: Start using mSrcParent as soon as DocumentsProvider::removeDocument() is
+ // implemented.
if (!deleteDocument(doc)) {
Log.w(TAG, "Failed to delete document @ " + doc.derivedUri);
onFileFailed(doc);
@@ -88,7 +93,8 @@
.append("DeleteJob")
.append("{")
.append("id=" + id)
- .append("srcs=" + mSrcs)
+ .append(", srcs=" + mSrcs)
+ .append(", srcParent=" + mSrcParent)
.append(", location=" + stack)
.append("}")
.toString();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
index aca2d7a..5d74cdc 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
@@ -65,6 +65,11 @@
public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST";
public static final String EXTRA_FAILURE = "com.android.documentsui.FAILURE";
+ // This extra is used only for moving and deleting. Currently it's not the case,
+ // but in the future those files may be from multiple different parents. In
+ // such case, this needs to be replaced with pairs of parent and child.
+ public static final String EXTRA_SRC_PARENT = "com.android.documentsui.SRC_PARENT";
+
public static final int OPERATION_UNKNOWN = -1;
public static final int OPERATION_COPY = 1;
public static final int OPERATION_MOVE = 2;
@@ -152,14 +157,14 @@
Job job = null;
synchronized (mRunning) {
if (mWakeLock == null) {
- mWakeLock = mPowerManager.newWakeLock(
- PowerManager.PARTIAL_WAKE_LOCK, TAG);
+ mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
}
List<DocumentInfo> srcs = intent.getParcelableArrayListExtra(EXTRA_SRC_LIST);
+ DocumentInfo srcParent = intent.getParcelableExtra(EXTRA_SRC_PARENT);
DocumentStack stack = intent.getParcelableExtra(Shared.EXTRA_STACK);
- job = createJob(operationType, jobId, srcs, stack);
+ job = createJob(operationType, jobId, srcs, srcParent, stack);
if (job == null) {
return;
@@ -222,7 +227,8 @@
*/
@GuardedBy("mRunning")
private @Nullable Job createJob(
- @OpType int operationType, String id, List<DocumentInfo> srcs, DocumentStack stack) {
+ @OpType int operationType, String id, List<DocumentInfo> srcs, DocumentInfo srcParent,
+ DocumentStack stack) {
if (mRunning.containsKey(id)) {
Log.w(TAG, "Duplicate job id: " + id
@@ -236,10 +242,12 @@
job = jobFactory.createCopy(this, getApplicationContext(), this, id, stack, srcs);
break;
case OPERATION_MOVE:
- job = jobFactory.createMove(this, getApplicationContext(), this, id, stack, srcs);
+ job = jobFactory.createMove(this, getApplicationContext(), this, id, stack, srcs,
+ srcParent);
break;
case OPERATION_DELETE:
- job = jobFactory.createDelete(this, getApplicationContext(), this, id, stack, srcs);
+ job = jobFactory.createDelete(this, getApplicationContext(), this, id, stack, srcs,
+ srcParent);
break;
default:
throw new UnsupportedOperationException();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java
index f59a32a..9d017ee 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java
@@ -26,6 +26,7 @@
import static com.android.documentsui.services.FileOperationService.EXTRA_JOB_ID;
import static com.android.documentsui.services.FileOperationService.EXTRA_OPERATION;
import static com.android.documentsui.services.FileOperationService.EXTRA_SRC_LIST;
+import static com.android.documentsui.services.FileOperationService.EXTRA_SRC_PARENT;
import static com.android.documentsui.services.FileOperationService.OPERATION_COPY;
import static com.android.documentsui.services.FileOperationService.OPERATION_DELETE;
import static com.android.documentsui.services.FileOperationService.OPERATION_MOVE;
@@ -35,6 +36,7 @@
import android.content.Intent;
import android.content.res.Resources;
import android.os.Parcelable;
+import android.support.annotation.VisibleForTesting;
import android.support.design.widget.Snackbar;
import android.util.Log;
@@ -65,8 +67,8 @@
* Tries to start the activity. Returns the job id.
*/
public static String start(
- Activity activity, List<DocumentInfo> srcDocs, DocumentStack stack,
- int operationType) {
+ Activity activity, List<DocumentInfo> srcDocs,
+ DocumentStack stack, int operationType) {
if (DEBUG) Log.d(TAG, "Handling generic 'start' call.");
@@ -74,7 +76,7 @@
case OPERATION_COPY:
return FileOperations.copy(activity, srcDocs, stack);
case OPERATION_MOVE:
- return FileOperations.move(activity, srcDocs, stack);
+ throw new IllegalArgumentException("Moving requires providing the source parent.");
case OPERATION_DELETE:
throw new UnsupportedOperationException("Delete isn't currently supported.");
default:
@@ -83,14 +85,27 @@
}
/**
- * Makes a best effort to cancel operation identified by jobId.
- *
- * @param context Context for the intent.
- * @param jobId The id of the job to cancel.
- * Use {@link #createJobId} if you don't have one handy.
- * @param srcDocs A list of src files to copy.
- * @param dstStack The copy destination stack.
+ * Tries to start the activity. Returns the job id.
*/
+ public static String start(
+ Activity activity, List<DocumentInfo> srcDocs, DocumentInfo srcParent,
+ DocumentStack stack, int operationType) {
+
+ if (DEBUG) Log.d(TAG, "Handling generic 'start' call.");
+
+ switch (operationType) {
+ case OPERATION_COPY:
+ return FileOperations.copy(activity, srcDocs, stack);
+ case OPERATION_MOVE:
+ return FileOperations.move(activity, srcDocs, srcParent, stack);
+ case OPERATION_DELETE:
+ throw new UnsupportedOperationException("Delete isn't currently supported.");
+ default:
+ throw new UnsupportedOperationException("Unknown operation: " + operationType);
+ }
+ }
+
+ @VisibleForTesting
public static void cancel(Activity activity, String jobId) {
if (DEBUG) Log.d(TAG, "Attempting to canceling operation: " + jobId);
@@ -101,15 +116,7 @@
activity.startService(intent);
}
- /**
- * Starts the service for a copy operation.
- *
- * @param context Context for the intent.
- * @param jobId A unique jobid for this job.
- * Use {@link #createJobId} if you don't have one handy.
- * @param srcDocs A list of src files to copy.
- * @param destination The copy destination stack.
- */
+ @VisibleForTesting
public static String copy(
Activity activity, List<DocumentInfo> srcDocs, DocumentStack destination) {
String jobId = createJobId();
@@ -131,14 +138,17 @@
* @param jobId A unique jobid for this job.
* Use {@link #createJobId} if you don't have one handy.
* @param srcDocs A list of src files to copy.
+ * @param srcParent Parent of all the source documents.
* @param destination The move destination stack.
*/
public static String move(
- Activity activity, List<DocumentInfo> srcDocs, DocumentStack destination) {
+ Activity activity, List<DocumentInfo> srcDocs, DocumentInfo srcParent,
+ DocumentStack destination) {
String jobId = createJobId();
if (DEBUG) Log.d(TAG, "Initiating 'move' operation id: " + jobId);
- Intent intent = createBaseIntent(OPERATION_MOVE, activity, jobId, srcDocs, destination);
+ Intent intent = createBaseIntent(OPERATION_MOVE, activity, jobId, srcDocs, srcParent,
+ destination);
createSharedSnackBar(activity, R.plurals.move_begin, srcDocs.size())
.show();
@@ -154,16 +164,19 @@
* @param jobId A unique jobid for this job.
* Use {@link #createJobId} if you don't have one handy.
* @param srcDocs A list of src files to copy.
+ * @param srcParent Parent of all the source documents.
* @param delay Number of milliseconds to wait before executing the job.
* @return Id of the job.
*/
public static String delete(
- Activity activity, List<DocumentInfo> srcDocs, DocumentStack location, int delay) {
+ Activity activity, List<DocumentInfo> srcDocs, DocumentInfo srcParent,
+ DocumentStack location, int delay) {
String jobId = createJobId();
if (DEBUG) Log.d(TAG, "Initiating 'delete' operation id " + jobId
+ " delayed by " + delay + " milliseconds.");
- Intent intent = createBaseIntent(OPERATION_DELETE, activity, jobId, srcDocs, location);
+ Intent intent = createBaseIntent(OPERATION_DELETE, activity, jobId, srcDocs, srcParent,
+ location);
intent.putExtra(EXTRA_DELAY, delay);
activity.startService(intent);
@@ -171,7 +184,7 @@
}
/**
- * Starts the service for a move operation.
+ * Starts the service for an operation.
*
* @param jobId A unique jobid for this job.
* Use {@link #createJobId} if you don't have one handy.
@@ -179,13 +192,35 @@
* @return Id of the job.
*/
public static Intent createBaseIntent(
- @OpType int operationType, Context context, String jobId,
- List<DocumentInfo> srcDocs, DocumentStack localeStack) {
+ @OpType int operationType, Context context, String jobId, List<DocumentInfo> srcDocs,
+ DocumentStack localeStack) {
Intent intent = new Intent(context, FileOperationService.class);
intent.putExtra(EXTRA_JOB_ID, jobId);
- intent.putParcelableArrayListExtra(
- EXTRA_SRC_LIST, asArrayList(srcDocs));
+ intent.putParcelableArrayListExtra(EXTRA_SRC_LIST, asArrayList(srcDocs));
+ intent.putExtra(EXTRA_STACK, (Parcelable) localeStack);
+ intent.putExtra(EXTRA_OPERATION, operationType);
+
+ return intent;
+ }
+
+ /**
+ * Starts the service for an operation.
+ *
+ * @param jobId A unique jobid for this job.
+ * Use {@link #createJobId} if you don't have one handy.
+ * @param srcDocs A list of src files to copy.
+ * @param srcParent Parent of all the source documents.
+ * @return Id of the job.
+ */
+ public static Intent createBaseIntent(
+ @OpType int operationType, Context context, String jobId,
+ List<DocumentInfo> srcDocs, DocumentInfo srcParent, DocumentStack localeStack) {
+
+ Intent intent = new Intent(context, FileOperationService.class);
+ intent.putExtra(EXTRA_JOB_ID, jobId);
+ intent.putParcelableArrayListExtra(EXTRA_SRC_LIST, asArrayList(srcDocs));
+ intent.putExtra(EXTRA_SRC_PARENT, srcParent);
intent.putExtra(EXTRA_STACK, (Parcelable) localeStack);
intent.putExtra(EXTRA_OPERATION, operationType);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
index f351df9..9534d6c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
@@ -274,13 +274,15 @@
}
Job createMove(Context service, Context appContext, Listener listener,
- String id, DocumentStack stack, List<DocumentInfo> srcs) {
- return new MoveJob(service, appContext, listener, id, stack, srcs);
+ String id, DocumentStack stack, List<DocumentInfo> srcs,
+ DocumentInfo srcParent) {
+ return new MoveJob(service, appContext, listener, id, stack, srcs, srcParent);
}
Job createDelete(Context service, Context appContext, Listener listener,
- String id, DocumentStack stack, List<DocumentInfo> srcs) {
- return new DeleteJob(service, appContext, listener, id, stack, srcs);
+ String id, DocumentStack stack, List<DocumentInfo> srcs,
+ DocumentInfo srcParent) {
+ return new DeleteJob(service, appContext, listener, id, stack, srcs, srcParent);
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
index 2a0262c..9b72077 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
@@ -33,9 +33,11 @@
import java.util.List;
+// TODO: Stop extending CopyJob.
final class MoveJob extends CopyJob {
private static final String TAG = "MoveJob";
+ final DocumentInfo mSrcParent;
/**
* Moves files to a destination identified by {@code destination}.
@@ -45,10 +47,12 @@
* @see @link {@link Job} constructor for most param descriptions.
*
* @param srcs List of files to be moved.
+ * @param srcParent Parent of all source files.
*/
MoveJob(Context service, Context appContext, Listener listener,
- String id, DocumentStack destination, List<DocumentInfo> srcs) {
+ String id, DocumentStack destination, List<DocumentInfo> srcs, DocumentInfo srcParent) {
super(service, appContext, listener, OPERATION_MOVE, id, destination, srcs);
+ this.mSrcParent = srcParent;
}
@Override
@@ -76,8 +80,8 @@
R.plurals.move_error_notification_title, R.drawable.ic_menu_copy);
}
- @Override
- boolean processDocument(DocumentInfo src, DocumentInfo dest) throws RemoteException {
+ boolean processDocument(DocumentInfo src, DocumentInfo srcParent, DocumentInfo dest)
+ throws RemoteException {
// TODO: When optimized move kicks in, we're not making any progress updates. FIX IT!
@@ -86,7 +90,8 @@
if (src.authority.equals(dest.authority)) {
if ((src.flags & Document.FLAG_SUPPORTS_MOVE) != 0) {
if (DocumentsContract.moveDocument(getClient(src), src.derivedUri,
- Uri.EMPTY /* Not used yet */, dest.derivedUri) == null) {
+ srcParent != null ? srcParent.derivedUri : mSrcParent.derivedUri,
+ dest.derivedUri) == null) {
onFileFailed(src);
return false;
}
@@ -106,6 +111,7 @@
// If we couldn't do an optimized copy...we fall back to vanilla byte copy.
boolean copied = byteCopyDocument(src, dest);
+ // TODO: Replace deleteDocument() with removeDocument() once implemented.
return copied && !isCanceled() && deleteDocument(src);
}
@@ -115,7 +121,8 @@
.append("MoveJob")
.append("{")
.append("id=" + id)
- .append("srcs=" + mSrcs)
+ .append(", srcs=" + mSrcs)
+ .append(", srcParent=" + mSrcParent)
.append(", destination=" + stack)
.append("}")
.toString();
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/AbstractCopyJobTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/AbstractCopyJobTest.java
index ec21150..eb8a061 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/services/AbstractCopyJobTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/AbstractCopyJobTest.java
@@ -23,6 +23,7 @@
import android.test.suitebuilder.annotation.MediumTest;
import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
import java.util.List;
@@ -109,7 +110,9 @@
public void runNoCopyDirToSelfTest() throws Exception {
Uri testDir = mDocs.createFolder(mSrcRoot, "someDir");
- createJob(newArrayList(testDir), testDir).run();
+ createJob(newArrayList(testDir),
+ DocumentsContract.buildDocumentUri(AUTHORITY, mSrcRoot.documentId),
+ testDir).run();
mJobListener.waitForFinished();
mJobListener.assertFailed();
@@ -122,7 +125,9 @@
Uri testDir = mDocs.createFolder(mSrcRoot, "someDir");
Uri destDir = mDocs.createFolder(testDir, "theDescendent");
- createJob(newArrayList(testDir), destDir).run();
+ createJob(newArrayList(testDir),
+ DocumentsContract.buildDocumentUri(AUTHORITY, mSrcRoot.documentId),
+ destDir).run();
mJobListener.waitForFinished();
mJobListener.assertFailed();
@@ -148,10 +153,13 @@
}
/**
- * Creates a job with a stack consisting to the default destination.
+ * Creates a job with a stack consisting to the default source and destination.
+ * TODO: Clean up, as mDestRoot.documentInfo may not really be the parent of
+ * srcs.
*/
final T createJob(List<Uri> srcs) throws Exception {
+ Uri srcParent = DocumentsContract.buildDocumentUri(AUTHORITY, mSrcRoot.documentId);
Uri destination = DocumentsContract.buildDocumentUri(AUTHORITY, mDestRoot.documentId);
- return createJob(srcs, destination);
+ return createJob(srcs, srcParent, destination);
}
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/AbstractJobTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/AbstractJobTest.java
index 691af6a..e559503 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/services/AbstractJobTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/AbstractJobTest.java
@@ -85,7 +85,7 @@
mDestRoot = mDocs.getRoot(ROOT_1_ID);
}
- final T createJob(List<Uri> srcs, Uri destination) throws Exception {
+ final T createJob(List<Uri> srcs, Uri srcParent, Uri destination) throws Exception {
DocumentStack stack = new DocumentStack();
stack.push(DocumentInfo.fromUri(mResolver, destination));
@@ -94,8 +94,9 @@
srcDocs.add(DocumentInfo.fromUri(mResolver, src));
}
- return createJob(srcDocs, stack);
+ return createJob(srcDocs, DocumentInfo.fromUri(mResolver, srcParent), stack);
}
- abstract T createJob(List<DocumentInfo> srcs, DocumentStack destination) throws Exception;
+ abstract T createJob(List<DocumentInfo> srcs, DocumentInfo srcParent, DocumentStack destination)
+ throws Exception;
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/CopyJobTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/CopyJobTest.java
index 1acf2dc..543396e 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/services/CopyJobTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/CopyJobTest.java
@@ -59,7 +59,9 @@
}
@Override
- CopyJob createJob(List<DocumentInfo> srcs, DocumentStack stack) throws Exception {
+ // TODO: Stop passing srcParent here, as it's not used for copying.
+ CopyJob createJob(List<DocumentInfo> srcs, DocumentInfo srcParent, DocumentStack stack)
+ throws Exception {
return new CopyJob(
mContext, mContext, mJobListener, FileOperations.createJobId(), stack, srcs);
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/DeleteJobTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/DeleteJobTest.java
index d6d10239..722df75 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/services/DeleteJobTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/DeleteJobTest.java
@@ -37,7 +37,8 @@
Uri testFile2 = mDocs.createDocument(mSrcRoot, "text/plain", "test2.txt");
mDocs.writeDocument(testFile2, FRUITY_BYTES);
- createJob(newArrayList(testFile1, testFile2)).run();
+ createJob(newArrayList(testFile1, testFile2),
+ DocumentsContract.buildDocumentUri(AUTHORITY, mSrcRoot.documentId)).run();
mJobListener.waitForFinished();
mDocs.assertChildCount(mSrcRoot, 0);
@@ -46,14 +47,17 @@
/**
* Creates a job with a stack consisting to the default src directory.
*/
- private final DeleteJob createJob(List<Uri> srcs) throws Exception {
+ private final DeleteJob createJob(List<Uri> srcs, Uri srcParent) throws Exception {
Uri stack = DocumentsContract.buildDocumentUri(AUTHORITY, mSrcRoot.documentId);
- return createJob(srcs, stack);
+ return createJob(srcs, srcParent, stack);
}
@Override
- DeleteJob createJob(List<DocumentInfo> srcs, DocumentStack stack) throws Exception {
+ // TODO: Remove inheritance, as stack is not used for deleting, nor srcParent.
+ DeleteJob createJob(List<DocumentInfo> srcs, DocumentInfo srcParent, DocumentStack stack)
+ throws Exception {
return new DeleteJob(
- mContext, mContext, mJobListener, FileOperations.createJobId(), stack, srcs);
+ mContext, mContext, mJobListener, FileOperations.createJobId(), stack, srcs,
+ srcParent);
}
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/MoveJobTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/MoveJobTest.java
index 69d2db7..749264a 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/services/MoveJobTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/MoveJobTest.java
@@ -19,6 +19,8 @@
import static com.google.common.collect.Lists.newArrayList;
import android.net.Uri;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract;
import android.test.suitebuilder.annotation.MediumTest;
import com.android.documentsui.model.DocumentInfo;
@@ -36,8 +38,9 @@
}
public void testMoveVirtualTypedFile() throws Exception {
+ mDocs.createFolder(mSrcRoot, "hello");
Uri testFile = mDocs.createVirtualFile(
- mSrcRoot, "/virtual.sth", "virtual/mime-type",
+ mSrcRoot, "/hello/virtual.sth", "virtual/mime-type",
FRUITY_BYTES, "application/pdf", "text/html");
createJob(newArrayList(testFile)).run();
@@ -89,9 +92,13 @@
mDocs.assertChildCount(mSrcRoot, 1);
}
+ // TODO: Add test cases for moving when multi-parented.
+
@Override
- MoveJob createJob(List<DocumentInfo> srcs, DocumentStack stack) throws Exception {
+ MoveJob createJob(List<DocumentInfo> srcs, DocumentInfo srcParent, DocumentStack stack)
+ throws Exception {
return new MoveJob(
- mContext, mContext, mJobListener, FileOperations.createJobId(), stack, srcs);
+ mContext, mContext, mJobListener, FileOperations.createJobId(), stack, srcs,
+ srcParent);
}
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
index cd30e26..46a2098 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
@@ -16,6 +16,7 @@
package com.android.printspooler.ui;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.Loader;
@@ -452,7 +453,7 @@
return mPersistenceManager.mReadHistoryCompleted;
}
- public void setTrackedPrinter(PrinterId printerId) {
+ public void setTrackedPrinter(@Nullable PrinterId printerId) {
if (isStarted() && mDiscoverySession != null
&& mDiscoverySession.isPrinterDiscoveryStarted()) {
if (mTrackedPrinter != null) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 811adda..743df99 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -1003,7 +1003,9 @@
if (currMediaSize == null) {
attributes.setMediaSize(defaults.getMediaSize());
} else {
- boolean foundCurrentMediaSize = false;
+ MediaSize newMediaSize = null;
+ boolean isPortrait = currMediaSize.isPortrait();
+
// Try to find the current media size in the capabilities as
// it may be in a different orientation.
MediaSize currMediaSizePortrait = currMediaSize.asPortrait();
@@ -1011,14 +1013,21 @@
for (int i = 0; i < mediaSizeCount; i++) {
MediaSize mediaSize = sortedMediaSizes.get(i);
if (currMediaSizePortrait.equals(mediaSize.asPortrait())) {
- attributes.setMediaSize(currMediaSize);
- foundCurrentMediaSize = true;
+ newMediaSize = mediaSize;
break;
}
}
// If we did not find the current media size fall back to default.
- if (!foundCurrentMediaSize) {
- attributes.setMediaSize(defaults.getMediaSize());
+ if (newMediaSize == null) {
+ newMediaSize = defaults.getMediaSize();
+ }
+
+ if (newMediaSize != null) {
+ if (isPortrait) {
+ attributes.setMediaSize(newMediaSize.asPortrait());
+ } else {
+ attributes.setMediaSize(newMediaSize.asLandscape());
+ }
}
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java
index cbc568a..6d60bb8 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java
@@ -16,6 +16,7 @@
package com.android.printspooler.ui;
+import android.annotation.Nullable;
import android.app.Activity;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.Loader;
@@ -89,7 +90,7 @@
return false;
}
- public void setTrackedPrinter(PrinterId printerId) {
+ public void setTrackedPrinter(@Nullable PrinterId printerId) {
FusedPrintersProvider provider = getPrinterProvider();
if (provider != null) {
provider.setTrackedPrinter(printerId);
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index bcb5bd8..d3c1364 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.IPackageManager;
+import android.content.pm.UserInfo;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -36,6 +37,8 @@
import android.view.MenuItem;
import android.widget.TextView;
+import com.android.internal.widget.LockPatternUtils;
+
import java.util.List;
/**
@@ -60,9 +63,9 @@
*
* @param userRestriction Restriction to check
* @param userId User which we need to check if restriction is enforced on.
- * @return EnforcedAdmin Object containing the enforce admin and admin user details, or
- * {@code null} If the restriction is not set. If the restriction is set by both device owner
- * and profile owner, then the admin will be set to {@code null} and userId to
+ * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
+ * or {@code null} If the restriction is not set. If the restriction is set by both device owner
+ * and profile owner, then the admin component will be set to {@code null} and userId to
* {@link UserHandle#USER_NULL}.
*/
public static EnforcedAdmin checkIfRestrictionEnforced(Context context,
@@ -112,48 +115,80 @@
}
/**
- * Checks if lock screen notification features are disabled by policy. This should be
- * only used for keyguard notification features but not the keyguard features
- * (e.g. KEYGUARD_DISABLE_FINGERPRINT) where a profile owner can set them on the parent user
- * as it won't work for that case.
+ * Checks if keyguard features are disabled by policy.
*
- * @param keyguardNotificationFeatures Could be any of notification features that can be
+ * @param keyguardFeatures Could be any of keyguard features that can be
* disabled by {@link android.app.admin.DevicePolicyManager#setKeyguardDisabledFeatures}.
- * @return EnforcedAdmin Object containing the enforce admin and admin user details, or
- * {@code null} If the notification features are not disabled. If the restriction is set by
- * multiple admins, then the admin will be set to {@code null} and userId to
+ * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
+ * or {@code null} If the notification features are not disabled. If the restriction is set by
+ * multiple admins, then the admin component will be set to {@code null} and userId to
* {@link UserHandle#USER_NULL}.
*/
- public static EnforcedAdmin checkIfKeyguardNotificationFeaturesDisabled(Context context,
- int keyguardNotificationFeatures) {
+ public static EnforcedAdmin checkIfKeyguardFeaturesDisabled(Context context,
+ int keyguardFeatures) {
final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
Context.DEVICE_POLICY_SERVICE);
if (dpm == null) {
return null;
}
- boolean isDisabledByMultipleAdmins = false;
- ComponentName adminComponent = null;
- List<ComponentName> admins = dpm.getActiveAdmins();
- if (admins != null) {
- int disabledKeyguardFeatures;
+ final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
+ EnforcedAdmin enforcedAdmin = null;
+ final int userId = UserHandle.myUserId();
+ if (um.getUserInfo(userId).isManagedProfile()) {
+ final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId);
+ if (admins == null) {
+ return null;
+ }
for (ComponentName admin : admins) {
- disabledKeyguardFeatures = dpm.getKeyguardDisabledFeatures(admin);
- if ((disabledKeyguardFeatures & keyguardNotificationFeatures) != 0) {
- if (adminComponent == null) {
- adminComponent = admin;
+ if ((dpm.getKeyguardDisabledFeatures(admin, userId) & keyguardFeatures) != 0) {
+ if (enforcedAdmin == null) {
+ enforcedAdmin = new EnforcedAdmin(admin, userId);
} else {
- isDisabledByMultipleAdmins = true;
- break;
+ return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
}
}
}
- }
- EnforcedAdmin enforcedAdmin = null;
- if (adminComponent != null) {
- if (!isDisabledByMultipleAdmins) {
- enforcedAdmin = new EnforcedAdmin(adminComponent, UserHandle.myUserId());
- } else {
- enforcedAdmin = new EnforcedAdmin();
+ } else {
+ // Consider all admins for this user and the profiles that are visible from this
+ // user that do not use a separate work challenge.
+ for (UserInfo userInfo : um.getProfiles(userId)) {
+ final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id);
+ if (admins == null) {
+ return null;
+ }
+ final boolean isSeparateProfileChallengeEnabled =
+ lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id);
+ for (ComponentName admin : admins) {
+ if (!isSeparateProfileChallengeEnabled) {
+ if ((dpm.getKeyguardDisabledFeatures(admin, userInfo.id)
+ & keyguardFeatures) != 0) {
+ if (enforcedAdmin == null) {
+ enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
+ } else {
+ return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
+ }
+ // This same admins could have set policies both on the managed profile
+ // and on the parent. So, if the admin has set the policy on the
+ // managed profile here, we don't need to further check if that admin
+ // has set policy on the parent admin.
+ continue;
+ }
+ }
+ if (userInfo.isManagedProfile()) {
+ // If userInfo.id is a managed profile, we also need to look at
+ // the policies set on the parent.
+ DevicePolicyManager parentDpm = dpm.getParentProfileInstance(admin);
+ if ((parentDpm.getKeyguardDisabledFeatures(admin, userInfo.id)
+ & keyguardFeatures) != 0) {
+ if (enforcedAdmin == null) {
+ enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
+ } else {
+ return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
+ }
+ }
+ }
+ }
}
}
return enforcedAdmin;
@@ -283,6 +318,78 @@
return enforcedAdmin;
}
+ /**
+ * Checks if any admin has set maximum time to lock.
+ *
+ * @return EnforcedAdmin Object containing the enforced admin component and admin user details,
+ * or {@code null} if no admin has set this restriction. If multiple admins has set this, then
+ * the admin component will be set to {@code null} and userId to {@link UserHandle#USER_NULL}
+ */
+ public static EnforcedAdmin checkIfMaximumTimeToLockIsSet(Context context) {
+ final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
+ EnforcedAdmin enforcedAdmin = null;
+ final int userId = UserHandle.myUserId();
+ if (lockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
+ // If the user has a separate challenge, only consider the admins in that user.
+ final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userId);
+ if (admins == null) {
+ return null;
+ }
+ for (ComponentName admin : admins) {
+ if (dpm.getMaximumTimeToLock(admin, userId) > 0) {
+ if (enforcedAdmin == null) {
+ enforcedAdmin = new EnforcedAdmin(admin, userId);
+ } else {
+ return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
+ }
+ }
+ }
+ } else {
+ // Return all admins for this user and the profiles that are visible from this
+ // user that do not use a separate work challenge.
+ final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ for (UserInfo userInfo : um.getProfiles(userId)) {
+ final List<ComponentName> admins = dpm.getActiveAdminsAsUser(userInfo.id);
+ if (admins == null) {
+ return null;
+ }
+ final boolean isSeparateProfileChallengeEnabled =
+ lockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id);
+ for (ComponentName admin : admins) {
+ if (!isSeparateProfileChallengeEnabled) {
+ if (dpm.getMaximumTimeToLock(admin, userInfo.id) > 0) {
+ if (enforcedAdmin == null) {
+ enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
+ } else {
+ return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
+ }
+ // This same admins could have set policies both on the managed profile
+ // and on the parent. So, if the admin has set the policy on the
+ // managed profile here, we don't need to further check if that admin
+ // has set policy on the parent admin.
+ continue;
+ }
+ }
+ if (userInfo.isManagedProfile()) {
+ // If userInfo.id is a managed profile, we also need to look at
+ // the policies set on the parent.
+ DevicePolicyManager parentDpm = dpm.getParentProfileInstance(admin);
+ if (parentDpm.getMaximumTimeToLock(admin, userInfo.id) > 0) {
+ if (enforcedAdmin == null) {
+ enforcedAdmin = new EnforcedAdmin(admin, userInfo.id);
+ } else {
+ return EnforcedAdmin.MULTIPLE_ENFORCED_ADMIN;
+ }
+ }
+ }
+ }
+ }
+ }
+ return enforcedAdmin;
+ }
+
public static EnforcedAdmin getProfileOrDeviceOwnerOnCallingUser(Context context) {
final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
Context.DEVICE_POLICY_SERVICE);
@@ -409,6 +516,9 @@
public ComponentName component = null;
public int userId = UserHandle.USER_NULL;
+ // We use this to represent the case where a policy is enforced by multiple admins.
+ public final static EnforcedAdmin MULTIPLE_ENFORCED_ADMIN = new EnforcedAdmin();
+
public EnforcedAdmin(ComponentName component, int userId) {
this.component = component;
this.userId = userId;
diff --git a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
index 58a477e..1859207 100644
--- a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
+++ b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
@@ -17,6 +17,7 @@
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -38,14 +39,39 @@
private static final String TAG = "SuggestionParser";
+ // If defined, only returns this suggestion if the feature is supported.
+ public static final String META_DATA_REQUIRE_FEATURE = "com.android.settings.require_feature";
+
+ /**
+ * Allows suggestions to appear after a certain number of days, and to re-appear if dismissed.
+ * For instance:
+ * 0,10
+ * Will appear immediately, but if the user removes it, it will come back after 10 days.
+ *
+ * Another example:
+ * 10,30
+ * Will only show up after 10 days, and then again after 30.
+ */
+ public static final String META_DATA_DISMISS_CONTROL = "com.android.settings.dismiss";
+
+ // Shared prefs keys for storing dismissed state.
+ // Index into current dismissed state.
+ private static final String DISMISS_INDEX = "_dismiss_index";
+ private static final String SETUP_TIME = "_setup_time";
+ private static final String IS_DISMISSED = "_is_dismissed";
+
+ private static final long MILLIS_IN_DAY = 24 * 60 * 60 * 1000;
+
private final Context mContext;
private final List<SuggestionCategory> mSuggestionList;
private final ArrayMap<Pair<String, String>, Tile> addCache = new ArrayMap<>();
+ private final SharedPreferences mSharedPrefs;
- public SuggestionParser(Context context, int orderXml) {
+ public SuggestionParser(Context context, SharedPreferences sharedPrefs, int orderXml) {
mContext = context;
mSuggestionList = (List<SuggestionCategory>) new SuggestionOrderInflater(mContext)
.parse(orderXml);
+ mSharedPrefs = sharedPrefs;
}
public List<Tile> getSuggestions() {
@@ -57,6 +83,23 @@
return suggestions;
}
+ /**
+ * Dismisses a suggestion, returns true if the suggestion has no more dismisses left and should
+ * be disabled.
+ */
+ public boolean dismissSuggestion(Tile suggestion) {
+ String keyBase = suggestion.intent.getComponent().flattenToShortString();
+ int index = mSharedPrefs.getInt(keyBase + DISMISS_INDEX, 0);
+ String dismissControl = suggestion.metaData.getString(META_DATA_DISMISS_CONTROL);
+ if (dismissControl == null || parseDismissString(dismissControl).length == index) {
+ return true;
+ }
+ mSharedPrefs.edit()
+ .putBoolean(keyBase + IS_DISMISSED, true)
+ .commit();
+ return false;
+ }
+
private void readSuggestions(SuggestionCategory category, List<Tile> suggestions) {
int countBefore = suggestions.size();
Intent intent = new Intent(Intent.ACTION_MAIN);
@@ -66,6 +109,11 @@
}
TileUtils.getTilesForIntent(mContext, new UserHandle(UserHandle.myUserId()), intent,
addCache, null, suggestions, true, false);
+ for (int i = countBefore; i < suggestions.size(); i++) {
+ if (!isAvailable(suggestions.get(i)) || isDismissed(suggestions.get(i))) {
+ suggestions.remove(i--);
+ }
+ }
if (!category.multiple && suggestions.size() > (countBefore + 1)) {
// If there are too many, remove them all and only re-add the one with the highest
// priority.
@@ -80,6 +128,59 @@
}
}
+ private boolean isAvailable(Tile suggestion) {
+ String featureRequired = suggestion.metaData.getString(META_DATA_REQUIRE_FEATURE);
+ if (featureRequired != null) {
+ return mContext.getPackageManager().hasSystemFeature(featureRequired);
+ }
+ return true;
+ }
+
+ private boolean isDismissed(Tile suggestion) {
+ Object dismissObj = suggestion.metaData.get(META_DATA_DISMISS_CONTROL);
+ if (dismissObj == null) {
+ return false;
+ }
+ String dismissControl = String.valueOf(dismissObj);
+ String keyBase = suggestion.intent.getComponent().flattenToShortString();
+ if (!mSharedPrefs.contains(keyBase + SETUP_TIME)) {
+ mSharedPrefs.edit()
+ .putLong(keyBase + SETUP_TIME, System.currentTimeMillis())
+ .commit();
+ }
+ // Default to dismissed, so that we can have suggestions that only first appear after
+ // some number of days.
+ if (!mSharedPrefs.getBoolean(keyBase + IS_DISMISSED, true)) {
+ return false;
+ }
+ int index = mSharedPrefs.getInt(keyBase + DISMISS_INDEX, 0);
+ int currentDismiss = parseDismissString(dismissControl)[index];
+ long time = getEndTime(mSharedPrefs.getLong(keyBase + SETUP_TIME, 0), currentDismiss);
+ if (System.currentTimeMillis() >= time) {
+ // Dismiss timeout has passed, undismiss it.
+ mSharedPrefs.edit()
+ .putBoolean(keyBase + IS_DISMISSED, false)
+ .putInt(keyBase + DISMISS_INDEX, index + 1)
+ .commit();
+ return false;
+ }
+ return true;
+ }
+
+ private long getEndTime(long startTime, int daysDelay) {
+ long days = daysDelay * MILLIS_IN_DAY;
+ return startTime + days;
+ }
+
+ private int[] parseDismissString(String dismissControl) {
+ String[] dismissStrs = dismissControl.split(",");
+ int[] dismisses = new int[dismissStrs.length];
+ for (int i = 0; i < dismissStrs.length; i++) {
+ dismisses[i] = Integer.parseInt(dismissStrs[i]);
+ }
+ return dismisses;
+ }
+
private static class SuggestionCategory {
public String category;
public String pkg;
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
index 5d8668b..e53dd2f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java
@@ -228,7 +228,7 @@
private static String getActiveSubscriberId(Context context) {
final TelephonyManager tele = TelephonyManager.from(context);
final String actualSubscriberId = tele.getSubscriberId(
- SubscriptionManager.getDefaultDataSubId());
+ SubscriptionManager.getDefaultDataSubscriptionId());
return actualSubscriberId;
}
diff --git a/packages/SystemUI/res/drawable/brightness_mirror_background.xml b/packages/SystemUI/res/drawable/brightness_mirror_background.xml
index fadfe63..e901e40 100644
--- a/packages/SystemUI/res/drawable/brightness_mirror_background.xml
+++ b/packages/SystemUI/res/drawable/brightness_mirror_background.xml
@@ -16,9 +16,4 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/system_primary_color" />
- <corners
- android:topLeftRadius="@dimen/notification_material_rounded_rect_radius"
- android:topRightRadius="@dimen/notification_material_rounded_rect_radius"
- android:bottomLeftRadius="@dimen/notification_material_rounded_rect_radius"
- android:bottomRightRadius="@dimen/notification_material_rounded_rect_radius"/>
</shape>
diff --git a/packages/SystemUI/res/drawable/notification_material_bg.xml b/packages/SystemUI/res/drawable/notification_material_bg.xml
index 6a0277f..ae45663 100644
--- a/packages/SystemUI/res/drawable/notification_material_bg.xml
+++ b/packages/SystemUI/res/drawable/notification_material_bg.xml
@@ -20,7 +20,6 @@
<item>
<shape>
<solid android:color="@color/notification_material_background_color" />
- <corners android:radius="@dimen/notification_material_rounded_rect_radius" />
</shape>
</item>
</ripple>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/notification_material_bg_dim.xml b/packages/SystemUI/res/drawable/notification_material_bg_dim.xml
index 6581942..b6a8b70 100644
--- a/packages/SystemUI/res/drawable/notification_material_bg_dim.xml
+++ b/packages/SystemUI/res/drawable/notification_material_bg_dim.xml
@@ -18,7 +18,6 @@
<item>
<shape>
<solid android:color="@color/notification_material_background_dimmed_color" />
- <corners android:radius="@dimen/notification_material_rounded_rect_radius" />
</shape>
</item>
</ripple>
diff --git a/packages/SystemUI/res/drawable/qs_background_primary.xml b/packages/SystemUI/res/drawable/qs_background_primary.xml
index 686df2c..1bf7d4c 100644
--- a/packages/SystemUI/res/drawable/qs_background_primary.xml
+++ b/packages/SystemUI/res/drawable/qs_background_primary.xml
@@ -13,10 +13,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetTop="@dimen/notification_material_rounded_rect_radius_negative">
+<inset xmlns:android="http://schemas.android.com/apk/res/android">
<shape>
<solid android:color="@color/system_primary_color"/>
- <corners android:radius="@dimen/notification_material_rounded_rect_radius"/>
</shape>
</inset>
diff --git a/packages/SystemUI/res/drawable/qs_background_secondary.xml b/packages/SystemUI/res/drawable/qs_background_secondary.xml
index 3662e5a..31c0162 100644
--- a/packages/SystemUI/res/drawable/qs_background_secondary.xml
+++ b/packages/SystemUI/res/drawable/qs_background_secondary.xml
@@ -17,7 +17,5 @@
<solid android:color="@color/system_secondary_color" />
<corners
android:topLeftRadius="0dp"
- android:topRightRadius="0dp"
- android:bottomLeftRadius="@dimen/notification_material_rounded_rect_radius"
- android:bottomRightRadius="@dimen/notification_material_rounded_rect_radius"/>
+ android:topRightRadius="0dp" />
</shape>
diff --git a/packages/SystemUI/res/drawable/volume_dialog_background.xml b/packages/SystemUI/res/drawable/volume_dialog_background.xml
index f09c01b..e98bfb8 100644
--- a/packages/SystemUI/res/drawable/volume_dialog_background.xml
+++ b/packages/SystemUI/res/drawable/volume_dialog_background.xml
@@ -14,9 +14,5 @@
limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
-
<solid android:color="@color/system_primary_color" />
-
- <corners android:radius="@dimen/notification_material_rounded_rect_radius" />
-
</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/apps_bar.xml b/packages/SystemUI/res/layout/apps_bar.xml
deleted file mode 100644
index e226805..0000000
--- a/packages/SystemUI/res/layout/apps_bar.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2016, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
--->
-
-<!-- Container for the app shelf. -->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/app_shelf"
- android:orientation="horizontal"
- android:layout_height="match_parent"
- android:layout_width="0dp"
- android:layout_weight="1">
- <com.android.systemui.statusbar.phone.NavigationBarApps
- android:id="@+id/navigation_bar_apps"
- android:layout_width="wrap_content"
- android:layout_height="match_parent" />
-</LinearLayout>
diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
index 9ef743d..6e4b213 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
@@ -33,7 +33,8 @@
android:paddingTop="@dimen/car_lockscreen_disclaimer_title_padding_top" />
<TextView
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
+ android:layout_height="0dp"
+ android:layout_weight="1"
android:text="@string/car_lockscreen_disclaimer_text"
android:textSize="@dimen/car_lockscreen_disclaimer_text_size"
android:paddingStart="@dimen/car_lockscreen_disclaimer_text_padding_start"
@@ -44,7 +45,6 @@
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingTop="@dimen/car_lockscreen_user_grid_view_padding_top"
android:stretchMode="columnWidth">
</com.android.systemui.statusbar.car.UserGridView>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/car_navigation_button.xml b/packages/SystemUI/res/layout/car_navigation_button.xml
index 479f18d..7677646 100644
--- a/packages/SystemUI/res/layout/car_navigation_button.xml
+++ b/packages/SystemUI/res/layout/car_navigation_button.xml
@@ -26,9 +26,10 @@
<com.android.keyguard.AlphaOptimizedImageButton
android:id="@+id/car_nav_button_icon"
android:layout_height="match_parent"
- android:layout_width="wrap_content"
+ android:layout_width="@dimen/car_navigation_button_width"
android:layout_centerInParent="true"
- android:animateLayoutChanges="true">
+ android:animateLayoutChanges="true"
+ android:scaleType="fitCenter">
</com.android.keyguard.AlphaOptimizedImageButton>
<com.android.keyguard.AlphaOptimizedImageButton
@@ -37,6 +38,7 @@
android:layout_width="wrap_content"
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/car_nav_button_icon"
- android:animateLayoutChanges="true">
+ android:animateLayoutChanges="true"
+ android:scaleType="fitCenter">
</com.android.keyguard.AlphaOptimizedImageButton>
</com.android.systemui.statusbar.car.CarNavigationButton>
diff --git a/packages/SystemUI/res/layout/notification_children_divider.xml b/packages/SystemUI/res/layout/notification_children_divider.xml
index 53273cf..dad7cea 100644
--- a/packages/SystemUI/res/layout/notification_children_divider.xml
+++ b/packages/SystemUI/res/layout/notification_children_divider.xml
@@ -19,5 +19,5 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/notification_more_divider"
android:layout_width="match_parent"
- android:layout_height="@dimen/notification_children_divider_height"
+ android:layout_height="@dimen/notification_divider_height"
android:background="#61000000" />
diff --git a/packages/SystemUI/res/layout/qs_customize_panel.xml b/packages/SystemUI/res/layout/qs_customize_panel.xml
index f430fa5..e56431b 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel.xml
@@ -87,9 +87,7 @@
android:id="@+id/quick_settings_panel"
android:background="#0000"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/notification_side_padding"
- android:layout_marginRight="@dimen/notification_side_padding" />
+ android:layout_height="wrap_content" />
</com.android.systemui.tuner.AutoScrollView>
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index ab590f8..6784695 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -23,8 +23,6 @@
android:layout_width="@dimen/notification_panel_width"
android:layout_height="@dimen/status_bar_header_height"
android:layout_gravity="@integer/notification_panel_layout_gravity"
- android:paddingStart="@dimen/notification_side_padding"
- android:paddingEnd="@dimen/notification_side_padding"
android:clipChildren="false"
android:clipToPadding="false"
android:baselineAligned="false"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 12cf137..89abe2d 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -55,20 +55,13 @@
layout="@layout/qs_panel"
android:layout_marginTop="@dimen/status_bar_header_height_expanded"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/notification_side_padding"
- android:layout_marginRight="@dimen/notification_side_padding"/>
+ android:layout_height="wrap_content" />
<!-- A view to reserve space for the collapsed stack -->
<!-- Layout height: notification_min_height + bottom_stack_peek_amount -->
<View
android:id="@+id/reserve_notification_space"
android:layout_height="@dimen/min_stack_height"
- android:layout_width="match_parent"
- android:layout_marginTop="@dimen/notifications_top_padding" />
-
- <View
- android:layout_height="@dimen/notification_side_padding"
android:layout_width="match_parent" />
</LinearLayout>
</com.android.systemui.statusbar.phone.ObservableScrollView>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 5eca471..dd75dbf 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -23,8 +23,6 @@
android:layout_width="@dimen/notification_panel_width"
android:layout_height="@dimen/status_bar_header_height"
android:layout_gravity="@integer/notification_panel_layout_gravity"
- android:paddingStart="@dimen/notification_side_padding"
- android:paddingEnd="@dimen/notification_side_padding"
android:baselineAligned="false"
android:elevation="4dp"
android:background="@drawable/notification_header_bg"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml b/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
deleted file mode 100644
index e220a16..0000000
--- a/packages/SystemUI/res/layout/status_bar_notification_speed_bump.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
- ~ Copyright (C) 2014 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License
- -->
-
-<!-- Extends FrameLayout -->
-<com.android.systemui.statusbar.SpeedBumpView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="@dimen/speed_bump_height"
- android:visibility="gone"
- >
- <com.android.systemui.statusbar.AlphaOptimizedView
- android:id="@+id/speedbump_line"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="#6fdddddd"
- android:layout_gravity="center_vertical"/>
-</com.android.systemui.statusbar.SpeedBumpView>
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 4c80b48..3dca77d 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -65,8 +65,6 @@
android:layout_width="@dimen/notification_panel_width"
android:layout_height="wrap_content"
android:layout_gravity="@integer/notification_panel_layout_gravity"
- android:paddingLeft="@dimen/notification_side_padding"
- android:paddingRight="@dimen/notification_side_padding"
android:visibility="invisible">
<FrameLayout
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 7cbc55c..34796cd 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -19,8 +19,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/volume_dialog_margin_bottom"
- android:layout_marginLeft="@dimen/notification_side_padding"
- android:layout_marginRight="@dimen/notification_side_padding"
android:background="@drawable/volume_dialog_background"
android:translationZ="4dp" >
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index b2190ec..5e25d2c 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -78,14 +78,13 @@
<color name="notification_material_background_color">#ffffffff</color>
<!-- The color of the material notification background when dimmed -->
- <color name="notification_material_background_dimmed_color">#f2ffffff</color>
+ <color name="notification_material_background_dimmed_color">#ccffffff</color>
<!-- The color of the material notification background when low priority -->
<color name="notification_material_background_low_priority_color">#fff5f5f5</color>
- <!-- The color of the material notification background for media notifications when no custom
- color is specified -->
- <color name="notification_material_background_media_default_color">#ff424242</color>
+ <!-- The background color of the notification shade -->
+ <color name="notification_shade_background_color">#ffeeeeee</color>
<!-- The color of the ripples on the untinted notifications -->
<color name="notification_ripple_untinted_color">#28000000</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index aedc2c5..4aa4d42 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -195,6 +195,10 @@
<!-- Svelte specific logic, see RecentsConfiguration.SVELTE_* constants. -->
<integer name="recents_svelte_level">0</integer>
+ <!-- In multi-window, determines whether the stack where recents lives should grow from
+ the smallest position when being launched. -->
+ <bool name="recents_grow_in_multiwindow">true</bool>
+
<!-- Recents: The relative range of visible tasks from the current scroll position
while the stack is focused. -->
<item name="recents_layout_focused_range_min" format="float" type="integer">-3</item>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 46a0f2a..e245c24 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -87,9 +87,6 @@
<!-- gap on either side of status bar notification icons -->
<dimen name="status_bar_icon_padding">0dp</dimen>
- <!-- half the distance between notifications in the panel -->
- <dimen name="notification_divider_height">2dp</dimen>
-
<!-- The padding on the global screenshot background image -->
<dimen name="global_screenshot_bg_padding">20dp</dimen>
@@ -137,7 +134,7 @@
<!-- Width for the notification panel and related windows -->
<dimen name="match_parent">-1px</dimen>
- <dimen name="standard_notification_panel_width">416dp</dimen><!-- includes notification_side_padding on each side -->
+ <dimen name="standard_notification_panel_width">416dp</dimen>
<dimen name="notification_panel_width">@dimen/match_parent</dimen>
<!-- Gravity for the notification panel -->
@@ -298,17 +295,14 @@
<!-- The height of the area before the top stack in which the notifications slow down -->
<dimen name="top_stack_slow_down_length">12dp</dimen>
- <!-- The side padding of the notifications-->
- <dimen name="notification_side_padding">8dp</dimen>
-
<!-- Z distance between notifications if they are in the stack -->
- <dimen name="z_distance_between_notifications">1dp</dimen>
+ <dimen name="z_distance_between_notifications">0.5dp</dimen>
- <!-- The padding between the individual notification cards when dimmed. -->
- <dimen name="notification_padding_dimmed">0dp</dimen>
+ <!-- The height of the divider between the individual notifications. -->
+ <dimen name="notification_divider_height">0.5dp</dimen>
- <!-- The padding between the individual notification cards. -->
- <dimen name="notification_padding">2dp</dimen>
+ <!-- The height of the divider between the individual notifications when the notification wants it to be increased. This is currently the case for notification groups -->
+ <dimen name="notification_divider_height_increased">6dp</dimen>
<!-- The minimum amount of top overscroll to go to the quick settings. -->
<dimen name="min_top_overscroll_to_qs">36dp</dimen>
@@ -328,8 +322,6 @@
<!-- Falsing threshold used when dismissing notifications from the lockscreen. -->
<dimen name="swipe_helper_falsing_threshold">70dp</dimen>
- <dimen name="notifications_top_padding">4dp</dimen>
-
<!-- Minimum distance the user has to drag down to go to the full shade. -->
<dimen name="keyguard_drag_down_min_distance">100dp</dimen>
@@ -374,21 +366,12 @@
phone hints. -->
<dimen name="edge_tap_area_width">48dp</dimen>
- <!-- radius of the corners of the material rounded rect background -->
- <dimen name="notification_material_rounded_rect_radius">2dp</dimen>
-
- <!-- radius of the corners of the material rounded rect background but negative-->
- <dimen name="notification_material_rounded_rect_radius_negative">-2dp</dimen>
-
<!-- The padding between notification children when collapsed -->
<dimen name="notification_children_padding">4dp</dimen>
<!-- The padding on top of the first notification to the children container -->
<dimen name="notification_children_container_top_padding">8dp</dimen>
- <!-- The height of the divider between the notfication children -->
- <dimen name="notification_children_divider_height">1dp</dimen>
-
<!-- The vertical distance from which the notification appear when children are expanded -->
<dimen name="notification_appear_distance">140dp</dimen>
diff --git a/packages/SystemUI/res/values/dimens_car.xml b/packages/SystemUI/res/values/dimens_car.xml
index ecdccee..04402b7 100644
--- a/packages/SystemUI/res/values/dimens_car.xml
+++ b/packages/SystemUI/res/values/dimens_car.xml
@@ -18,15 +18,15 @@
<resources>
<dimen name="car_lockscreen_disclaimer_title_size">48sp</dimen>
<dimen name="car_lockscreen_disclaimer_title_padding_start">96dp</dimen>
- <dimen name="car_lockscreen_disclaimer_title_padding_top">96dp</dimen>
+ <dimen name="car_lockscreen_disclaimer_title_padding_top">82dp</dimen>
<dimen name="car_lockscreen_disclaimer_text_size">28sp</dimen>
<dimen name="car_lockscreen_disclaimer_text_padding_start">96dp</dimen>
<dimen name="car_lockscreen_disclaimer_text_padding_end">96dp</dimen>
- <dimen name="car_lockscreen_disclaimer_text_padding_top">32dp</dimen>
+ <dimen name="car_lockscreen_disclaimer_text_padding_top">8dp</dimen>
<dimen name="car_lockscreen_user_grid_view_padding_start">10dp</dimen>
<dimen name="car_lockscreen_user_grid_view_padding_end">10dp</dimen>
- <dimen name="car_lockscreen_user_grid_view_padding_top">128dp</dimen>
<dimen name="car_fullscreen_user_pod_image_avatar_width">128dp</dimen>
<dimen name="car_fullscreen_user_pod_image_avatar_height">128dp</dimen>
<dimen name="car_fullscreen_user_pod_text_size">24sp</dimen>
+ <dimen name="car_navigation_button_width">64dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 0bd350b..87aedab 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -18,22 +18,22 @@
<resources>
<item type="id" name="translation_y_animator_tag"/>
<item type="id" name="translation_z_animator_tag"/>
- <item type="id" name="scale_animator_tag"/>
<item type="id" name="alpha_animator_tag"/>
<item type="id" name="top_inset_animator_tag"/>
<item type="id" name="height_animator_tag"/>
+ <item type="id" name="shadow_alpha_animator_tag"/>
<item type="id" name="translation_y_animator_end_value_tag"/>
<item type="id" name="translation_z_animator_end_value_tag"/>
- <item type="id" name="scale_animator_end_value_tag"/>
<item type="id" name="alpha_animator_end_value_tag"/>
<item type="id" name="top_inset_animator_end_value_tag"/>
<item type="id" name="height_animator_end_value_tag"/>
+ <item type="id" name="shadow_alpha_animator_end_value_tag"/>
<item type="id" name="translation_y_animator_start_value_tag"/>
<item type="id" name="translation_z_animator_start_value_tag"/>
- <item type="id" name="scale_animator_start_value_tag"/>
<item type="id" name="alpha_animator_start_value_tag"/>
<item type="id" name="top_inset_animator_start_value_tag"/>
<item type="id" name="height_animator_start_value_tag"/>
+ <item type="id" name="shadow_alpha_animator_start_value_tag"/>
<item type="id" name="doze_saved_filter_tag"/>
<item type="id" name="qs_icon_tag"/>
<item type="id" name="scrim"/>
diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
index 99028a6c..001d1f2 100644
--- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
@@ -32,7 +32,7 @@
/**
* Docks the top-most task and opens recents.
*/
- boolean dockTopTask(boolean draggingInRecents, int stackCreateMode, Rect initialBounds);
+ boolean dockTopTask(int dragMode, int stackCreateMode, Rect initialBounds);
/**
* Called during a drag-from-navbar-in gesture.
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index fd4161f..5b955a4 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -30,11 +30,9 @@
import android.view.View;
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.statusbar.Interpolators;
public class SwipeHelper implements Gefingerpoken {
static final String TAG = "com.android.systemui.SwipeHelper";
@@ -48,9 +46,6 @@
public static final int X = 0;
public static final int Y = 1;
- private static LinearInterpolator sLinearInterpolator = new LinearInterpolator();
- private final Interpolator mFastOutLinearInInterpolator;
-
private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
private int DEFAULT_ESCAPE_ANIMATION_DURATION = 200; // ms
private int MAX_ESCAPE_ANIMATION_DURATION = 400; // ms
@@ -97,8 +92,6 @@
mPagingTouchSlop = ViewConfiguration.get(context).getScaledPagingTouchSlop();
mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f); // extra long-press!
- mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
- android.R.interpolator.fast_out_linear_in);
mFalsingThreshold = context.getResources().getDimensionPixelSize(
R.dimen.swipe_helper_falsing_threshold);
mFalsingManager = FalsingManager.getInstance(context);
@@ -357,9 +350,9 @@
}
ObjectAnimator anim = createTranslationAnimation(animView, newPos);
if (useAccelerateInterpolator) {
- anim.setInterpolator(mFastOutLinearInInterpolator);
+ anim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
} else {
- anim.setInterpolator(sLinearInterpolator);
+ anim.setInterpolator(Interpolators.LINEAR);
}
anim.setDuration(duration);
if (delay > 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java b/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
index c9ba885..25f8bb0 100644
--- a/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ViewInvertHelper.java
@@ -24,8 +24,8 @@
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.view.View;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
+
+import com.android.systemui.statusbar.Interpolators;
import java.util.ArrayList;
@@ -35,7 +35,6 @@
public class ViewInvertHelper {
private final Paint mDarkPaint = new Paint();
- private final Interpolator mLinearOutSlowInInterpolator;
private final ColorMatrix mMatrix = new ColorMatrix();
private final ColorMatrix mGrayscaleMatrix = new ColorMatrix();
private final long mFadeDuration;
@@ -46,8 +45,6 @@
addTarget(v);
}
public ViewInvertHelper(Context context, long fadeDuration) {
- mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- android.R.interpolator.linear_out_slow_in);
mFadeDuration = fadeDuration;
}
@@ -89,7 +86,7 @@
}
});
animator.setDuration(mFadeDuration);
- animator.setInterpolator(mLinearOutSlowInInterpolator);
+ animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
animator.setStartDelay(delay);
animator.start();
}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
index c3a8f2e..92cd027 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
@@ -16,8 +16,6 @@
package com.android.systemui.assist;
-import com.android.systemui.R;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -35,6 +33,9 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AnimationUtils;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.Interpolators;
+
/**
* Visually discloses that contextual data was provided to an assistant.
*/
@@ -120,13 +121,11 @@
R.interpolator.assist_disclosure_trace));
mAlphaInAnimator = ValueAnimator.ofInt(0, 255).setDuration(ALPHA_IN_ANIMATION_DURATION);
mAlphaInAnimator.addUpdateListener(this);
- mAlphaInAnimator.setInterpolator(AnimationUtils.loadInterpolator(mContext,
- android.R.interpolator.fast_out_slow_in));
+ mAlphaInAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mAlphaOutAnimator = ValueAnimator.ofInt(255, 0).setDuration(
ALPHA_OUT_ANIMATION_DURATION);
mAlphaOutAnimator.addUpdateListener(this);
- mAlphaOutAnimator.setInterpolator(AnimationUtils.loadInterpolator(mContext,
- android.R.interpolator.fast_out_linear_in));
+ mAlphaOutAnimator.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
mAnimator = new AnimatorSet();
mAnimator.play(mAlphaInAnimator).with(mTracingAnimator);
mAnimator.play(mAlphaInAnimator).before(mAlphaOutAnimator);
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java
index 67017db..34770c4 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java
@@ -20,19 +20,15 @@
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import com.android.systemui.R;
+import com.android.systemui.statusbar.Interpolators;
public class AssistOrbContainer extends FrameLayout {
private static final long EXIT_START_DELAY = 150;
- private final Interpolator mLinearOutSlowInInterpolator;
- private final Interpolator mFastOutLinearInInterpolator;
-
private View mScrim;
private View mNavbarScrim;
private AssistOrbView mOrb;
@@ -49,10 +45,6 @@
public AssistOrbContainer(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- android.R.interpolator.linear_out_slow_in);
- mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
- android.R.interpolator.fast_out_slow_in);
}
@Override
@@ -109,12 +101,12 @@
.alpha(1f)
.setDuration(300)
.setStartDelay(0)
- .setInterpolator(mLinearOutSlowInInterpolator);
+ .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
mNavbarScrim.animate()
.alpha(1f)
.setDuration(300)
.setStartDelay(0)
- .setInterpolator(mLinearOutSlowInInterpolator);
+ .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
}
});
}
@@ -132,12 +124,12 @@
.alpha(0f)
.setDuration(250)
.setStartDelay(EXIT_START_DELAY)
- .setInterpolator(mFastOutLinearInInterpolator);
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mNavbarScrim.animate()
.alpha(0f)
.setDuration(250)
.setStartDelay(EXIT_START_DELAY)
- .setInterpolator(mFastOutLinearInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.withEndAction(endRunnable);
}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbView.java b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbView.java
index a3372a8..2d933f6 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbView.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbView.java
@@ -27,13 +27,13 @@
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;
-import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.android.systemui.R;
+import com.android.systemui.statusbar.Interpolators;
public class AssistOrbView extends FrameLayout {
@@ -43,8 +43,6 @@
private final Paint mBackgroundPaint = new Paint();
private final Rect mCircleRect = new Rect();
private final Rect mStaticRect = new Rect();
- private final Interpolator mAppearInterpolator;
- private final Interpolator mDisappearInterpolator;
private final Interpolator mOvershootInterpolator = new OvershootInterpolator();
private boolean mClipToOutline;
@@ -117,10 +115,6 @@
R.dimen.assist_orb_travel_distance);
mMaxElevation = context.getResources().getDimensionPixelSize(
R.dimen.assist_orb_elevation);
- mAppearInterpolator = AnimationUtils.loadInterpolator(mContext,
- android.R.interpolator.linear_out_slow_in);
- mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext,
- android.R.interpolator.fast_out_linear_in);
mBackgroundPaint.setAntiAlias(true);
mBackgroundPaint.setColor(getResources().getColor(R.color.assist_orb_color));
}
@@ -256,8 +250,8 @@
}
public void startExitAnimation(long delay) {
- animateCircleSize(0, 200, delay, mDisappearInterpolator);
- animateOffset(0, 200, delay, mDisappearInterpolator);
+ animateCircleSize(0, 200, delay, Interpolators.FAST_OUT_LINEAR_IN);
+ animateOffset(0, 200, delay, Interpolators.FAST_OUT_LINEAR_IN);
}
public void startEnterAnimation() {
@@ -266,7 +260,7 @@
@Override
public void run() {
animateCircleSize(mCircleMinSize, 300, 0 /* delay */, mOvershootInterpolator);
- animateOffset(mStaticOffset, 400, 0 /* delay */, mAppearInterpolator);
+ animateOffset(mStaticOffset, 400, 0 /* delay */, Interpolators.LINEAR_OUT_SLOW_IN);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
index b36b95a..37085c7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsNonSystemUserCallbacks.aidl
@@ -16,6 +16,8 @@
package com.android.systemui.recents;
+import android.graphics.Rect;
+
/**
* Due to the fact that RecentsActivity is per-user, we need to establish an
* interface (this) for the system user to callback to the secondary users in
@@ -29,6 +31,8 @@
void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
void toggleRecents();
void onConfigurationChanged();
+ void dockTopTask(int topTaskId, int dragMode, int stackCreateMode,
+ in Rect initialBounds);
void onDraggingInRecents(float distanceFromTop);
void onDraggingInRecentsEnded(float velocity);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
index 6b49195..cb8f0e7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
+++ b/packages/SystemUI/src/com/android/systemui/recents/IRecentsSystemUserCallbacks.aidl
@@ -26,4 +26,7 @@
void updateRecentsVisibility(boolean visible);
void startScreenPinning();
+ void sendRecentsDrawnEvent();
+ void sendDockingTopTaskEvent(int dragMode);
+ void sendLaunchRecentsEvent();
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 2baefd5..b8310f2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -16,6 +16,7 @@
package com.android.systemui.recents;
+import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -36,8 +37,11 @@
import com.android.systemui.RecentsComponent;
import com.android.systemui.SystemUI;
import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
+import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
+import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.model.RecentsTaskLoader;
@@ -366,17 +370,38 @@
}
@Override
- public boolean dockTopTask(boolean draggingInRecents, int stackCreateMode, Rect initialBounds) {
+ public boolean dockTopTask(int dragMode, int stackCreateMode, Rect initialBounds) {
// Ensure the device has been provisioned before allowing the user to interact with
// recents
if (!isUserSetup()) {
return false;
}
- if (mImpl.dockTopTask(draggingInRecents, stackCreateMode,initialBounds)) {
- if (draggingInRecents) {
- mDraggingInRecentsCurrentUser = sSystemServicesProxy.getCurrentUser();
+ int currentUser = sSystemServicesProxy.getCurrentUser();
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
+ boolean screenPinningActive = ssp.isScreenPinningActive();
+ boolean isTopTaskHome = topTask != null && SystemServicesProxy.isHomeStack(topTask.stackId);
+ if (topTask != null && !isTopTaskHome && !screenPinningActive) {
+ if (sSystemServicesProxy.isSystemUser(currentUser)) {
+ mImpl.dockTopTask(topTask.id, dragMode, stackCreateMode, initialBounds);
+ } else {
+ if (mSystemUserCallbacks != null) {
+ IRecentsNonSystemUserCallbacks callbacks =
+ mSystemUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
+ if (callbacks != null) {
+ try {
+ callbacks.dockTopTask(topTask.id, dragMode, stackCreateMode,
+ initialBounds);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback failed", e);
+ }
+ } else {
+ Log.e(TAG, "No SystemUI callbacks found for user: " + currentUser);
+ }
+ }
}
+ mDraggingInRecentsCurrentUser = currentUser;
return true;
}
return false;
@@ -516,6 +541,54 @@
}
}
+ public final void onBusEvent(final RecentsDrawnEvent event) {
+ int processUser = sSystemServicesProxy.getProcessUser();
+ if (!sSystemServicesProxy.isSystemUser(processUser)) {
+ postToSystemUser(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mCallbacksToSystemUser.sendRecentsDrawnEvent();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback failed", e);
+ }
+ }
+ });
+ }
+ }
+
+ public final void onBusEvent(final DockingTopTaskEvent event) {
+ int processUser = sSystemServicesProxy.getProcessUser();
+ if (!sSystemServicesProxy.isSystemUser(processUser)) {
+ postToSystemUser(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mCallbacksToSystemUser.sendDockingTopTaskEvent(event.dragMode);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback failed", e);
+ }
+ }
+ });
+ }
+ }
+
+ public final void onBusEvent(final RecentsActivityStartingEvent event) {
+ int processUser = sSystemServicesProxy.getProcessUser();
+ if (!sSystemServicesProxy.isSystemUser(processUser)) {
+ postToSystemUser(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mCallbacksToSystemUser.sendLaunchRecentsEvent();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback failed", e);
+ }
+ }
+ });
+ }
+ }
+
/**
* Attempts to register with the system user.
*/
@@ -525,7 +598,8 @@
@Override
public void run() {
try {
- mCallbacksToSystemUser.registerNonSystemUserCallbacks(mImpl, processUser);
+ mCallbacksToSystemUser.registerNonSystemUserCallbacks(
+ new RecentsImplProxy(mImpl), processUser);
} catch (RemoteException e) {
Log.e(TAG, "Failed to register", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 3a3b19d..a11c06d7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -59,6 +59,7 @@
import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
+import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
@@ -400,6 +401,17 @@
EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, true));
MetricsLogger.visible(this, MetricsLogger.OVERVIEW_ACTIVITY);
+
+ mRecentsView.getViewTreeObserver().addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+
+ @Override
+ public boolean onPreDraw() {
+ mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
+ EventBus.getDefault().post(new RecentsDrawnEvent());
+ return true;
+ }
+ });
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 5f11bee..b78fd22 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -41,9 +41,11 @@
import com.android.systemui.R;
import com.android.systemui.SystemUIApplication;
import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
import com.android.systemui.recents.events.activity.HideRecentsEvent;
import com.android.systemui.recents.events.activity.IterateRecentsEvent;
+import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
@@ -62,6 +64,7 @@
import com.android.systemui.recents.views.TaskViewHeader;
import com.android.systemui.recents.views.TaskViewTransform;
import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import java.util.ArrayList;
@@ -72,8 +75,7 @@
* An implementation of the Recents component for the current user. For secondary users, this can
* be called remotely from the system user.
*/
-public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements
- ActivityOptions.OnAnimationFinishedListener {
+public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener {
private final static String TAG = "RecentsImpl";
// The minimum amount of time between each recents button press that we will handle
@@ -532,18 +534,14 @@
showRelativeAffiliatedTask(false);
}
- public boolean dockTopTask(boolean draggingInRecents, int stackCreateMode, Rect initialBounds) {
+ public void dockTopTask(int topTaskId, int dragMode,
+ int stackCreateMode, Rect initialBounds) {
SystemServicesProxy ssp = Recents.getSystemServices();
- ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
- boolean screenPinningActive = ssp.isScreenPinningActive();
- boolean isTopTaskHome = SystemServicesProxy.isHomeStack(topTask.stackId);
- if (topTask != null && !isTopTaskHome && !screenPinningActive) {
- ssp.moveTaskToDockedStack(topTask.id, stackCreateMode, initialBounds);
- showRecents(false /* triggeredFromAltTab */, draggingInRecents, false /* animate */,
- true /* reloadTasks*/);
- return true;
- }
- return false;
+ ssp.moveTaskToDockedStack(topTaskId, stackCreateMode, initialBounds);
+ showRecents(false /* triggeredFromAltTab */,
+ dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS, false /* animate */,
+ true /* reloadTasks*/);
+ EventBus.getDefault().send(new DockingTopTaskEvent(dragMode));
}
/**
@@ -918,6 +916,7 @@
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
}
mCanReuseTaskStackViews = true;
+ EventBus.getDefault().send(new RecentsActivityStartingEvent());
}
/**** OnAnimationFinishedListener Implementation ****/
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
new file mode 100644
index 0000000..86ec98a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplProxy.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.recents;
+
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+
+import com.android.internal.os.SomeArgs;
+
+/**
+ * A proxy class which directs all methods from {@link IRecentsNonSystemUserCallbacks} to
+ * {@link RecentsImpl} and makes sure they are called from the main thread.
+ */
+public class RecentsImplProxy extends IRecentsNonSystemUserCallbacks.Stub {
+
+ private static final int MSG_PRELOAD_RECENTS = 1;
+ private static final int MSG_CANCEL_PRELOADING_RECENTS = 2;
+ private static final int MSG_SHOW_RECENTS = 3;
+ private static final int MSG_HIDE_RECENTS = 4;
+ private static final int MSG_TOGGLE_RECENTS = 5;
+ private static final int MSG_ON_CONFIGURATION_CHANGED = 6;
+ private static final int MSG_DOCK_TOP_TASK = 7;
+ private static final int MSG_ON_DRAGGING_IN_RECENTS = 8;
+ private static final int MSG_ON_DRAGGING_IN_RECENTS_ENDED = 9;
+
+ private RecentsImpl mImpl;
+
+ public RecentsImplProxy(RecentsImpl recentsImpl) {
+ mImpl = recentsImpl;
+ }
+
+ @Override
+ public void preloadRecents() throws RemoteException {
+ mHandler.sendEmptyMessage(MSG_PRELOAD_RECENTS);
+ }
+
+ @Override
+ public void cancelPreloadingRecents() throws RemoteException {
+ mHandler.sendEmptyMessage(MSG_CANCEL_PRELOADING_RECENTS);
+ }
+
+ @Override
+ public void showRecents(boolean triggeredFromAltTab, boolean draggingInRecents, boolean animate,
+ boolean reloadTasks) throws RemoteException {
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = triggeredFromAltTab ? 1 : 0;
+ args.argi2 = draggingInRecents ? 1 : 0;
+ args.argi3 = animate ? 1 : 0;
+ args.argi4 = reloadTasks ? 1 : 0;
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_SHOW_RECENTS, args));
+ }
+
+ @Override
+ public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey)
+ throws RemoteException {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_HIDE_RECENTS, triggeredFromAltTab ? 1 :0,
+ triggeredFromHomeKey ? 1 : 0));
+ }
+
+ @Override
+ public void toggleRecents() throws RemoteException {
+ mHandler.sendEmptyMessage(MSG_TOGGLE_RECENTS);
+ }
+
+ @Override
+ public void onConfigurationChanged() throws RemoteException {
+ mHandler.sendEmptyMessage(MSG_ON_CONFIGURATION_CHANGED);
+ }
+
+ @Override
+ public void dockTopTask(int topTaskId, int dragMode, int stackCreateMode,
+ Rect initialBounds) throws RemoteException {
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = topTaskId;
+ args.argi2 = dragMode;
+ args.argi3 = stackCreateMode;
+ args.arg1 = initialBounds;
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_DOCK_TOP_TASK, args));
+ }
+
+ @Override
+ public void onDraggingInRecents(float distanceFromTop) throws RemoteException {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_DRAGGING_IN_RECENTS, distanceFromTop));
+ }
+
+ @Override
+ public void onDraggingInRecentsEnded(float velocity) throws RemoteException {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_DRAGGING_IN_RECENTS_ENDED, velocity));
+ }
+
+ private final Handler mHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_PRELOAD_RECENTS:
+ mImpl.preloadRecents();
+ break;
+ case MSG_CANCEL_PRELOADING_RECENTS:
+ mImpl.cancelPreloadingRecents();
+ break;
+ case MSG_SHOW_RECENTS:
+ SomeArgs args = (SomeArgs) msg.obj;
+ mImpl.showRecents(args.argi1 != 0, args.argi2 != 0, args.argi3 != 0,
+ args.argi4 != 0);
+ break;
+ case MSG_HIDE_RECENTS:
+ mImpl.hideRecents(msg.arg1 != 0, msg.arg2 != 0);
+ break;
+ case MSG_TOGGLE_RECENTS:
+ mImpl.toggleRecents();
+ break;
+ case MSG_ON_CONFIGURATION_CHANGED:
+ mImpl.onConfigurationChanged();
+ break;
+ case MSG_DOCK_TOP_TASK:
+ args = (SomeArgs) msg.obj;
+ mImpl.dockTopTask(args.argi1, args.argi2, args.argi3 = 0,
+ (Rect) args.arg1);
+ break;
+ case MSG_ON_DRAGGING_IN_RECENTS:
+ mImpl.onDraggingInRecents((Float) msg.obj);
+ break;
+ case MSG_ON_DRAGGING_IN_RECENTS_ENDED:
+ mImpl.onDraggingInRecentsEnded((Float) msg.obj);
+ break;
+ default:
+ super.handleMessage(msg);
+ }
+ super.handleMessage(msg);
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
index fb21500..ae0051c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsSystemUser.java
@@ -22,6 +22,11 @@
import android.util.Log;
import android.util.SparseArray;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
+import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
+import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
+
/**
* An implementation of the system user's Recents interface to be called remotely by secondary
* users.
@@ -70,4 +75,19 @@
public void startScreenPinning() {
mImpl.onStartScreenPinning(mContext);
}
+
+ @Override
+ public void sendRecentsDrawnEvent() {
+ EventBus.getDefault().post(new RecentsDrawnEvent());
+ }
+
+ @Override
+ public void sendDockingTopTaskEvent(int dragMode) throws RemoteException {
+ EventBus.getDefault().post(new DockingTopTaskEvent(dragMode));
+ }
+
+ @Override
+ public void sendLaunchRecentsEvent() throws RemoteException {
+ EventBus.getDefault().post(new RecentsActivityStartingEvent());
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockingTopTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockingTopTaskEvent.java
new file mode 100644
index 0000000..264c2c4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DockingTopTaskEvent.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Fires when the user invoked the gesture to dock the top/left task.
+ */
+public class DockingTopTaskEvent extends EventBus.Event {
+
+ public int dragMode;
+
+ public DockingTopTaskEvent(int dragMode) {
+ this.dragMode = dragMode;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/RecentsActivityStartingEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/RecentsActivityStartingEvent.java
new file mode 100644
index 0000000..a2ecfe2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/RecentsActivityStartingEvent.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Called after recents activity is being started, i.e. startActivity has just been called.
+ */
+public class RecentsActivityStartingEvent extends EventBus.Event{
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/RecentsDrawnEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/RecentsDrawnEvent.java
new file mode 100644
index 0000000..5483166
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/RecentsDrawnEvent.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.recents.events.ui;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Fired when recents was launched and has drawn its first frame.
+ */
+public class RecentsDrawnEvent extends EventBus.Event {
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 87cfcff..2882cec 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -378,13 +378,19 @@
ActivityManager.StackInfo stackInfo = null;
try {
stackInfo = mIam.getStackInfo(DOCKED_STACK_ID);
- if (stackInfo != null && stackInfo.userId != getCurrentUser()) {
- return false;
- }
} catch (RemoteException e) {
e.printStackTrace();
}
- return stackInfo != null;
+
+ if (stackInfo != null) {
+ int userId = getCurrentUser();
+ boolean hasUserTask = false;
+ for (int i = stackInfo.taskUserIds.length - 1; i >= 0 && !hasUserTask; i--) {
+ hasUserTask = (stackInfo.taskUserIds[i] == userId);
+ }
+ return hasUserTask;
+ }
+ return false;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 08793e8..c0e1e44 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -49,7 +49,12 @@
import com.android.internal.policy.DockedDividerUtils;
import com.android.systemui.R;
import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
+import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
+import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
import com.android.systemui.statusbar.FlingAnimationUtils;
+import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
import static android.view.PointerIcon.STYLE_HORIZONTAL_DOUBLE_ARROW;
import static android.view.PointerIcon.STYLE_VERTICAL_DOUBLE_ARROW;
@@ -118,6 +123,10 @@
private DividerSnapAlgorithm mSnapAlgorithm;
private final Rect mStableInsets = new Rect();
+ private boolean mAnimateAfterRecentsDrawn;
+ private boolean mGrowAfterRecentsDrawn;
+ private boolean mGrowRecents;
+
public DividerView(Context context) {
super(context);
}
@@ -148,6 +157,7 @@
mDividerSize = mDividerWindowWidth - 2 * mDividerInsets;
mTouchElevation = getResources().getDimensionPixelSize(
R.dimen.docked_stack_divider_lift_elevation);
+ mGrowRecents = getResources().getBoolean(R.bool.recents_grow_in_multiwindow);
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
android.R.interpolator.fast_out_slow_in);
mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
@@ -161,6 +171,18 @@
}
@Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ EventBus.getDefault().register(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ EventBus.getDefault().unregister(this);
+ }
+
+ @Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
mStableInsets.set(insets.getStableInsetLeft(), insets.getStableInsetTop(),
insets.getStableInsetRight(), insets.getStableInsetBottom());
@@ -175,15 +197,18 @@
return mWindowManagerProxy;
}
- public boolean startDragging(boolean animate) {
- mHandle.setTouching(true, animate);
+ public boolean startDragging(boolean animate, boolean touching) {
+ if (touching) {
+ mHandle.setTouching(true, animate);
+ }
mDockSide = mWindowManagerProxy.getDockSide();
- mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), mDisplayWidth,
- mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets);
+ getSnapAlgorithm();
if (mDockSide != WindowManager.DOCKED_INVALID) {
mWindowManagerProxy.setResizing(true);
mWindowManager.setSlippery(false);
- liftBackground();
+ if (touching) {
+ liftBackground();
+ }
return true;
} else {
return false;
@@ -197,10 +222,31 @@
releaseBackground();
}
+ public void stopDragging(int position, SnapTarget target, long duration,
+ Interpolator interpolator) {
+ mHandle.setTouching(false, true /* animate */);
+ flingTo(position, target, duration, interpolator);
+ mWindowManager.setSlippery(true);
+ releaseBackground();
+ }
+
public DividerSnapAlgorithm getSnapAlgorithm() {
+ if (mSnapAlgorithm == null) {
+ mSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(), mDisplayWidth,
+ mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets);
+ }
return mSnapAlgorithm;
}
+ public int getCurrentPosition() {
+ getLocationOnScreen(mTempInt2);
+ if (isHorizontalDivision()) {
+ return mTempInt2[1] + mDividerInsets;
+ } else {
+ return mTempInt2[0] + mDividerInsets;
+ }
+ }
+
@Override
public boolean onTouch(View v, MotionEvent event) {
convertToScreenCoordinates(event);
@@ -211,13 +257,8 @@
mVelocityTracker.addMovement(event);
mStartX = (int) event.getX();
mStartY = (int) event.getY();
- getLocationOnScreen(mTempInt2);
- boolean result = startDragging(true /* animate */);
- if (isHorizontalDivision()) {
- mStartPosition = mTempInt2[1] + mDividerInsets;
- } else {
- mStartPosition = mTempInt2[0] + mDividerInsets;
- }
+ boolean result = startDragging(true /* animate */, true /* touching */);
+ mStartPosition = getCurrentPosition();
mMoving = false;
return result;
case MotionEvent.ACTION_MOVE:
@@ -265,8 +306,20 @@
if (avoidDismissStart && snapTarget == mSnapAlgorithm.getDismissStartTarget()) {
snapTarget = mSnapAlgorithm.getFirstSplitTarget();
}
- final SnapTarget finalTarget = snapTarget;
+ ValueAnimator anim = getFlingAnimator(position, snapTarget);
+ mFlingAnimationUtils.apply(anim, position, snapTarget.position, velocity);
+ anim.start();
+ }
+ private void flingTo(int position, SnapTarget target, long duration,
+ Interpolator interpolator) {
+ ValueAnimator anim = getFlingAnimator(position, target);
+ anim.setDuration(duration);
+ anim.setInterpolator(interpolator);
+ anim.start();
+ }
+
+ private ValueAnimator getFlingAnimator(int position, final SnapTarget snapTarget) {
ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
anim.addUpdateListener(new AnimatorUpdateListener() {
@Override
@@ -274,19 +327,18 @@
resizeStack((Integer) animation.getAnimatedValue(),
animation.getAnimatedFraction() == 1f
? TASK_POSITION_SAME
- : finalTarget.position, finalTarget);
+ : snapTarget.position, snapTarget);
}
});
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- commitSnapFlags(finalTarget);
+ commitSnapFlags(snapTarget);
mWindowManagerProxy.setResizing(false);
mDockSide = WindowManager.DOCKED_INVALID;
}
});
- mFlingAnimationUtils.apply(anim, position, snapTarget.position, velocity);
- anim.start();
+ return anim;
}
private void commitSnapFlags(SnapTarget target) {
@@ -359,6 +411,7 @@
display.getDisplayInfo(info);
mDisplayWidth = info.logicalWidth;
mDisplayHeight = info.logicalHeight;
+ mSnapAlgorithm = null;
}
private int calculatePosition(int touchX, int touchY) {
@@ -607,4 +660,33 @@
inoutInfo.touchableRegion.op(mBackground.getLeft(), mBackground.getTop(),
mBackground.getRight(), mBackground.getBottom(), Op.UNION);
}
+
+ public final void onBusEvent(RecentsActivityStartingEvent recentsActivityStartingEvent) {
+ if (mGrowRecents && getWindowManagerProxy().getDockSide() == WindowManager.DOCKED_TOP
+ && getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position) {
+ mGrowAfterRecentsDrawn = true;
+ startDragging(false /* animate */, false /* touching */);
+ }
+ }
+
+ public final void onBusEvent(DockingTopTaskEvent dockingEvent) {
+ if (dockingEvent.dragMode == NavigationBarGestureHelper.DRAG_MODE_NONE) {
+ mGrowAfterRecentsDrawn = false;
+ mAnimateAfterRecentsDrawn = true;
+ startDragging(false /* animate */, false /* touching */);
+ }
+ }
+
+ public final void onBusEvent(RecentsDrawnEvent drawnEvent) {
+ if (mAnimateAfterRecentsDrawn) {
+ mAnimateAfterRecentsDrawn = false;
+ stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250,
+ TOUCH_RESPONSE_INTERPOLATOR);
+ }
+ if (mGrowAfterRecentsDrawn) {
+ mGrowAfterRecentsDrawn = false;
+ stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250,
+ TOUCH_RESPONSE_INTERPOLATOR);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 38d24ce..01bfcea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -19,6 +19,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.animation.TimeAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
@@ -28,13 +29,12 @@
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.ViewConfiguration;
-import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
import android.view.animation.PathInterpolator;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
/**
* Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer}
@@ -107,11 +107,8 @@
private OnActivatedListener mOnActivatedListener;
- private final Interpolator mLinearOutSlowInInterpolator;
- protected final Interpolator mFastOutSlowInInterpolator;
private final Interpolator mSlowOutFastInInterpolator;
private final Interpolator mSlowOutLinearInInterpolator;
- private final Interpolator mLinearInterpolator;
private Interpolator mCurrentAppearInterpolator;
private Interpolator mCurrentAlphaInterpolator;
@@ -132,16 +129,37 @@
private FalsingManager mFalsingManager;
private boolean mTrackTouch;
+ private float mNormalBackgroundVisibilityAmount;
+ private ValueAnimator mFadeInFromDarkAnimator;
+ private ValueAnimator.AnimatorUpdateListener mBackgroundVisibilityUpdater
+ = new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ setNormalBackgroundVisibilityAmount(mBackgroundNormal.getAlpha());
+ }
+ };
+ private AnimatorListenerAdapter mFadeInEndListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ mFadeInFromDarkAnimator = null;
+ updateOutlineAlpha();
+ }
+ };
+ private ValueAnimator.AnimatorUpdateListener mUpdateOutlineListener
+ = new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ updateOutlineAlpha();
+ }
+ };
+ private float mShadowAlpha = 1.0f;
+
public ActivatableNotificationView(Context context, AttributeSet attrs) {
super(context, attrs);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
- mFastOutSlowInInterpolator =
- AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
mSlowOutFastInInterpolator = new PathInterpolator(0.8f, 0.0f, 0.6f, 1.0f);
- mLinearOutSlowInInterpolator =
- AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
mSlowOutLinearInInterpolator = new PathInterpolator(0.8f, 0.0f, 1.0f, 1.0f);
- mLinearInterpolator = new LinearInterpolator();
setClipChildren(false);
setClipToPadding(false);
mLegacyColor = context.getColor(R.color.notification_legacy_background_color);
@@ -166,6 +184,7 @@
mBackgroundDimmed.setCustomBackground(R.drawable.notification_material_bg_dim);
updateBackground();
updateBackgroundTint();
+ updateOutlineAlpha();
}
private final Runnable mTapTimeoutRunnable = new Runnable() {
@@ -272,7 +291,7 @@
}
}
- private void startActivateAnimation(boolean reverse) {
+ private void startActivateAnimation(final boolean reverse) {
if (!isAttachedToWindow()) {
return;
}
@@ -291,8 +310,8 @@
Interpolator interpolator;
Interpolator alphaInterpolator;
if (!reverse) {
- interpolator = mLinearOutSlowInInterpolator;
- alphaInterpolator = mLinearOutSlowInInterpolator;
+ interpolator = Interpolators.LINEAR_OUT_SLOW_IN;
+ alphaInterpolator = Interpolators.LINEAR_OUT_SLOW_IN;
} else {
interpolator = ACTIVATE_INVERSE_INTERPOLATOR;
alphaInterpolator = ACTIVATE_INVERSE_ALPHA_INTERPOLATOR;
@@ -317,6 +336,16 @@
mBackgroundNormal.animate()
.alpha(reverse ? 0f : 1f)
.setInterpolator(alphaInterpolator)
+ .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float animatedFraction = animation.getAnimatedFraction();
+ if (reverse) {
+ animatedFraction = 1.0f - animatedFraction;
+ }
+ setNormalBackgroundVisibilityAmount(animatedFraction);
+ }
+ })
.setDuration(ACTIVATE_ANIMATION_LENGTH);
}
@@ -377,8 +406,27 @@
} else {
updateBackground();
}
- setOutlineAlpha(dark ? 0f : 1f);
- }
+ updateOutlineAlpha();
+ }
+
+ private void updateOutlineAlpha() {
+ if (mDark) {
+ setOutlineAlpha(0f);
+ return;
+ }
+ float alpha = NotificationStackScrollLayout.BACKGROUND_ALPHA_DIMMED;
+ alpha = (alpha + (1.0f - alpha) * mNormalBackgroundVisibilityAmount);
+ alpha *= mShadowAlpha;
+ if (mFadeInFromDarkAnimator != null) {
+ alpha *= mFadeInFromDarkAnimator.getAnimatedFraction();
+ }
+ setOutlineAlpha(alpha);
+ }
+
+ public void setNormalBackgroundVisibilityAmount(float normalBackgroundVisibilityAmount) {
+ mNormalBackgroundVisibilityAmount = normalBackgroundVisibilityAmount;
+ updateOutlineAlpha();
+ }
public void setShowingLegacyBackground(boolean showing) {
mShowingLegacyBackground = showing;
@@ -431,7 +479,7 @@
.scaleY(1f)
.setDuration(DARK_ANIMATION_LENGTH)
.setStartDelay(delay)
- .setInterpolator(mLinearOutSlowInInterpolator)
+ .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
@@ -441,7 +489,15 @@
background.setAlpha(1f);
}
})
+ .setUpdateListener(mBackgroundVisibilityUpdater)
.start();
+ mFadeInFromDarkAnimator = TimeAnimator.ofFloat(0.0f, 1.0f);
+ mFadeInFromDarkAnimator.setDuration(DARK_ANIMATION_LENGTH);
+ mFadeInFromDarkAnimator.setStartDelay(delay);
+ mFadeInFromDarkAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
+ mFadeInFromDarkAnimator.addListener(mFadeInEndListener);
+ mFadeInFromDarkAnimator.addUpdateListener(mUpdateOutlineListener);
+ mFadeInFromDarkAnimator.start();
}
/**
@@ -474,7 +530,7 @@
mBackgroundNormal.setAlpha(startAlpha);
mBackgroundAnimator =
ObjectAnimator.ofFloat(mBackgroundNormal, View.ALPHA, startAlpha, endAlpha);
- mBackgroundAnimator.setInterpolator(mFastOutSlowInInterpolator);
+ mBackgroundAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mBackgroundAnimator.setDuration(duration);
mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -487,6 +543,7 @@
mBackgroundAnimator = null;
}
});
+ mBackgroundAnimator.addUpdateListener(mBackgroundVisibilityUpdater);
mBackgroundAnimator.start();
}
@@ -504,6 +561,8 @@
mBackgroundNormal.setAlpha(1f);
removeCallbacks(mTapTimeoutRunnable);
}
+ setNormalBackgroundVisibilityAmount(
+ mBackgroundNormal.getVisibility() == View.VISIBLE ? 1.0f : 0.0f);
}
protected boolean shouldHideBackground() {
@@ -577,16 +636,16 @@
float targetValue;
if (isAppearing) {
mCurrentAppearInterpolator = mSlowOutFastInInterpolator;
- mCurrentAlphaInterpolator = mLinearOutSlowInInterpolator;
+ mCurrentAlphaInterpolator = Interpolators.LINEAR_OUT_SLOW_IN;
targetValue = 1.0f;
} else {
- mCurrentAppearInterpolator = mFastOutSlowInInterpolator;
+ mCurrentAppearInterpolator = Interpolators.FAST_OUT_SLOW_IN;
mCurrentAlphaInterpolator = mSlowOutLinearInInterpolator;
targetValue = 0.0f;
}
mAppearAnimator = ValueAnimator.ofFloat(mAppearAnimationFraction,
targetValue);
- mAppearAnimator.setInterpolator(mLinearInterpolator);
+ mAppearAnimator.setInterpolator(Interpolators.LINEAR);
mAppearAnimator.setDuration(
(long) (duration * Math.abs(mAppearAnimationFraction - targetValue)));
mAppearAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@@ -772,6 +831,19 @@
return getBgColor() == otherView.getBgColor();
}
+ @Override
+ public float getShadowAlpha() {
+ return mShadowAlpha;
+ }
+
+ @Override
+ public void setShadowAlpha(float shadowAlpha) {
+ if (shadowAlpha != mShadowAlpha) {
+ mShadowAlpha = shadowAlpha;
+ updateOutlineAlpha();
+ }
+ }
+
public interface OnActivatedListener {
void onActivated(ActivatableNotificationView view);
void onActivationReset(ActivatableNotificationView view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 2592486..efa56bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -186,7 +186,7 @@
protected DevicePolicyManager mDevicePolicyManager;
protected IDreamManager mDreamManager;
- PowerManager mPowerManager;
+ protected PowerManager mPowerManager;
protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
// public mode, private notifications, etc
@@ -219,8 +219,6 @@
// which notification is currently being longpress-examined by the user
private NotificationGuts mNotificationGutsExposed;
- private TimeInterpolator mLinearOutSlowIn, mFastOutLinearIn;
-
private KeyboardShortcuts mKeyboardShortcuts;
/**
@@ -638,11 +636,6 @@
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- mLinearOutSlowIn = AnimationUtils.loadInterpolator(mContext,
- android.R.interpolator.linear_out_slow_in);
- mFastOutLinearIn = AnimationUtils.loadInterpolator(mContext,
- android.R.interpolator.fast_out_linear_in);
-
// Connect in to the status bar manager service
mCommandQueue = new CommandQueue(this);
@@ -1016,7 +1009,7 @@
final Animator a
= ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r);
a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- a.setInterpolator(mLinearOutSlowIn);
+ a.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
a.start();
guts.setExposed(true);
mStackScroller.onHeightChanged(null, true /* needsAnimation */);
@@ -1048,7 +1041,7 @@
final Animator a = ViewAnimationUtils.createCircularReveal(v,
x, y, r, 0);
a.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- a.setInterpolator(mFastOutLinearIn);
+ a.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
a.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
index f71f092..24cd948 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CrossFadeHelper.java
@@ -31,7 +31,7 @@
view.animate()
.alpha(0f)
.setDuration(ANIMATION_DURATION_LENGTH)
- .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+ .setInterpolator(Interpolators.ALPHA_OUT)
.withEndAction(new Runnable() {
@Override
public void run() {
@@ -56,7 +56,7 @@
view.animate()
.alpha(1f)
.setDuration(ANIMATION_DURATION_LENGTH)
- .setInterpolator(PhoneStatusBar.ALPHA_IN)
+ .setInterpolator(Interpolators.ALPHA_IN)
.withEndAction(null);
if (view.hasOverlappingRendering()) {
view.animate().withLayer();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index 8570198..5c83f5f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -24,8 +24,7 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
+
import com.android.systemui.ExpandHelper;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
@@ -53,7 +52,6 @@
private final int[] mTemp2 = new int[2];
private boolean mDraggedFarEnough;
private ExpandableView mStartingChild;
- private Interpolator mInterpolator;
private float mLastHeight;
private FalsingManager mFalsingManager;
@@ -61,8 +59,6 @@
DragDownCallback dragDownCallback) {
mMinDragDistance = context.getResources().getDimensionPixelSize(
R.dimen.keyguard_drag_down_min_distance);
- mInterpolator =
- AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mCallback = callback;
mDragDownCallback = dragDownCallback;
@@ -187,7 +183,7 @@
}
ObjectAnimator anim = ObjectAnimator.ofInt(child, "actualHeight",
child.getActualHeight(), child.getMinHeight());
- anim.setInterpolator(mInterpolator);
+ anim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
anim.setDuration(SPRING_BACK_ANIMATION_LENGTH_MS);
anim.addListener(new AnimatorListenerAdapter() {
@Override
@@ -200,7 +196,7 @@
private void cancelExpansion() {
ValueAnimator anim = ValueAnimator.ofFloat(mLastHeight, 0);
- anim.setInterpolator(mInterpolator);
+ anim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
anim.setDuration(SPRING_BACK_ANIMATION_LENGTH_MS);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 93be009..6fae3ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -1126,6 +1126,11 @@
}
@Override
+ public boolean needsIncreasedPadding() {
+ return mIsSummaryWithChildren && isGroupExpanded();
+ }
+
+ @Override
protected boolean disallowSingleClick(MotionEvent event) {
float x = event.getX();
float y = event.getY();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index a6fc4bb..44c6a5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -24,22 +24,17 @@
import android.view.View;
import android.view.ViewOutlineProvider;
-import com.android.systemui.R;
-
/**
* Like {@link ExpandableView}, but setting an outline for the height and clipping.
*/
public abstract class ExpandableOutlineView extends ExpandableView {
private final Rect mOutlineRect = new Rect();
- protected final int mRoundedRectCornerRadius;
private boolean mCustomOutline;
- private float mOutlineAlpha = 1f;
+ private float mOutlineAlpha = -1f;
public ExpandableOutlineView(Context context, AttributeSet attrs) {
super(context, attrs);
- mRoundedRectCornerRadius = getResources().getDimensionPixelSize(
- R.dimen.notification_material_rounded_rect_radius);
setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
@@ -49,7 +44,7 @@
getWidth(),
Math.max(getActualHeight(), mClipTopAmount));
} else {
- outline.setRoundRect(mOutlineRect, mRoundedRectCornerRadius);
+ outline.setRect(mOutlineRect);
}
outline.setAlpha(mOutlineAlpha);
}
@@ -69,8 +64,10 @@
}
protected void setOutlineAlpha(float alpha) {
- mOutlineAlpha = alpha;
- invalidateOutline();
+ if (alpha != mOutlineAlpha) {
+ mOutlineAlpha = alpha;
+ invalidateOutline();
+ }
}
protected void setOutlineRect(RectF rect) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index c190864..a0fb34a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -388,6 +388,17 @@
return super.hasOverlappingRendering() && getActualHeight() <= getHeight();
}
+ public float getShadowAlpha() {
+ return 0.0f;
+ }
+
+ public void setShadowAlpha(float shadowAlpha) {
+ }
+
+ public boolean needsIncreasedPadding() {
+ return false;
+ }
+
/**
* A listener notifying when {@link #getActualHeight} changes.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
index 0fa088b..c4ffd7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/FlingAnimationUtils.java
@@ -19,7 +19,6 @@
import android.animation.Animator;
import android.content.Context;
import android.view.ViewPropertyAnimator;
-import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
@@ -41,8 +40,6 @@
private static final float LINEAR_OUT_SLOW_IN_START_GRADIENT = 1.0f / LINEAR_OUT_SLOW_IN_X2;
private Interpolator mLinearOutSlowIn;
- private Interpolator mFastOutSlowIn;
- private Interpolator mFastOutLinearIn;
private float mMinVelocityPxPerSecond;
private float mMaxLengthSeconds;
@@ -53,10 +50,6 @@
public FlingAnimationUtils(Context ctx, float maxLengthSeconds) {
mMaxLengthSeconds = maxLengthSeconds;
mLinearOutSlowIn = new PathInterpolator(0, 0, LINEAR_OUT_SLOW_IN_X2, 1);
- mFastOutSlowIn
- = AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_slow_in);
- mFastOutLinearIn
- = AnimationUtils.loadInterpolator(ctx, android.R.interpolator.fast_out_linear_in);
mMinVelocityPxPerSecond
= MIN_VELOCITY_DP_PER_SECOND * ctx.getResources().getDisplayMetrics().density;
mHighVelocityPxPerSecond
@@ -150,7 +143,7 @@
// Just use a normal interpolator which doesn't take the velocity into account.
durationSeconds = maxLengthSeconds;
- mAnimatorProperties.interpolator = mFastOutSlowIn;
+ mAnimatorProperties.interpolator = Interpolators.FAST_OUT_SLOW_IN;
}
mAnimatorProperties.duration = (long) (durationSeconds * 1000);
return mAnimatorProperties;
@@ -223,7 +216,7 @@
// Just use a normal interpolator which doesn't take the velocity into account.
durationSeconds = maxLengthSeconds;
- mAnimatorProperties.interpolator = mFastOutLinearIn;
+ mAnimatorProperties.interpolator = Interpolators.FAST_OUT_LINEAR_IN;
}
mAnimatorProperties.duration = (long) (durationSeconds * 1000);
return mAnimatorProperties;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/Interpolators.java b/packages/SystemUI/src/com/android/systemui/statusbar/Interpolators.java
new file mode 100644
index 0000000..5979468
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/Interpolators.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+import android.view.animation.PathInterpolator;
+
+/**
+ * Utility class to receive interpolators from
+ */
+public class Interpolators {
+ public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+ public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
+ public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
+ public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
+ public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
+ public static final Interpolator LINEAR = new LinearInterpolator();
+ public static final Interpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 8058933..841b9d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -33,13 +33,11 @@
import android.view.RenderNodeAnimator;
import android.view.View;
import android.view.ViewAnimationUtils;
-import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.ImageView;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.KeyguardAffordanceHelper;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
/**
* An ImageView which does not have overlapping renderings commands and therefore does not need a
@@ -55,8 +53,6 @@
private final int mMinBackgroundRadius;
private final Paint mCirclePaint;
- private final Interpolator mAppearInterpolator;
- private final Interpolator mDisappearInterpolator;
private final int mInverseColor;
private final int mNormalColor;
private final ArgbEvaluator mColorInterpolator;
@@ -136,10 +132,6 @@
mInverseColor = 0xff000000;
mMinBackgroundRadius = mContext.getResources().getDimensionPixelSize(
R.dimen.keyguard_affordance_min_background_radius);
- mAppearInterpolator = AnimationUtils.loadInterpolator(mContext,
- android.R.interpolator.linear_out_slow_in);
- mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext,
- android.R.interpolator.fast_out_linear_in);
mColorInterpolator = new ArgbEvaluator();
mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.3f);
}
@@ -261,7 +253,7 @@
RenderNodeAnimator animator = new RenderNodeAnimator(mHwCirclePaint,
RenderNodeAnimator.PAINT_ALPHA, 255);
animator.setTarget(this);
- animator.setInterpolator(PhoneStatusBar.ALPHA_IN);
+ animator.setInterpolator(Interpolators.ALPHA_IN);
animator.setDuration(250);
animator.start();
}
@@ -282,7 +274,7 @@
RenderNodeAnimator animator = new RenderNodeAnimator(mHwCirclePaint,
RenderNodeAnimator.PAINT_ALPHA, 0);
animator.setDuration(duration);
- animator.setInterpolator(PhoneStatusBar.ALPHA_OUT);
+ animator.setInterpolator(Interpolators.ALPHA_OUT);
animator.setTarget(this);
animator.start();
}
@@ -352,8 +344,8 @@
cancelAnimator(mPreviewClipper);
ValueAnimator animator = getAnimatorToRadius(circleRadius);
Interpolator interpolator = circleRadius == 0.0f
- ? mDisappearInterpolator
- : mAppearInterpolator;
+ ? Interpolators.FAST_OUT_LINEAR_IN
+ : Interpolators.LINEAR_OUT_SLOW_IN;
animator.setInterpolator(interpolator);
long duration = 250;
if (!slowAnimation) {
@@ -438,8 +430,8 @@
animator.addListener(mScaleEndListener);
if (interpolator == null) {
interpolator = imageScale == 0.0f
- ? mDisappearInterpolator
- : mAppearInterpolator;
+ ? Interpolators.FAST_OUT_LINEAR_IN
+ : Interpolators.LINEAR_OUT_SLOW_IN;
}
animator.setInterpolator(interpolator);
if (duration == -1) {
@@ -501,8 +493,8 @@
animator.addListener(mAlphaEndListener);
if (interpolator == null) {
interpolator = alpha == 0.0f
- ? mDisappearInterpolator
- : mAppearInterpolator;
+ ? Interpolators.FAST_OUT_LINEAR_IN
+ : Interpolators.LINEAR_OUT_SLOW_IN;
}
animator.setInterpolator(interpolator);
if (duration == -1) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 36cf906..635e66d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -52,8 +52,6 @@
private static final int VISIBLE_TYPE_SINGLELINE = 3;
private final Rect mClipBounds = new Rect();
- private final int mRoundRectRadius;
- private final boolean mRoundRectClippingEnabled;
private final int mMinContractedHeight;
private final OnLayoutChangeListener mLayoutUpdater = new OnLayoutChangeListener() {
@Override
@@ -100,13 +98,6 @@
}
};
- private final ViewOutlineProvider mOutlineProvider = new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRoundRect(0, 0, view.getWidth(), mUnrestrictedContentHeight,
- mRoundRectRadius);
- }
- };
private OnClickListener mExpandClickListener;
private boolean mBeforeN;
private boolean mExpandable;
@@ -116,14 +107,9 @@
public NotificationContentView(Context context, AttributeSet attrs) {
super(context, attrs);
mHybridViewManager = new HybridNotificationViewManager(getContext(), this);
- mRoundRectRadius = getResources().getDimensionPixelSize(
- R.dimen.notification_material_rounded_rect_radius);
- mRoundRectClippingEnabled = getResources().getBoolean(
- R.bool.config_notifications_round_rect_clipping);
mMinContractedHeight = getResources().getDimensionPixelSize(
R.dimen.min_notification_layout_height);
reset(true);
- setOutlineProvider(mOutlineProvider);
}
public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight) {
@@ -253,7 +239,6 @@
mContractedWrapper = NotificationViewWrapper.wrap(getContext(), child);
selectLayout(false /* animate */, true /* force */);
mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */);
- updateRoundRectClipping();
}
public void setExpandedChild(View child) {
@@ -267,7 +252,6 @@
mExpandedChild.addOnLayoutChangeListener(mLayoutUpdater);
mExpandedWrapper = NotificationViewWrapper.wrap(getContext(), child);
selectLayout(false /* animate */, true /* force */);
- updateRoundRectClipping();
}
public void setHeadsUpChild(View child) {
@@ -281,7 +265,6 @@
mHeadsUpChild.addOnLayoutChangeListener(mLayoutUpdater);
mHeadsUpWrapper = NotificationViewWrapper.wrap(getContext(), child);
selectLayout(false /* animate */, true /* force */);
- updateRoundRectClipping();
}
@Override
@@ -344,27 +327,6 @@
updateClipping();
}
- private void updateRoundRectClipping() {
- boolean enabled = needsRoundRectClipping();
- setClipToOutline(enabled);
- }
-
- private boolean needsRoundRectClipping() {
- if (!mRoundRectClippingEnabled) {
- return false;
- }
- boolean needsForContracted = mContractedChild != null
- && mContractedChild.getVisibility() == View.VISIBLE
- && mContractedWrapper.needsRoundRectClipping();
- boolean needsForExpanded = mExpandedChild != null
- && mExpandedChild.getVisibility() == View.VISIBLE
- && mExpandedWrapper.needsRoundRectClipping();
- boolean needsForHeadsUp = mExpandedChild != null
- && mExpandedChild.getVisibility() == View.VISIBLE
- && mExpandedWrapper.needsRoundRectClipping();
- return needsForContracted || needsForExpanded || needsForHeadsUp;
- }
-
private void updateClipping() {
if (mClipToActualHeight) {
mClipBounds.set(0, mClipTopAmount, getWidth(), mContentHeight);
@@ -412,7 +374,6 @@
boolean singleLineVisible = visibleType == VISIBLE_TYPE_SINGLELINE;
mSingleLineView.setVisible(singleLineVisible);
}
- updateRoundRectClipping();
}
private void animateToVisibleType(int visibleType) {
@@ -426,7 +387,6 @@
hiddenView.setVisible(false);
}
});
- updateRoundRectClipping();
}
/**
@@ -553,7 +513,6 @@
if (mHeadsUpChild != null) {
mHeadsUpWrapper.notifyContentUpdated(entry.notification);
}
- updateRoundRectClipping();
}
private void updateSingleLineView() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
index e4cd7d9..5abd1d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
@@ -206,13 +206,8 @@
void saveImportance(final StatusBarNotification sbn) {
int progress = mSeekBar.getProgress();
try {
- if (mApplyToTopic.isChecked()) {
- mINotificationManager.setTopicImportance(sbn.getPackageName(), sbn.getUid(), mTopic,
- progress);
- } else {
- mINotificationManager.setAppImportance(
- sbn.getPackageName(), sbn.getUid(), progress);
- }
+ mINotificationManager.setImportance(sbn.getPackageName(), sbn.getUid(),
+ mApplyToTopic.isChecked() ? mTopic : null, progress);
} catch (RemoteException e) {
// :(
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index 682676b..4e3ecb1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -22,7 +22,10 @@
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Paint;
import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Interpolator;
@@ -32,11 +35,14 @@
*/
public class ScrimView extends View
{
+ private final Paint mPaint = new Paint();
private int mScrimColor;
private boolean mIsEmpty = true;
private boolean mDrawAsSrc;
private float mViewAlpha = 1.0f;
private ValueAnimator mAlphaAnimator;
+ private Rect mExcludedRect = new Rect();
+ private boolean mHasExcludedArea;
private ValueAnimator.AnimatorUpdateListener mAlphaUpdateListener
= new ValueAnimator.AnimatorUpdateListener() {
@Override
@@ -51,6 +57,7 @@
mAlphaAnimator = null;
}
};
+ private Runnable mChangeRunnable;
public ScrimView(Context context) {
this(context, null);
@@ -72,15 +79,43 @@
protected void onDraw(Canvas canvas) {
if (mDrawAsSrc || (!mIsEmpty && mViewAlpha > 0f)) {
PorterDuff.Mode mode = mDrawAsSrc ? PorterDuff.Mode.SRC : PorterDuff.Mode.SRC_OVER;
- int color = mScrimColor;
- color = Color.argb((int) (Color.alpha(color) * mViewAlpha), Color.red(color),
- Color.green(color), Color.blue(color));
- canvas.drawColor(color, mode);
+ int color = getScrimColorWithAlpha();
+ if (!mHasExcludedArea) {
+ canvas.drawColor(color, mode);
+ } else {
+ mPaint.setColor(color);
+ if (mExcludedRect.top > 0) {
+ canvas.drawRect(0, 0, getWidth(), mExcludedRect.top, mPaint);
+ }
+ if (mExcludedRect.left > 0) {
+ canvas.drawRect(0, mExcludedRect.top, mExcludedRect.left, mExcludedRect.bottom,
+ mPaint);
+ }
+ if (mExcludedRect.right < getWidth()) {
+ canvas.drawRect(mExcludedRect.right,
+ mExcludedRect.top,
+ getWidth(),
+ mExcludedRect.bottom,
+ mPaint);
+ }
+ if (mExcludedRect.bottom < getHeight()) {
+ canvas.drawRect(0, mExcludedRect.bottom, getWidth(), getHeight(), mPaint);
+ }
+ }
}
}
+ public int getScrimColorWithAlpha() {
+ int color = mScrimColor;
+ color = Color.argb((int) (Color.alpha(color) * mViewAlpha), Color.red(color),
+ Color.green(color), Color.blue(color));
+ return color;
+ }
+
public void setDrawAsSrc(boolean asSrc) {
mDrawAsSrc = asSrc;
+ mPaint.setXfermode(new PorterDuffXfermode(mDrawAsSrc ? PorterDuff.Mode.SRC
+ : PorterDuff.Mode.SRC_OVER));
invalidate();
}
@@ -89,6 +124,9 @@
mIsEmpty = Color.alpha(color) == 0;
mScrimColor = color;
invalidate();
+ if (mChangeRunnable != null) {
+ mChangeRunnable.run();
+ }
}
}
@@ -105,8 +143,13 @@
if (mAlphaAnimator != null) {
mAlphaAnimator.cancel();
}
- mViewAlpha = alpha;
- invalidate();
+ if (alpha != mViewAlpha) {
+ mViewAlpha = alpha;
+ invalidate();
+ if (mChangeRunnable != null) {
+ mChangeRunnable.run();
+ }
+ }
}
public void animateViewAlpha(float alpha, long durationOut, Interpolator interpolator) {
@@ -120,4 +163,23 @@
mAlphaAnimator.setDuration(durationOut);
mAlphaAnimator.start();
}
+
+ public void setExcludedArea(Rect area) {
+ if (area == null) {
+ mHasExcludedArea = false;
+ invalidate();
+ return;
+ }
+ area.left = Math.max(area.left, 0);
+ area.top = Math.max(area.top, 0);
+ area.right = Math.min(area.right, getWidth());
+ area.bottom = Math.min(area.bottom, getHeight());
+ mExcludedRect.set(area);
+ mHasExcludedArea = area.left < area.right && area.top < area.bottom;
+ invalidate();
+ }
+
+ public void setChangeRunnable(Runnable changeRunnable) {
+ mChangeRunnable = changeRunnable;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
deleted file mode 100644
index 1fc8744..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SpeedBumpView.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-import com.android.systemui.R;
-
-/**
- * The view representing the separation between important and less important notifications
- */
-public class SpeedBumpView extends ExpandableView {
-
- private final int mSpeedBumpHeight;
- private AlphaOptimizedView mLine;
- private boolean mIsVisible = true;
- private final Interpolator mFastOutSlowInInterpolator;
-
- public SpeedBumpView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mSpeedBumpHeight = getResources()
- .getDimensionPixelSize(R.dimen.speed_bump_height);
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
- android.R.interpolator.fast_out_slow_in);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mLine = (AlphaOptimizedView) findViewById(R.id.speedbump_line);
- }
-
- @Override
- protected int getInitialHeight() {
- return mSpeedBumpHeight;
- }
-
- @Override
- public int getIntrinsicHeight() {
- return mSpeedBumpHeight;
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- mLine.setPivotX(mLine.getWidth() / 2);
- mLine.setPivotY(mLine.getHeight() / 2);
- setOutlineProvider(null);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- measureChildren(widthMeasureSpec, heightMeasureSpec);
- int height = mSpeedBumpHeight;
- setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), height);
- }
-
- @Override
- public boolean isTransparent() {
- return true;
- }
-
- public void performVisibilityAnimation(boolean nowVisible, long delay) {
- animateDivider(nowVisible, delay, null /* onFinishedRunnable */);
- }
-
- /**
- * Animate the divider to a new visibility.
- *
- * @param nowVisible should it now be visible
- * @param delay the delay after the animation should start
- * @param onFinishedRunnable A runnable which should be run when the animation is
- * finished.
- */
- public void animateDivider(boolean nowVisible, long delay, Runnable onFinishedRunnable) {
- if (nowVisible != mIsVisible) {
- // Animate dividers
- float endValue = nowVisible ? 1.0f : 0.0f;
- mLine.animate()
- .alpha(endValue)
- .setStartDelay(delay)
- .scaleX(endValue)
- .scaleY(endValue)
- .setInterpolator(mFastOutSlowInInterpolator)
- .withEndAction(onFinishedRunnable);
- mIsVisible = nowVisible;
- } else {
- if (onFinishedRunnable != null) {
- onFinishedRunnable.run();
- }
- }
- }
-
- public void setInvisible() {
- mLine.setAlpha(0.0f);
- mLine.setScaleX(0.0f);
- mLine.setScaleY(0.0f);
- mIsVisible = false;
- }
-
- @Override
- public void performRemoveAnimation(long duration, float translationDirection,
- Runnable onFinishedRunnable) {
- // TODO: Use duration
- performVisibilityAnimation(false, 0 /* delay */);
- }
-
- @Override
- public void performAddAnimation(long delay, long duration) {
- // TODO: Use duration
- performVisibilityAnimation(true, delay);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
index 2f66c41..c836637 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StackScrollerDecorView.java
@@ -21,8 +21,6 @@
import android.view.View;
import android.view.animation.Interpolator;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
-
/**
* A common base class for all views in the notification stack scroller which don't have a
* background.
@@ -80,9 +78,9 @@
float endValue = nowVisible ? 1.0f : 0.0f;
Interpolator interpolator;
if (nowVisible) {
- interpolator = PhoneStatusBar.ALPHA_IN;
+ interpolator = Interpolators.ALPHA_IN;
} else {
- interpolator = PhoneStatusBar.ALPHA_OUT;
+ interpolator = Interpolators.ALPHA_OUT;
}
mAnimating = true;
mContent.animate()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
index 3e2c4c6..bed64a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -39,6 +39,10 @@
* the navigation buttons by updating arrays_car.xml appropriately in an overlay.
*/
class CarNavigationBarController {
+ private static final String EXTRA_FACET_CATEGORIES = "categories";
+ private static final String EXTRA_FACET_PACKAGES = "packages";
+ private static final String EXTRA_FACET_ID = "filter_id";
+ private static final String EXTRA_FACET_LAUNCH_PICKER = "launch_picker";
// Each facet of the navigation bar maps to a set of package names or categories defined in
// arrays_car.xml. Package names for a given facet are delimited by ";"
@@ -64,6 +68,7 @@
private List<CarNavigationButton> mNavButtons = new ArrayList<CarNavigationButton>();
private int mCurrentFacetIndex;
+ private String mCurrentPackageName;
public CarNavigationBarController(Context context,
CarNavigationBarView navBar,
@@ -75,6 +80,7 @@
}
public void taskChanged(String packageName) {
+ mCurrentPackageName = packageName;
// If the package name belongs to a filter, then highlight appropriate button in
// the navigation bar.
if (mFacetPackageMap.containsKey(packageName)) {
@@ -121,7 +127,8 @@
CarNavigationButton button = createNavButton(icon, i, hasLongpress);
mNavButtons.add(button);
- mNavBar.addButton(button, createNavButton(icon, i, hasLongpress));
+ mNavBar.addButton(button,
+ createNavButton(icon, i, hasLongpress) /* lightsOutButton */);
initFacetFilterMaps(i,
facetPackageNames.getString(i).split(FACET_FILTER_DEMILITER),
@@ -132,7 +139,7 @@
}
}
- private void initFacetFilterMaps(int id, String[] packageNames, String[] categories){
+ private void initFacetFilterMaps(int id, String[] packageNames, String[] categories) {
mFacetCategories.add(categories);
for (int i = 0; i < categories.length; i++) {
mFacetCategoryMap.put(categories[i], id);
@@ -234,7 +241,6 @@
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- setCurrentFacet(id);
onFacetClicked(id);
}
});
@@ -245,13 +251,13 @@
@Override
public boolean onLongClick(View v) {
onFacetLongClicked(id);
- setCurrentFacet(id);
return true;
}
});
} else {
button.setLongClickable(false);
}
+
return button;
}
@@ -262,14 +268,35 @@
}
private void onFacetClicked(int index) {
- // TODO: determine what data to pass to the trampoline, so it can start
- // the default app or the lens picker.
- startActivity(mIntents.get(index));
+ Intent intent = mIntents.get(index);
+ String packageName = intent.getPackage();
+
+ if (packageName == null) {
+ return;
+ }
+
+ // Don't launch the lens picker if it's already running and the
+ // user clicks the same facet
+ if (packageName.equals(mCurrentPackageName) && index == mCurrentFacetIndex) {
+ return;
+ }
+
+ intent.putExtra(EXTRA_FACET_CATEGORIES, mFacetCategories.get(index));
+ intent.putExtra(EXTRA_FACET_PACKAGES, mFacetPackages.get(index));
+ // The facet is identified by the index in which it was added to the nav bar.
+ // This value can be used to determine which facet was selected
+ intent.putExtra(EXTRA_FACET_ID, Integer.toString(index));
+
+ // If the current facet is clicked, we want to launch the picker by default
+ // rather than the "preferred/last run" app.
+ intent.putExtra(EXTRA_FACET_LAUNCH_PICKER, index == mCurrentFacetIndex);
+
+ setCurrentFacet(index);
+ startActivity(intent);
}
private void onFacetLongClicked(int index) {
- // TODO: determine what data to pass to the trampoline, so it can start
- // the default app or the lens picker.
+ setCurrentFacet(index);
startActivity(mLongPressIntents.get(index));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
index 36b3a8a..504f059 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
@@ -18,8 +18,6 @@
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
-import android.widget.ImageButton;
-import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.android.keyguard.AlphaOptimizedImageButton;
import com.android.systemui.R;
@@ -43,13 +41,11 @@
super.onFinishInflate();
mIcon = (AlphaOptimizedImageButton) findViewById(R.id.car_nav_button_icon);
mIcon.setClickable(false);
- mIcon.setScaleType(ImageView.ScaleType.CENTER);
mIcon.setBackgroundColor(android.R.color.transparent);
mIcon.setAlpha(UNSELECTED_ALPHA);
mMoreIcon = (AlphaOptimizedImageButton) findViewById(R.id.car_nav_button_more_icon);
mMoreIcon.setClickable(false);
- mMoreIcon.setScaleType(ImageView.ScaleType.CENTER);
mMoreIcon.setBackgroundColor(android.R.color.transparent);
mMoreIcon.setVisibility(INVISIBLE);
mMoreIcon.setImageDrawable(getContext().getDrawable(R.drawable.car_ic_arrow));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
index fd65aac..97bf4b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
@@ -41,9 +41,4 @@
mInvertHelper.update(dark);
}
}
-
- @Override
- public boolean needsRoundRectClipping() {
- return true;
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
index 4fd4cab..f43a5d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
@@ -38,6 +38,7 @@
import com.android.systemui.R;
import com.android.systemui.ViewInvertHelper;
+import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.ViewTransformationHelper;
import com.android.systemui.statusbar.phone.NotificationPanelView;
@@ -55,7 +56,6 @@
0, PorterDuff.Mode.SRC_ATOP);
private final int mIconDarkAlpha;
private final int mIconDarkColor = 0xffffffff;
- protected final Interpolator mLinearOutSlowInInterpolator;
protected final ViewInvertHelper mInvertHelper;
protected final ViewTransformationHelper mTransformationHelper;
@@ -69,8 +69,6 @@
protected NotificationHeaderViewWrapper(Context ctx, View view) {
super(view);
mIconDarkAlpha = ctx.getResources().getInteger(R.integer.doze_small_icon_alpha);
- mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(ctx,
- android.R.interpolator.linear_out_slow_in);
mInvertHelper = new ViewInvertHelper(ctx, NotificationPanelView.DOZE_ANIMATION_DURATION);
mTransformationHelper = new ViewTransformationHelper();
resolveHeaderViews();
@@ -185,7 +183,7 @@
ValueAnimator animator = ValueAnimator.ofFloat(startIntensity, endIntensity);
animator.addUpdateListener(updateListener);
animator.setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
- animator.setInterpolator(mLinearOutSlowInInterpolator);
+ animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
animator.setStartDelay(delay);
if (listener != null) {
animator.addListener(listener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index a959e07..3475d13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -26,6 +26,7 @@
import android.widget.TextView;
import com.android.systemui.statusbar.CrossFadeHelper;
+import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.TransformableView;
import com.android.systemui.statusbar.ViewTransformationHelper;
import com.android.systemui.statusbar.stack.StackStateAnimator;
@@ -64,7 +65,7 @@
- ownPosition[1]) * 0.33f)
.setDuration(
StackStateAnimator.ANIMATION_DURATION_STANDARD)
- .setInterpolator(TransformState.FAST_OUT_SLOW_IN)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.withEndAction(new Runnable() {
@Override
public void run() {
@@ -103,7 +104,7 @@
.translationY(0)
.setDuration(
StackStateAnimator.ANIMATION_DURATION_STANDARD)
- .setInterpolator(TransformState.FAST_OUT_SLOW_IN)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.withEndAction(new Runnable() {
@Override
public void run() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index 0ceba78..a1cf07e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -65,14 +65,6 @@
public void notifyContentUpdated(StatusBarNotification notification) {};
/**
- * @return true if this template might need to be clipped with a round rect to make it look
- * nice, false otherwise
- */
- public boolean needsRoundRectClipping() {
- return false;
- }
-
- /**
* Update the appearance of the expand button.
*
* @param expandable should this view be expandable
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index 388ba0e..3e1c40a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -22,8 +22,6 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
-import android.view.animation.Interpolator;
-import android.view.animation.PathInterpolator;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
@@ -31,6 +29,7 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.stack.StackStateAnimator;
/**
@@ -44,7 +43,6 @@
private static final int CLIP_CLIPPING_SET = R.id.clip_children_set_tag;
private static final int CLIP_CHILDREN_TAG = R.id.clip_children_tag;
private static final int CLIP_TO_PADDING = R.id.clip_to_padding_tag;
- public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
private static Pools.SimplePool<TransformState> sInstancePool = new Pools.SimplePool<>(40);
protected View mTransformedView;
@@ -110,7 +108,7 @@
}
}
transformedView.animate()
- .setInterpolator(TransformState.FAST_OUT_SLOW_IN)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
.withEndAction(new Runnable() {
@Override
@@ -168,7 +166,7 @@
.translationY(otherStablePosition[1] - ownPosition[1]);
}
transformedView.animate()
- .setInterpolator(TransformState.FAST_OUT_SLOW_IN)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
.withEndAction(new Runnable() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index a3f404a..37e5558 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -32,6 +32,7 @@
import android.view.animation.LinearInterpolator;
import com.android.systemui.R;
+import com.android.systemui.statusbar.Interpolators;
public class BarTransitions {
private static final boolean DEBUG = false;
@@ -124,7 +125,6 @@
private final int mTransparent;
private final int mWarning;
private final Drawable mGradient;
- private final TimeInterpolator mInterpolator;
private int mMode = -1;
private boolean mAnimating;
@@ -152,7 +152,6 @@
mWarning = context.getColor(com.android.internal.R.color.battery_saver_mode_color);
}
mGradient = context.getDrawable(gradientResourceId);
- mInterpolator = new LinearInterpolator();
}
@Override
@@ -222,7 +221,8 @@
mGradientAlpha = targetGradientAlpha;
} else {
final float t = (now - mStartTime) / (float)(mEndTime - mStartTime);
- final float v = Math.max(0, Math.min(mInterpolator.getInterpolation(t), 1));
+ final float v = Math.max(0, Math.min(
+ Interpolators.LINEAR.getInterpolation(t), 1));
mGradientAlpha = (int)(v * targetGradientAlpha + mGradientAlphaStart * (1 - v));
mColor = Color.argb(
(int)(v * Color.alpha(targetColor) + Color.alpha(mColorStart) * (1 - v)),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 3ff69c9..b5dba18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -23,11 +23,11 @@
import android.content.Context;
import android.os.Handler;
import android.util.Log;
-import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
+import com.android.systemui.statusbar.Interpolators;
/**
* Controller which handles all the doze animations of the scrims.
@@ -37,10 +37,6 @@
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final DozeParameters mDozeParameters;
- private final Interpolator mPulseInInterpolator = PhoneStatusBar.ALPHA_OUT;
- private final Interpolator mPulseInInterpolatorPickup;
- private final Interpolator mPulseOutInterpolator = PhoneStatusBar.ALPHA_IN;
- private final Interpolator mDozeAnimationInterpolator;
private final Handler mHandler = new Handler();
private final ScrimController mScrimController;
@@ -55,8 +51,6 @@
public DozeScrimController(ScrimController scrimController, Context context) {
mScrimController = scrimController;
mDozeParameters = new DozeParameters(context);
- mDozeAnimationInterpolator = mPulseInInterpolatorPickup =
- AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
}
public void setDozing(boolean dozing, boolean animate) {
@@ -70,9 +64,11 @@
cancelPulsing();
if (animate) {
startScrimAnimation(false /* inFront */, 0f /* target */,
- NotificationPanelView.DOZE_ANIMATION_DURATION, mDozeAnimationInterpolator);
+ NotificationPanelView.DOZE_ANIMATION_DURATION,
+ Interpolators.LINEAR_OUT_SLOW_IN);
startScrimAnimation(true /* inFront */, 0f /* target */,
- NotificationPanelView.DOZE_ANIMATION_DURATION, mDozeAnimationInterpolator);
+ NotificationPanelView.DOZE_ANIMATION_DURATION,
+ Interpolators.LINEAR_OUT_SLOW_IN);
} else {
abortAnimations();
mScrimController.setDozeBehindAlpha(0f);
@@ -116,7 +112,7 @@
final boolean pickup = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
startScrimAnimation(true /* inFront */, 0f,
mDozeParameters.getPulseInDuration(pickup),
- pickup ? mPulseInInterpolatorPickup : mPulseInInterpolator,
+ pickup ? Interpolators.LINEAR_OUT_SLOW_IN : Interpolators.ALPHA_OUT,
mPulseInFinished);
}
}
@@ -266,7 +262,7 @@
if (DEBUG) Log.d(TAG, "Pulse out, mDozing=" + mDozing);
if (!mDozing) return;
startScrimAnimation(true /* inFront */, 1f, mDozeParameters.getPulseOutDuration(),
- mPulseOutInterpolator, mPulseOutFinished);
+ Interpolators.ALPHA_IN, mPulseOutFinished);
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/GetActivityIconTask.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/GetActivityIconTask.java
deleted file mode 100644
index d2bec7c..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/GetActivityIconTask.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.app.AppGlobals;
-import android.content.pm.ActivityInfo;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Typeface;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.AsyncTask;
-import android.os.RemoteException;
-import android.util.Slog;
-import android.widget.ImageView;
-
-/**
- * Retrieves the icon for an activity and sets it as the Drawable on an ImageView. The ImageView
- * is hidden if the activity isn't recognized or if there is no icon.
- */
-class GetActivityIconTask extends AsyncTask<AppButtonData, Void, Drawable> {
- private final static String TAG = "GetActivityIconTask";
-
- private final PackageManager mPackageManager;
-
- // The ImageView that will receive the icon.
- private final ImageView mImageView;
-
- public GetActivityIconTask(PackageManager packageManager, ImageView imageView) {
- mPackageManager = packageManager;
- mImageView = imageView;
- }
-
- @Override
- protected Drawable doInBackground(AppButtonData... params) {
- if (params.length != 1) {
- throw new IllegalArgumentException("Expected one parameter");
- }
- AppButtonData buttonData = params[0];
- AppInfo appInfo = buttonData.appInfo;
- try {
- IPackageManager mPM = AppGlobals.getPackageManager();
- ActivityInfo ai = mPM.getActivityInfo(
- appInfo.getComponentName(),
- 0,
- appInfo.getUser().getIdentifier());
-
- if (ai == null) {
- Slog.w(TAG, "Icon not found for " + appInfo);
- return null;
- }
-
- Drawable unbadgedIcon = ai.loadIcon(mPackageManager);
- Drawable badgedIcon =
- mPackageManager.getUserBadgedIcon(unbadgedIcon, appInfo.getUser());
-
- if (NavigationBarApps.DEBUG) {
- // Draw pinned indicator and number of running tasks.
- Bitmap bitmap = Bitmap.createBitmap(
- badgedIcon.getIntrinsicWidth(),
- badgedIcon.getIntrinsicHeight(),
- Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- badgedIcon.setBounds(
- 0, 0, badgedIcon.getIntrinsicWidth(), badgedIcon.getIntrinsicHeight());
- badgedIcon.draw(canvas);
- Paint paint = new Paint();
- paint.setStyle(Paint.Style.FILL);
- if (buttonData.pinned) {
- paint.setColor(Color.WHITE);
- canvas.drawCircle(10, 10, 10, paint);
- }
- if (buttonData.tasks != null && buttonData.tasks.size() > 0) {
- paint.setColor(Color.BLACK);
- canvas.drawCircle(60, 30, 30, paint);
- paint.setColor(Color.WHITE);
- paint.setTextSize(50);
- paint.setTypeface(Typeface.create("sans-serif", Typeface.BOLD));
- canvas.drawText(Integer.toString(buttonData.tasks.size()), 50, 50, paint);
- }
- badgedIcon = new BitmapDrawable(null, bitmap);
- }
-
- return badgedIcon;
- } catch (RemoteException e) {
- Slog.w(TAG, "Icon not found for " + appInfo, e);
- return null;
- }
- }
-
- @Override
- protected void onPostExecute(Drawable icon) {
- mImageView.setImageDrawable(icon);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
index 26abc48..e7064e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java
@@ -43,7 +43,6 @@
private boolean mCollapseSnoozes;
private NotificationPanelView mPanel;
private ExpandableNotificationRow mPickedChild;
- private final int mNotificationsTopPadding;
public HeadsUpTouchHelper(HeadsUpManager headsUpManager,
NotificationStackScrollLayout stackScroller,
@@ -54,8 +53,6 @@
Context context = stackScroller.getContext();
final ViewConfiguration configuration = ViewConfiguration.get(context);
mTouchSlop = configuration.getScaledTouchSlop();
- mNotificationsTopPadding = context.getResources()
- .getDimensionPixelSize(R.dimen.notifications_top_padding);
}
public boolean isTrackingHeadsUp() {
@@ -80,10 +77,6 @@
mInitialTouchX = x;
setTrackingHeadsUp(false);
ExpandableView child = mStackScroller.getChildAtRawPosition(x, y);
- if (child == null && y < mNotificationsTopPadding) {
- // We should also allow drags from the margin above the heads up
- child = mStackScroller.getChildAtRawPosition(x, y + mNotificationsTopPadding);
- }
mTouchingHeadsUpView = false;
if (child instanceof ExpandableNotificationRow) {
mPickedChild = (ExpandableNotificationRow) child;
@@ -113,8 +106,7 @@
mHeadsUpManager.unpinAll();
mPanel.setPanelScrimMinFraction((float) expandedHeight
/ mPanel.getMaxPanelHeight());
- mPanel.startExpandMotion(x, y, true /* startTracking */, expandedHeight
- + mNotificationsTopPadding);
+ mPanel.startExpandMotion(x, y, true /* startTracking */, expandedHeight);
mPanel.clearNotificattonEffects();
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index 41adeb5..c220efe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -24,12 +24,11 @@
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.FlingAnimationUtils;
+import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.KeyguardAffordanceView;
/**
@@ -60,8 +59,6 @@
private KeyguardAffordanceView mLeftIcon;
private KeyguardAffordanceView mCenterIcon;
private KeyguardAffordanceView mRightIcon;
- private Interpolator mAppearInterpolator;
- private Interpolator mDisappearInterpolator;
private Animator mSwipeAnimator;
private FalsingManager mFalsingManager;
private int mMinBackgroundRadius;
@@ -107,10 +104,6 @@
mHintGrowAmount =
mContext.getResources().getDimensionPixelSize(R.dimen.hint_grow_amount_sideways);
mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.4f);
- mAppearInterpolator = AnimationUtils.loadInterpolator(mContext,
- android.R.interpolator.linear_out_slow_in);
- mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext,
- android.R.interpolator.fast_out_linear_in);
mFalsingManager = FalsingManager.getInstance(mContext);
}
@@ -272,7 +265,7 @@
}
}
});
- animator.setInterpolator(mAppearInterpolator);
+ animator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
animator.setDuration(HINT_PHASE1_DURATION);
animator.start();
mSwipeAnimator = animator;
@@ -292,7 +285,7 @@
onFinishedListener.run();
}
});
- animator.setInterpolator(mDisappearInterpolator);
+ animator.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
animator.setDuration(HINT_PHASE2_DURATION);
animator.setStartDelay(HINT_CIRCLE_OPEN_DURATION);
animator.start();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 14176a6..94d3829 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -58,6 +58,7 @@
import com.android.systemui.R;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.policy.AccessibilityController;
@@ -111,7 +112,6 @@
private AccessibilityController mAccessibilityController;
private PhoneStatusBar mPhoneStatusBar;
- private final Interpolator mLinearOutSlowInInterpolator;
private boolean mUserSetupComplete;
private boolean mPrewarmBound;
private Messenger mPrewarmMessenger;
@@ -146,8 +146,6 @@
public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
- mLinearOutSlowInInterpolator =
- AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
}
private AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() {
@@ -600,7 +598,7 @@
mIndicationText.setAlpha(0f);
mIndicationText.animate()
.alpha(1f)
- .setInterpolator(mLinearOutSlowInInterpolator)
+ .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
.setDuration(NotificationPanelView.DOZE_ANIMATION_DURATION);
}
@@ -610,7 +608,7 @@
element.animate()
.alpha(1f)
.translationY(0f)
- .setInterpolator(mLinearOutSlowInInterpolator)
+ .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
.setStartDelay(delay)
.setDuration(DOZE_ANIMATION_ELEMENT_DURATION);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index f41e47b..e67aa84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -23,14 +23,13 @@
import android.util.TypedValue;
import android.view.View;
import android.view.ViewTreeObserver;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.R;
+import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.policy.UserInfoController;
@@ -58,7 +57,6 @@
private KeyguardUserSwitcher mKeyguardUserSwitcher;
private int mSystemIconsSwitcherHiddenExpandedMargin;
- private Interpolator mFastOutSlowInInterpolator;
public KeyguardStatusBarView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -73,8 +71,6 @@
mBatteryLevel = (TextView) findViewById(R.id.battery_level);
mCarrierLabel = (TextView) findViewById(R.id.keyguard_carrier_text);
loadDimens();
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
- android.R.interpolator.fast_out_slow_in);
updateUserSwitcher();
}
@@ -199,7 +195,7 @@
.translationX(0)
.setDuration(400)
.setStartDelay(userSwitcherHiding ? 300 : 0)
- .setInterpolator(mFastOutSlowInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.start();
if (userSwitcherHiding) {
getOverlay().add(mMultiUserSwitch);
@@ -207,7 +203,7 @@
.alpha(0f)
.setDuration(300)
.setStartDelay(0)
- .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+ .setInterpolator(Interpolators.ALPHA_OUT)
.withEndAction(new Runnable() {
@Override
public void run() {
@@ -223,7 +219,7 @@
.alpha(1f)
.setDuration(300)
.setStartDelay(200)
- .setInterpolator(PhoneStatusBar.ALPHA_IN);
+ .setInterpolator(Interpolators.ALPHA_IN);
}
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
deleted file mode 100644
index ed6d940..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
+++ /dev/null
@@ -1,1123 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-
-import android.animation.LayoutTransition;
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.ActivityManager.RecentTaskInfo;
-import android.app.ActivityManagerNative;
-import android.app.ActivityOptions;
-import android.app.IActivityManager;
-import android.app.ITaskStackListener;
-import android.content.BroadcastReceiver;
-import android.content.ClipData;
-import android.content.ClipDescription;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.AttributeSet;
-import android.util.Slog;
-import android.view.DragEvent;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.PopupMenu;
-import android.widget.Toast;
-
-import com.android.internal.content.PackageMonitor;
-import com.android.systemui.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Container for application icons that appear in the navigation bar. Their appearance is similar
- * to the launcher hotseat. Clicking an icon launches or activates the associated activity. A long
- * click will trigger a drag to allow the icons to be reordered. As an icon is dragged the other
- * icons shift to make space for it to be dropped. These layout changes are animated.
- * Navigation bar contains both pinned and unpinned apps: pinned in the left part, unpinned in the
- * right part, with no separator in between.
- */
-class NavigationBarApps extends LinearLayout
- implements NavigationBarAppsModel.OnAppsChangedListener {
- public final static boolean DEBUG = false;
- private final static String TAG = "NavigationBarApps";
-
- /**
- * Intent extra to store user serial number.
- */
- static final String EXTRA_PROFILE = "profile";
-
- // There are separate NavigationBarApps view instances for landscape vs. portrait, but they
- // share the data model.
- private static NavigationBarAppsModel sAppsModel;
-
- private final PackageManager mPackageManager;
- private final UserManager mUserManager;
- private final LayoutInflater mLayoutInflater;
- private final AppPackageMonitor mAppPackageMonitor;
- private final WindowManager mWindowManager;
-
-
- // This view has two roles:
- // 1) If the drag started outside the pinned apps list, it is a placeholder icon with a null
- // tag.
- // 2) If the drag started inside the pinned apps list, it is the icon for the app being dragged
- // with the associated AppInfo tag.
- // The icon is set invisible for the duration of the drag, creating a visual space for a drop.
- // When the user is not dragging this member is null.
- private ImageView mDragView;
-
- private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- int currentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
- onUserSwitched(currentUserId);
- } else if (Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
- UserHandle removedProfile = intent.getParcelableExtra(Intent.EXTRA_USER);
- onManagedProfileRemoved(removedProfile);
- }
- }
- };
-
- // Layout params for the window that contains the anchor for the popup menus.
- // We need to create a window for a popup menu because the NavBar window is too narrow and can't
- // contain the menu.
- private final WindowManager.LayoutParams mPopupAnchorLayoutParams;
- // View that contains the anchor for popup menus. The view occupies the whole screen, and
- // has a child that will be moved to make the menu to appear where we need it.
- private final ViewGroup mPopupAnchor;
- private final PopupMenu mPopupMenu;
-
- /**
- * True if popup menu code is busy with a popup operation.
- * Attempting to show a popup menu or to add menu items while it's returning true will
- * corrupt/crash the app.
- */
- private boolean mIsPopupInUse = false;
- private final int [] mClickedIconLocation = new int[2];
-
- public NavigationBarApps(Context context, AttributeSet attrs) {
- super(context, attrs);
- if (sAppsModel == null) {
- sAppsModel = new NavigationBarAppsModel(context);
- }
- mPackageManager = context.getPackageManager();
- mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
- mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- mLayoutInflater = LayoutInflater.from(context);
- mAppPackageMonitor = new AppPackageMonitor();
-
- // Dragging an icon removes and adds back the dragged icon. Use the layout transitions to
- // trigger animation. By default all transitions animate, so turn off the unneeded ones.
- LayoutTransition transition = new LayoutTransition();
- // Don't trigger on disappear. Adding the view will trigger the layout animation.
- transition.disableTransitionType(LayoutTransition.DISAPPEARING);
- // Don't animate the dragged icon itself.
- transition.disableTransitionType(LayoutTransition.APPEARING);
- // When an icon is dragged off the shelf, start sliding the other icons over immediately
- // to match the parent view's animation.
- transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
- transition.setStagger(LayoutTransition.CHANGE_DISAPPEARING, 0);
- setLayoutTransition(transition);
-
- TaskStackListener taskStackListener = new TaskStackListener();
- IActivityManager iam = ActivityManagerNative.getDefault();
- try {
- iam.registerTaskStackListener(taskStackListener);
- } catch (RemoteException e) {
- Slog.e(TAG, "registerTaskStackListener failed", e);
- }
-
- mPopupAnchorLayoutParams =
- new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
- WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY,
- WindowManager.LayoutParams.FLAG_FULLSCREEN
- | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
- | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
- PixelFormat.TRANSLUCENT);
- mPopupAnchorLayoutParams.setTitle("ShelfMenuAnchor");
-
- mPopupAnchor = (ViewGroup) mLayoutInflater.inflate(R.layout.shelf_menu_anchor, null);
-
- ImageView anchorButton =
- (ImageView) mPopupAnchor.findViewById(R.id.shelf_menu_anchor_anchor);
- mPopupMenu = new PopupMenu(context, anchorButton);
- }
-
- // Monitor that catches events like "app uninstalled".
- private class AppPackageMonitor extends PackageMonitor {
- @Override
- public void onPackageRemoved(String packageName, int uid) {
- postUnpinIfUnlauncheable(packageName, new UserHandle(getChangingUserId()));
- super.onPackageRemoved(packageName, uid);
- }
-
- @Override
- public void onPackageModified(String packageName) {
- postUnpinIfUnlauncheable(packageName, new UserHandle(getChangingUserId()));
- super.onPackageModified(packageName);
- }
-
- @Override
- public void onPackagesAvailable(String[] packages) {
- if (isReplacing()) {
- UserHandle user = new UserHandle(getChangingUserId());
-
- for (String packageName : packages) {
- postUnpinIfUnlauncheable(packageName, user);
- }
- }
- super.onPackagesAvailable(packages);
- }
-
- @Override
- public void onPackagesUnavailable(String[] packages) {
- if (!isReplacing()) {
- UserHandle user = new UserHandle(getChangingUserId());
-
- for (String packageName : packages) {
- postUnpinIfUnlauncheable(packageName, user);
- }
- }
- super.onPackagesUnavailable(packages);
- }
- }
-
- private void postUnpinIfUnlauncheable(final String packageName, final UserHandle user) {
- // This method doesn't necessarily get called in the main thread. Redirect the call into
- // the main thread.
- post(new Runnable() {
- @Override
- public void run() {
- if (!isAttachedToWindow()) return;
- unpinIfUnlauncheable(packageName, user);
- }
- });
- }
-
- private void unpinIfUnlauncheable(String packageName, UserHandle user) {
- // Unpin icons for all apps that match a package that perhaps became unlauncheable.
- boolean appsWereUnpinned = false;
- for(int i = getChildCount() - 1; i >= 0; --i) {
- View child = getChildAt(i);
- AppButtonData appButtonData = (AppButtonData)child.getTag();
- if (appButtonData == null) continue; // Skip the drag placeholder.
-
- if (!appButtonData.pinned) continue;
-
- AppInfo appInfo = appButtonData.appInfo;
- if (!appInfo.getUser().equals(user)) continue;
-
- ComponentName appComponentName = appInfo.getComponentName();
- if (!appComponentName.getPackageName().equals(packageName)) continue;
-
- if (sAppsModel.resolveApp(appInfo) != null) {
- continue;
- }
-
- appButtonData.pinned = false;
- appsWereUnpinned = true;
-
- if (appButtonData.isEmpty()) {
- removeViewAt(i);
- }
- }
- if (appsWereUnpinned) {
- savePinnedApps();
- }
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- // When an icon is dragged out of the pinned area this view's width changes, which causes
- // the parent container's layout to change and the divider and recents icons to shift left.
- // Animate the parent's CHANGING transition.
- ViewGroup parent = (ViewGroup) getParent();
- LayoutTransition transition = new LayoutTransition();
- transition.disableTransitionType(LayoutTransition.APPEARING);
- transition.disableTransitionType(LayoutTransition.DISAPPEARING);
- transition.disableTransitionType(LayoutTransition.CHANGE_APPEARING);
- transition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
- transition.enableTransitionType(LayoutTransition.CHANGING);
- parent.setLayoutTransition(transition);
-
- sAppsModel.setCurrentUser(ActivityManager.getCurrentUser());
- recreatePinnedAppButtons();
- updateRecentApps();
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_SWITCHED);
- filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
- mContext.registerReceiver(mBroadcastReceiver, filter);
-
- mAppPackageMonitor.register(mContext, null, UserHandle.ALL, true);
- sAppsModel.addOnAppsChangedListener(this);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mContext.unregisterReceiver(mBroadcastReceiver);
- mAppPackageMonitor.unregister();
- sAppsModel.removeOnAppsChangedListener(this);
- }
-
- @Override
- protected void onVisibilityChanged(View changedView, int visibility) {
- super.onVisibilityChanged(changedView, visibility);
- if (mIsPopupInUse && !isShown()) {
- // Hide the popup if current view became invisible.
- shutdownPopupMenu();
- }
- }
-
- private void addAppButton(AppButtonData appButtonData) {
- ImageView button = createAppButton();
- updateApp(button, appButtonData);
- addView(button);
- }
-
- private List<AppInfo> getPinnedApps() {
- List<AppInfo> apps = new ArrayList<AppInfo>();
- int childCount = getChildCount();
- for (int i = 0; i != childCount; ++i) {
- View child = getChildAt(i);
- AppButtonData appButtonData = (AppButtonData)child.getTag();
- if (appButtonData == null) continue; // Skip the drag placeholder.
- if(!appButtonData.pinned) continue;
- apps.add(appButtonData.appInfo);
- }
- return apps;
- }
-
- /**
- * Creates an ImageView icon for each pinned app. Removes any existing icons. May be called
- * to synchronize the current view with the shared data mode.
- */
- private void recreatePinnedAppButtons() {
- // Remove any existing icon buttons.
- removeAllViews();
-
- List<AppInfo> apps = sAppsModel.getApps();
- int appCount = apps.size();
- for (int i = 0; i < appCount; i++) {
- AppInfo app = apps.get(i);
- addAppButton(new AppButtonData(app, true /* pinned */));
- }
- }
-
- /**
- * Saves pinned apps stored in app icons into the data model.
- */
- private void savePinnedApps() {
- sAppsModel.setApps(getPinnedApps());
- }
-
- /**
- * Creates a new ImageView for an app, inflated from R.layout.navigation_bar_app_item.
- */
- private ImageView createAppButton() {
- ImageView button = (ImageView) mLayoutInflater.inflate(
- R.layout.navigation_bar_app_item, this, false /* attachToRoot */);
- button.setOnHoverListener(new AppHoverListener());
- button.setOnClickListener(new AppClickListener());
- button.setOnContextClickListener(new AppContextClickListener());
- // TODO: Ripple effect. Use either KeyButtonRipple or the default ripple background.
- button.setOnLongClickListener(new AppLongClickListener());
- button.setOnDragListener(new AppIconDragListener());
- return button;
- }
-
- private class AppLongClickListener implements View.OnLongClickListener {
- @Override
- public boolean onLongClick(View v) {
- mDragView = (ImageView) v;
- AppButtonData appButtonData = (AppButtonData) v.getTag();
- startAppDrag(mDragView, appButtonData.appInfo);
- return true;
- }
- }
-
- /**
- * Returns the human-readable name for an activity's package or null.
- * TODO: Cache the labels, perhaps in an LruCache.
- */
- @Nullable
- private CharSequence getAppLabel(AppInfo appInfo) {
- NavigationBarAppsModel.ResolvedApp resolvedApp = sAppsModel.resolveApp(appInfo);
- if (resolvedApp == null) return null;
-
- CharSequence unbadgedLabel = resolvedApp.ri.loadLabel(mPackageManager);
- return mUserManager.getBadgedLabelForUser(unbadgedLabel, appInfo.getUser());
- }
-
- /** Helper function to start dragging an app icon (either pinned or recent). */
- static void startAppDrag(ImageView icon, AppInfo appInfo) {
- // The drag data is an Intent to launch the activity.
- Intent mainIntent = Intent.makeMainActivity(appInfo.getComponentName());
- UserManager userManager =
- (UserManager) icon.getContext().getSystemService(Context.USER_SERVICE);
- long userSerialNumber = userManager.getSerialNumberForUser(appInfo.getUser());
- mainIntent.putExtra(EXTRA_PROFILE, userSerialNumber);
- ClipData dragData = ClipData.newIntent("", mainIntent);
- // Use the ImageView to create the shadow.
- View.DragShadowBuilder shadow = new AppIconDragShadowBuilder(icon);
- // Use a global drag because the icon might be dragged into the launcher.
- icon.startDrag(dragData, shadow, null /* myLocalState */, View.DRAG_FLAG_GLOBAL);
- }
-
- @Override
- public boolean dispatchDragEvent(DragEvent event) {
- // ACTION_DRAG_ENTERED is handled by each individual app icon drag listener.
- boolean childHandled = super.dispatchDragEvent(event);
-
- // Other drag types are handled once per drag by this view. This is handled explicitly
- // because attaching a DragListener to this ViewGroup does not work -- the DragListener in
- // the children consumes the drag events.
- boolean handled = false;
- switch (event.getAction()) {
- case DragEvent.ACTION_DRAG_STARTED:
- handled = onDragStarted(event);
- break;
- case DragEvent.ACTION_DRAG_ENDED:
- handled = onDragEnded();
- break;
- case DragEvent.ACTION_DROP:
- handled = onDrop(event);
- break;
- case DragEvent.ACTION_DRAG_EXITED:
- handled = onDragExited();
- break;
- }
-
- return handled || childHandled;
- }
-
- /** Returns true if a drag should be handled. */
- private static boolean canAcceptDrag(DragEvent event) {
- // Poorly behaved apps might not provide a clip description.
- if (event.getClipDescription() == null) {
- return false;
- }
- // The event must contain an intent.
- return event.getClipDescription().hasMimeType(ClipDescription.MIMETYPE_TEXT_INTENT);
- }
-
- /**
- * Sets up for a drag. Runs once per drag operation. Returns true if the data represents
- * an app shortcut and will be accepted for a drop.
- */
- private boolean onDragStarted(DragEvent event) {
- if (DEBUG) Slog.d(TAG, "onDragStarted");
-
- // Ensure that an app shortcut is being dragged.
- if (!canAcceptDrag(event)) {
- return false;
- }
-
- // If there are no pinned apps this view will be collapsed, but the user still needs some
- // empty space to use as a drag target.
- if (getChildCount() == 0) {
- mDragView = createPlaceholderDragView(0);
- }
-
- // If this is an existing icon being reordered, hide the app icon. The drag shadow will
- // continue to draw.
- if (mDragView != null) {
- mDragView.setVisibility(View.INVISIBLE);
- }
-
- // Listen for the drag end event.
- return true;
- }
-
- /**
- * Creates a blank icon-sized View to create an empty space during a drag.
- */
- private ImageView createPlaceholderDragView(int index) {
- ImageView button = createAppButton();
- addView(button, index);
- return button;
- }
-
- /**
- * Returns initial index for a new app that doesn't exist in Shelf.
- * Such apps get created by dragging them into Shelf from other apps or by dragging from Shelf
- * and then back, or by removing from shelf as an intermediate step of pinning an app via menu.
- * @param indexHint Initial proposed position for the item.
- * @param isAppPinned True if the app being dragged is pinned.
- */
- int getNewAppIndex(int indexHint, boolean isAppPinned) {
- int i;
- if (isAppPinned) {
- // For a pinned app, find the rightmost position to the left of the target that has a
- // pinned app. We'll insert to the right of that position.
- for (i = indexHint; i > 0; --i) {
- View v = getChildAt(i - 1);
- AppButtonData targetButtonData = (AppButtonData) v.getTag();
- if (targetButtonData.pinned) break;
- }
- } else {
- // For an unpinned app, find the leftmost position to the right of the target that has
- // an unpinned app. We'll insert to the left of that position.
- int childCount = getChildCount();
- for (i = indexHint; i < childCount; ++i) {
- View v = getChildAt(i);
- AppButtonData targetButtonData = (AppButtonData) v.getTag();
- if (!targetButtonData.pinned) break;
- }
- }
- return i;
- }
-
- /**
- * Handles a drag entering an existing icon. Not implemented in the drag listener because it
- * needs to use LinearLayout/ViewGroup methods.
- */
- private void onDragEnteredIcon(View target) {
- if (DEBUG) Slog.d(TAG, "onDragEntered " + indexOfChild(target));
-
- int targetIndex = indexOfChild(target);
-
- // If the drag didn't start from an existing shelf icon, add an invisible placeholder to
- // create empty space for the user to drag into.
- if (mDragView == null) {
- mDragView = createPlaceholderDragView(getNewAppIndex(targetIndex, true));
- return;
- }
-
- // If the user is dragging on top of the original icon location, do nothing.
- if (target == mDragView) {
- return;
- }
-
- // "Move" the dragged app by removing it and adding it back at the target location.
- AppButtonData targetButtonData = (AppButtonData) target.getTag();
- int dragViewIndex = indexOfChild(mDragView);
- AppButtonData dragViewButtonData = (AppButtonData) mDragView.getTag();
- // Calculating whether the dragged app is pinned. If the app came from outside if the shelf,
- // in which case dragViewButtonData == null, it's a new app that we'll pin. Otherwise, the
- // button data is defined, and we look whether that existing app is pinned.
- boolean isAppPinned = dragViewButtonData == null || dragViewButtonData.pinned;
-
- if (dragViewIndex == -1) {
- // Drag view exists, but is not a child, which means that the drag has started at or
- // already visited shelf, then left it, and now is entering it again.
- targetIndex = getNewAppIndex(targetIndex, isAppPinned);
- } else if (dragViewIndex < targetIndex) {
- // The dragged app is currently at the left of the view where the drag is.
- // We shouldn't allow moving a pinned app to the right of the unpinned app.
- if (!targetButtonData.pinned && isAppPinned) return;
- } else {
- // The dragged app is currently at the right of the view where the drag is.
- // We shouldn't allow moving a unpinned app to the left of the pinned app.
- if (targetButtonData.pinned && !isAppPinned) return;
- }
-
- // This works, but is subtle:
- // * If dragViewIndex > targetIndex then the dragged app is moving from right to left and
- // the dragged app will be added in front of the target.
- // * If dragViewIndex < targetIndex then the dragged app is moving from left to right.
- // Removing the drag view will shift the later views one position to the left. Adding
- // the view at targetIndex will therefore place the app *after* the target.
- removeView(mDragView);
- addView(mDragView, targetIndex);
- }
-
- private boolean onDrop(DragEvent event) {
- if (DEBUG) Slog.d(TAG, "onDrop");
-
- // An earlier drag event might have canceled the drag. If so, there is nothing to do.
- if (mDragView == null) {
- return true;
- }
-
- boolean dragResult = true;
- AppInfo appInfo = getAppFromDragEvent(event);
- if (appInfo == null) {
- // This wasn't a valid drop. Clean up the placeholder.
- removePlaceholderDragViewIfNeeded();
- dragResult = false;
- } else if (mDragView.getTag() == null) {
- // This is a drag that adds a new app. Convert the placeholder to a real icon.
- updateApp(mDragView, new AppButtonData(appInfo, true /* pinned */));
- }
- endDrag();
- return dragResult;
- }
-
- /** Cleans up at the end of a drag. */
- private void endDrag() {
- // An earlier drag event might have canceled the drag. If so, there is nothing to do.
- if (mDragView == null) return;
-
- mDragView.setVisibility(View.VISIBLE);
- mDragView = null;
- savePinnedApps();
- // Add recent tasks to the info of the potentially added app.
- updateRecentApps();
- }
-
- /** Returns an app info from a DragEvent, or null if the data wasn't valid. */
- private AppInfo getAppFromDragEvent(DragEvent event) {
- ClipData data = event.getClipData();
- if (data == null) {
- return null;
- }
- if (data.getItemCount() != 1) {
- return null;
- }
- ClipData.Item item = data.getItemAt(0);
- if (item == null) {
- return null;
- }
- Intent intent = item.getIntent();
- if (intent == null) {
- return null;
- }
- long userSerialNumber = intent.getLongExtra(EXTRA_PROFILE, -1);
- if (userSerialNumber == -1) {
- return null;
- }
- UserHandle appUser = mUserManager.getUserForSerialNumber(userSerialNumber);
- if (appUser == null) {
- return null;
- }
- ComponentName componentName = intent.getComponent();
- if (componentName == null) {
- return null;
- }
- AppInfo appInfo = new AppInfo(componentName, appUser);
- if (sAppsModel.resolveApp(appInfo) == null) {
- return null;
- }
- return appInfo;
- }
-
- /** Updates the app at a given view index. */
- private void updateApp(ImageView button, AppButtonData appButtonData) {
- CharSequence appLabel = getAppLabel(appButtonData.appInfo);
- button.setContentDescription(appLabel);
-
- button.setTag(appButtonData);
- new GetActivityIconTask(mPackageManager, button).execute(appButtonData);
- }
-
- /** Removes the empty placeholder view. */
- private void removePlaceholderDragViewIfNeeded() {
- // If the drag has ended already there is nothing to do.
- if (mDragView == null) {
- return;
- }
- removeView(mDragView);
- }
-
- /** Cleans up at the end of the drag. */
- private boolean onDragEnded() {
- if (DEBUG) Slog.d(TAG, "onDragEnded");
- // If the icon wasn't already dropped into the app list then remove the placeholder.
- removePlaceholderDragViewIfNeeded();
- endDrag();
- return true;
- }
-
- /** Handles the dragged icon exiting the bounds of this view during the drag. */
- private boolean onDragExited() {
- if (DEBUG) Slog.d(TAG, "onDragExited");
- // Remove the placeholder. It will be added again if the user drags the icon back over
- // the shelf.
- removePlaceholderDragViewIfNeeded();
- return true;
- }
-
- /** Drag listener for individual app icons. */
- private class AppIconDragListener implements View.OnDragListener {
- @Override
- public boolean onDrag(View v, DragEvent event) {
- switch (event.getAction()) {
- case DragEvent.ACTION_DRAG_STARTED: {
- // Every button listens for drag events in order to detect enter/exit.
- return canAcceptDrag(event);
- }
- case DragEvent.ACTION_DRAG_ENTERED: {
- // Forward to NavigationBarApps.
- onDragEnteredIcon(v);
- return false;
- }
- }
- return false;
- }
- }
-
- /**
- * Brings the menu popup to closed state.
- * Can be called at any stage of the asynchronous process of showing a menu.
- */
- private void shutdownPopupMenu() {
- mWindowManager.removeView(mPopupAnchor);
- mPopupMenu.dismiss();
- }
-
- /**
- * Shows already prepopulated popup menu using appIcon for anchor location.
- */
- private void showPopupMenu(ImageView appIcon) {
- // Movable view inside the popup anchor view. It serves as the actual anchor for the
- // menu.
- final ImageView anchorButton =
- (ImageView) mPopupAnchor.findViewById(R.id.shelf_menu_anchor_anchor);
- // Set same drawable as for the clicked button to have same size.
- anchorButton.setImageDrawable(appIcon.getDrawable());
-
- // Move the anchor button to the position of the app button.
- appIcon.getLocationOnScreen(mClickedIconLocation);
- anchorButton.setTranslationX(mClickedIconLocation[0]);
- anchorButton.setTranslationY(mClickedIconLocation[1]);
-
- final OnAttachStateChangeListener onAttachStateChangeListener =
- new OnAttachStateChangeListener() {
- @Override
- public void onViewAttachedToWindow(View v) {
- mPopupMenu.show();
- }
-
- @Override
- public void onViewDetachedFromWindow(View v) {}
- };
- anchorButton.addOnAttachStateChangeListener(onAttachStateChangeListener);
-
- mPopupMenu.setOnDismissListener(new PopupMenu.OnDismissListener() {
- @Override
- public void onDismiss(PopupMenu menu) {
- // FYU: thorough testing for closing menu either by the user or via
- // shutdownPopupMenu() called at various moments of the menu creation, revealed that
- // 'onDismiss' is guaranteed to be called after each invocation of showPopupMenu.
- mWindowManager.removeView(mPopupAnchor);
- anchorButton.removeOnAttachStateChangeListener(onAttachStateChangeListener);
- mPopupMenu.setOnDismissListener(null);
- mPopupMenu.getMenu().clear();
- mIsPopupInUse = false;
- }
- });
-
- mWindowManager.addView(mPopupAnchor, mPopupAnchorLayoutParams);
- mIsPopupInUse = true;
- }
-
- private void activateTask(int taskPersistentId) {
- // Launch or bring the activity to front.
- final IActivityManager iAm = ActivityManagerNative.getDefault();
- try {
- iAm.startActivityFromRecents(taskPersistentId, null /* options */);
- } catch (RemoteException e) {
- Slog.e(TAG, "Exception when activating a recent task", e);
- } catch (IllegalArgumentException e) {
- Slog.e(TAG, "Exception when activating a recent task", e);
- }
- }
-
- /**
- * Adds to the popup menu items for activating each of tasks in the specified list.
- */
- private void populateLaunchMenu(AppButtonData appButtonData) {
- Menu menu = mPopupMenu.getMenu();
- int taskCount = appButtonData.getTaskCount();
- for (int i = 0; i < taskCount; ++i) {
- final RecentTaskInfo taskInfo = appButtonData.tasks.get(i);
- MenuItem item = menu.add(getActivityForTask(taskInfo).flattenToShortString());
- item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- activateTask(taskInfo.persistentId);
- return true;
- }
- });
- }
- }
-
- /**
- * Shows a task selection menu for clicked or hovered-over apps that have more than 1 running
- * tasks.
- */
- void maybeShowLaunchMenu(ImageView appIcon) {
- if (mIsPopupInUse) return;
- AppButtonData appButtonData = (AppButtonData) appIcon.getTag();
- if (appButtonData.getTaskCount() <= 1) return;
-
- populateLaunchMenu(appButtonData);
- showPopupMenu(appIcon);
- }
-
- /**
- * A listener for hovering over an app icon.
- */
- private class AppHoverListener implements View.OnHoverListener {
- private final long DELAY_MILLIS = 1000;
- private Runnable mShowMenuCallback;
-
- @Override
- public boolean onHover(final View v, MotionEvent event) {
- if (mShowMenuCallback == null) {
- mShowMenuCallback = new Runnable() {
- @Override
- public void run() {
- maybeShowLaunchMenu((ImageView) v);
- }
- };
- }
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_HOVER_ENTER:
- postDelayed(mShowMenuCallback, DELAY_MILLIS);
- break;
- case MotionEvent.ACTION_HOVER_EXIT:
- removeCallbacks(mShowMenuCallback);
- break;
- }
- return false;
- }
- }
-
- /**
- * A click listener that launches an activity.
- */
- private class AppClickListener implements View.OnClickListener {
- private void launchApp(AppInfo appInfo, View anchor) {
- NavigationBarAppsModel.ResolvedApp resolvedApp = sAppsModel.resolveApp(appInfo);
- if (resolvedApp == null) {
- Toast.makeText(
- getContext(), R.string.activity_not_found, Toast.LENGTH_SHORT).show();
- return;
- }
-
- Intent launchIntent = resolvedApp.launchIntent;
-
- // Play a scale-up animation while launching the activity.
- // TODO: Consider playing a different animation, or no animation, if the activity is
- // already open in a visible window. In that case we should move the task to front
- // with minimal animation, perhaps using ActivityManager.moveTaskToFront().
- Rect sourceBounds = new Rect();
- anchor.getBoundsOnScreen(sourceBounds);
- ActivityOptions opts =
- ActivityOptions.makeScaleUpAnimation(
- anchor, 0, 0, anchor.getWidth(), anchor.getHeight());
- Bundle optsBundle = opts.toBundle();
- launchIntent.setSourceBounds(sourceBounds);
-
- mContext.startActivityAsUser(launchIntent, optsBundle, appInfo.getUser());
- }
-
- @Override
- public void onClick(View v) {
- AppButtonData appButtonData = (AppButtonData) v.getTag();
-
- if (appButtonData.getTaskCount() == 0) {
- launchApp(appButtonData.appInfo, v);
- } else {
- // Activate latest task.
- activateTask(appButtonData.tasks.get(0).persistentId);
-
- maybeShowLaunchMenu((ImageView) v);
- }
- }
- }
-
- /**
- * Context click listener that shows app's context menu.
- */
- private class AppContextClickListener implements View.OnContextClickListener {
- void updateState(ImageView appIcon) {
- savePinnedApps();
- if (DEBUG) {
- AppButtonData appButtonData = (AppButtonData) appIcon.getTag();
- new GetActivityIconTask(mPackageManager, appIcon).execute(appButtonData);
- }
- }
-
- /**
- * Adds to the popup menu items for pinning and unpinning the app in the shelf.
- */
- void populateContextMenu(final ImageView appIcon) {
- final AppButtonData appButtonData = (AppButtonData) appIcon.getTag();
- Menu menu = mPopupMenu.getMenu();
- if (appButtonData.pinned) {
- menu.add("Unpin").
- setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- appButtonData.pinned = false;
- removeView(appIcon);
- if (!appButtonData.isEmpty()) {
- // If the app has running tasks, re-add it to the end of shelf
- // after unpinning.
- addView(appIcon);
- }
- updateState(appIcon);
- return true;
- }
- });
- } else {
- menu.add("Pin").setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- appButtonData.pinned = true;
- removeView(appIcon);
- // Re-add the pinned icon to the end of the pinned list.
- addView(appIcon, getNewAppIndex(getChildCount(), true));
- updateState(appIcon);
- return true;
- }
- });
- }
- }
-
- @Override
- public boolean onContextClick(View v) {
- if (mIsPopupInUse) return true;
- ImageView appIcon = (ImageView) v;
- populateContextMenu(appIcon);
- showPopupMenu(appIcon);
- return true;
- }
- }
-
- private void onUserSwitched(int currentUserId) {
- sAppsModel.setCurrentUser(currentUserId);
- recreatePinnedAppButtons();
- }
-
- private void onManagedProfileRemoved(UserHandle removedProfile) {
- // Unpin apps from the removed profile.
- boolean itemsWereUnpinned = false;
- for(int i = getChildCount() - 1; i >= 0; --i) {
- View view = getChildAt(i);
- AppButtonData appButtonData = (AppButtonData)view.getTag();
- if (appButtonData == null) return; // Skip the drag placeholder.
- if (!appButtonData.pinned) continue;
- if (!appButtonData.appInfo.getUser().equals(removedProfile)) continue;
-
- appButtonData.pinned = false;
- itemsWereUnpinned = true;
- if (appButtonData.isEmpty()) {
- removeViewAt(i);
- }
- }
- if (itemsWereUnpinned) {
- savePinnedApps();
- }
- }
-
- /**
- * Returns app data for a button that matches the provided app info, if it exists, or null
- * otherwise.
- */
- private AppButtonData findAppButtonData(AppInfo appInfo) {
- int size = getChildCount();
- for (int i = 0; i < size; ++i) {
- View view = getChildAt(i);
- AppButtonData appButtonData = (AppButtonData)view.getTag();
- if (appButtonData == null) continue; // Skip the drag placeholder.
- if (appButtonData.appInfo.equals(appInfo)) {
- return appButtonData;
- }
- }
- return null;
- }
-
- private void updateTasks(List<RecentTaskInfo> tasks) {
- // Remove tasks from all app buttons.
- for (int i = getChildCount() - 1; i >= 0; --i) {
- View view = getChildAt(i);
- AppButtonData appButtonData = (AppButtonData)view.getTag();
- if (appButtonData == null) return; // Skip the drag placeholder.
- appButtonData.clearTasks();
- }
-
- // Re-add tasks to app buttons, adding new buttons if needed.
- int size = tasks.size();
- for (int i = 0; i != size; ++i) {
- RecentTaskInfo task = tasks.get(i);
- AppInfo taskAppInfo = taskToAppInfo(task);
- if (taskAppInfo == null) continue;
- AppButtonData appButtonData = findAppButtonData(taskAppInfo);
- if (appButtonData == null) {
- appButtonData = new AppButtonData(taskAppInfo, false);
- addAppButton(appButtonData);
- }
- appButtonData.addTask(task);
- }
-
- // Remove unpinned apps that now have no tasks.
- for (int i = getChildCount() - 1; i >= 0; --i) {
- View view = getChildAt(i);
- AppButtonData appButtonData = (AppButtonData)view.getTag();
- if (appButtonData == null) return; // Skip the drag placeholder.
- if (appButtonData.isEmpty()) {
- removeViewAt(i);
- }
- }
-
- if (DEBUG) {
- for (int i = getChildCount() - 1; i >= 0; --i) {
- View view = getChildAt(i);
- AppButtonData appButtonData = (AppButtonData)view.getTag();
- if (appButtonData == null) return; // Skip the drag placeholder.
- new GetActivityIconTask(mPackageManager, (ImageView )view).execute(appButtonData);
-
- }
- }
- }
-
- private void updateRecentApps() {
- ActivityManager activityManager =
- (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
- // TODO: Should this be getRunningTasks?
- List<RecentTaskInfo> recentTasks = activityManager.getRecentTasksForUser(
- ActivityManager.getMaxAppRecentsLimitStatic(),
- ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS |
- ActivityManager.RECENT_IGNORE_UNAVAILABLE |
- ActivityManager.RECENT_INCLUDE_PROFILES,
- UserHandle.USER_CURRENT);
- if (DEBUG) Slog.d(TAG, "Got recents " + recentTasks.size());
- updateTasks(recentTasks);
- }
-
- private static ComponentName getActivityForTask(RecentTaskInfo task) {
- // If the task was started from an alias, return the actual activity component that was
- // initially started.
- if (task.origActivity != null) {
- return task.origActivity;
- }
- // Prefer the first activity of the task.
- if (task.baseActivity != null) {
- return task.baseActivity;
- }
- // Then goes the activity that started the task.
- if (task.realActivity != null) {
- return task.realActivity;
- }
- // This should not happen, but fall back to the base intent's activity component name.
- return task.baseIntent.getComponent();
- }
-
- private ComponentName getLaunchComponentForPackage(String packageName, int userId) {
- // This code is based on ApplicationPackageManager.getLaunchIntentForPackage.
- PackageManager packageManager = mContext.getPackageManager();
-
- // First see if the package has an INFO activity; the existence of
- // such an activity is implied to be the desired front-door for the
- // overall package (such as if it has multiple launcher entries).
- Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
- intentToResolve.addCategory(Intent.CATEGORY_INFO);
- intentToResolve.setPackage(packageName);
- List<ResolveInfo> ris = packageManager.queryIntentActivitiesAsUser(
- intentToResolve, 0, userId);
-
- // Otherwise, try to find a main launcher activity.
- if (ris == null || ris.size() <= 0) {
- // reuse the intent instance
- intentToResolve.removeCategory(Intent.CATEGORY_INFO);
- intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
- intentToResolve.setPackage(packageName);
- ris = packageManager.queryIntentActivitiesAsUser(intentToResolve, 0, userId);
- }
- if (ris == null || ris.size() <= 0) {
- Slog.i(TAG, "Failed to build intent for " + packageName);
- return null;
- }
- return new ComponentName(ris.get(0).activityInfo.packageName,
- ris.get(0).activityInfo.name);
- }
-
- private AppInfo taskToAppInfo(RecentTaskInfo task) {
- ComponentName componentName = getActivityForTask(task);
- UserHandle taskUser = new UserHandle(task.userId);
- AppInfo appInfo = new AppInfo(componentName, taskUser);
-
- if (sAppsModel.resolveApp(appInfo) == null) {
- // If task's activity is not launcheable, fall back to a launch component of the
- // task's package.
- ComponentName component = getLaunchComponentForPackage(
- componentName.getPackageName(), task.userId);
-
- if (component == null) {
- return null;
- }
-
- appInfo = new AppInfo(component, taskUser);
- }
-
- return appInfo;
- }
-
- /**
- * A listener that updates the app buttons whenever the recents task stack changes.
- */
- private class TaskStackListener extends ITaskStackListener.Stub {
- @Override
- public void onTaskStackChanged() throws RemoteException {
- // Post the message back to the UI thread.
- post(new Runnable() {
- @Override
- public void run() {
- if (isAttachedToWindow()) {
- updateRecentApps();
- }
- }
- });
- }
-
- @Override
- public void onActivityPinned() {
- }
-
- @Override
- public void onPinnedActivityRestartAttempt() {
- }
- }
-
- @Override
- public void onPinnedAppsChanged() {
- if (getPinnedApps().equals(sAppsModel.getApps())) return;
- recreatePinnedAppButtons();
- updateRecentApps();
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java
deleted file mode 100644
index 76a9798..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.app.AppGlobals;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.ActivityInfo;
-import android.content.pm.IPackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.UserInfo;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Slog;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Data model and controller for app icons appearing in the navigation bar. The data is stored on
- * disk in SharedPreferences. Each icon has a separate pref entry consisting of a flattened
- * ComponentName.
- */
-class NavigationBarAppsModel {
- public interface OnAppsChangedListener {
- void onPinnedAppsChanged();
- }
-
- public class ResolvedApp {
- Intent launchIntent;
- ResolveInfo ri;
- }
-
- private final static String TAG = "NavigationBarAppsModel";
-
- // Default number of apps to load initially.
- private final static int NUM_INITIAL_APPS = 4;
-
- // Preferences file name.
- private final static String SHARED_PREFERENCES_NAME = "com.android.systemui.navbarapps";
-
- // Preference name for the version of the other preferences.
- private final static String VERSION_PREF = "version";
-
- // Current version number for preferences.
- private final static int CURRENT_VERSION = 3;
-
- // Preference name for the number of app icons.
- private final static String APP_COUNT_PREF = "app_count";
-
- // Preference name prefix for each app's info. The actual pref has an integer appended to it.
- private final static String APP_PREF_PREFIX = "app_";
-
- // User serial number prefix for each app's info. The actual pref has an integer appended to it.
- private final static String APP_USER_PREFIX = "app_user_";
-
- // Character separating current user serial number from the user-specific part of a pref.
- // Example "22|app_user_2" - when logged as user with serial 22, we'll use this pref for the
- // user serial of the third app of the logged-in user.
- private final static char USER_SEPARATOR = '|';
-
- private final Context mContext;
- private final UserManager mUserManager;
- private final SharedPreferences mPrefs;
-
- // Apps are represented as an ordered list of app infos.
- private List<AppInfo> mApps = new ArrayList<AppInfo>();
-
- private List<OnAppsChangedListener> mOnAppsChangedListeners =
- new ArrayList<OnAppsChangedListener>();
-
- // Id of the current user.
- private int mCurrentUserId = -1;
-
- // Serial number of the current user.
- private long mCurrentUserSerialNumber = -1;
-
- public NavigationBarAppsModel(Context context) {
- mContext = context;
- mPrefs = mContext.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
- mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
-
- int version = mPrefs.getInt(VERSION_PREF, -1);
- if (version != CURRENT_VERSION) {
- // Since the data format changed, clean everything.
- SharedPreferences.Editor edit = mPrefs.edit();
- edit.clear();
- edit.putInt(VERSION_PREF, CURRENT_VERSION);
- edit.apply();
- }
- }
-
- @VisibleForTesting
- protected IPackageManager getPackageManager() {
- return AppGlobals.getPackageManager();
- }
-
- // Returns a resolved app info for a given app info, or null if the app info is unlauncheable.
- public ResolvedApp resolveApp(AppInfo appInfo) {
- ComponentName component = appInfo.getComponentName();
- int appUserId = appInfo.getUser().getIdentifier();
-
- if (mCurrentUserId != appUserId) {
- // Check if app user is a profile of current user and the app user is enabled.
- UserInfo appUserInfo = mUserManager.getUserInfo(appUserId);
- UserInfo currentUserInfo = mUserManager.getUserInfo(mCurrentUserId);
- if (appUserInfo == null || currentUserInfo == null
- || appUserInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID
- || appUserInfo.profileGroupId != currentUserInfo.profileGroupId
- || !appUserInfo.isEnabled()) {
- Slog.e(TAG, "User " + appUserId +
- " is is not a profile of the current user, or is disabled.");
- return null;
- }
- }
-
- // This code is based on LauncherAppsService.startActivityAsUser code.
- Intent launchIntent = new Intent(Intent.ACTION_MAIN);
- launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
- launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- launchIntent.setPackage(component.getPackageName());
-
- try {
- ActivityInfo info = getPackageManager().getActivityInfo(component, 0, appUserId);
- if (info == null) {
- Slog.e(TAG, "Activity " + component + " is not installed.");
- return null;
- }
-
- if (!info.exported) {
- Slog.e(TAG, "Activity " + component + " doesn't have 'exported' attribute.");
- return null;
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to get activity info for " + component, e);
- return null;
- }
-
- // Check that the component actually has Intent.CATEGORY_LAUNCHER
- // as calling startActivityAsUser ignores the category and just
- // resolves based on the component if present.
- List<ResolveInfo> apps = mContext.getPackageManager().queryIntentActivitiesAsUser(launchIntent,
- 0 /* flags */, appUserId);
- final int size = apps.size();
- for (int i = 0; i < size; ++i) {
- ResolveInfo ri = apps.get(i);
- ActivityInfo activityInfo = ri.activityInfo;
- if (activityInfo.packageName.equals(component.getPackageName()) &&
- activityInfo.name.equals(component.getClassName())) {
- // Found an activity with category launcher that matches
- // this component so ok to launch.
- launchIntent.setComponent(component);
- ResolvedApp resolvedApp = new ResolvedApp();
- resolvedApp.launchIntent = launchIntent;
- resolvedApp.ri = ri;
- return resolvedApp;
- }
- }
-
- Slog.i(TAG, "Activity doesn't have category Intent.CATEGORY_LAUNCHER " + component);
- return null;
- }
-
- public void addOnAppsChangedListener(OnAppsChangedListener listener) {
- mOnAppsChangedListeners.add(listener);
- }
-
- public void removeOnAppsChangedListener(OnAppsChangedListener listener) {
- mOnAppsChangedListeners.remove(listener);
- }
-
- /**
- * Reinitializes the model for a new user.
- */
- public void setCurrentUser(int userId) {
- mCurrentUserId = userId;
- mCurrentUserSerialNumber = mUserManager.getSerialNumberForUser(new UserHandle(userId));
-
- mApps.clear();
-
- int appCount = mPrefs.getInt(userPrefixed(APP_COUNT_PREF), -1);
- if (appCount >= 0) {
- loadAppsFromPrefs(appCount);
- } else {
- // We switched to this user for the first time ever. This is a good opportunity to clean
- // prefs for users deleted in the past.
- removePrefsForDeletedUsers();
-
- addDefaultApps();
- }
- }
-
- /**
- * Removes prefs for users that don't exist on the device.
- */
- private void removePrefsForDeletedUsers() {
- // Build a set of string representations of serial numbers of the device users.
- final List<UserInfo> users = mUserManager.getUsers();
- final int userCount = users.size();
-
- final Set<String> userSerials = new HashSet<String> ();
-
- for (int i = 0; i < userCount; ++i) {
- userSerials.add(Long.toString(users.get(i).serialNumber));
- }
-
- // Walk though all prefs and delete ones which user is not in the string set.
- final Map<String, ?> allPrefs = mPrefs.getAll();
- final SharedPreferences.Editor edit = mPrefs.edit();
-
- for (Map.Entry<String, ?> pref : allPrefs.entrySet()) {
- final String key = pref.getKey();
- if (key.equals(VERSION_PREF)) continue;
-
- final int userSeparatorPos = key.indexOf(USER_SEPARATOR);
-
- if (userSeparatorPos < 0) {
- // Removing anomalous pref with no user.
- edit.remove(key);
- continue;
- }
-
- final String prefUserSerial = key.substring(0, userSeparatorPos);
-
- if (!userSerials.contains(prefUserSerial)) {
- // Removes pref for a not existing user.
- edit.remove(key);
- continue;
- }
- }
-
- edit.apply();
- }
-
- /** Returns the list of apps. */
- public List<AppInfo> getApps() {
- return mApps;
- }
-
- /** Sets the list of apps and saves it. */
- public void setApps(List<AppInfo> apps) {
- mApps = apps;
- savePrefs();
-
- int size = mOnAppsChangedListeners.size();
- for (int i = 0; i < size; ++i) {
- mOnAppsChangedListeners.get(i).onPinnedAppsChanged();
- }
- }
-
- /** Saves the current model to disk. */
- private void savePrefs() {
- SharedPreferences.Editor edit = mPrefs.edit();
- int appCount = mApps.size();
- edit.putInt(userPrefixed(APP_COUNT_PREF), appCount);
- for (int i = 0; i < appCount; i++) {
- final AppInfo appInfo = mApps.get(i);
- String componentNameString = appInfo.getComponentName().flattenToString();
- edit.putString(prefNameForApp(i), componentNameString);
- long userSerialNumber = mUserManager.getSerialNumberForUser(appInfo.getUser());
- edit.putLong(prefUserForApp(i), userSerialNumber);
- }
- // Start an asynchronous disk write.
- edit.apply();
- }
-
- /** Loads AppInfo from prefs. Returns null if something is wrong. */
- private AppInfo loadAppFromPrefs(int index) {
- String prefValue = mPrefs.getString(prefNameForApp(index), null);
- if (prefValue == null) {
- Slog.w(TAG, "Couldn't find pref " + prefNameForApp(index));
- return null;
- }
- ComponentName componentName = ComponentName.unflattenFromString(prefValue);
- if (componentName == null) {
- Slog.w(TAG, "Invalid component name " + prefValue);
- return null;
- }
- long userSerialNumber = mPrefs.getLong(prefUserForApp(index), -1);
- if (userSerialNumber == -1) {
- Slog.w(TAG, "Couldn't find pref " + prefUserForApp(index));
- return null;
- }
- UserHandle appUser = mUserManager.getUserForSerialNumber(userSerialNumber);
- if (appUser == null) {
- Slog.w(TAG, "No user for serial " + userSerialNumber);
- return null;
- }
- AppInfo appInfo = new AppInfo(componentName, appUser);
- if (resolveApp(appInfo) == null) {
- return null;
- }
- return appInfo;
- }
-
- /** Loads the list of apps from SharedPreferences. */
- private void loadAppsFromPrefs(int appCount) {
- for (int i = 0; i < appCount; i++) {
- AppInfo appInfo = loadAppFromPrefs(i);
- if (appInfo != null) {
- mApps.add(appInfo);
- }
- }
-
- if (appCount != mApps.size()) savePrefs();
- }
-
- /** Adds the first few apps from the owner profile. Used for demo purposes. */
- private void addDefaultApps() {
- // Get a list of all app activities.
- final Intent queryIntent = new Intent(Intent.ACTION_MAIN, null);
- queryIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-
- final List<ResolveInfo> apps = mContext.getPackageManager().queryIntentActivitiesAsUser(
- queryIntent, 0 /* flags */, mCurrentUserId);
- final int appCount = apps.size();
- for (int i = 0; i < NUM_INITIAL_APPS && i < appCount; i++) {
- ResolveInfo ri = apps.get(i);
- ComponentName componentName = new ComponentName(
- ri.activityInfo.packageName, ri.activityInfo.name);
- mApps.add(new AppInfo(componentName, new UserHandle(mCurrentUserId)));
- }
-
- savePrefs();
- }
-
- /** Returns a pref prefixed with the serial number of the current user. */
- private String userPrefixed(String pref) {
- return Long.toString(mCurrentUserSerialNumber) + USER_SEPARATOR + pref;
- }
-
- /** Returns the pref name for the app at a given index. */
- private String prefNameForApp(int index) {
- return userPrefixed(APP_PREF_PREFIX + Integer.toString(index));
- }
-
- /** Returns the pref name for the app's user at a given index. */
- private String prefUserForApp(int index) {
- return userPrefixed(APP_USER_PREFIX + Integer.toString(index));
- }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index abe357a..92288a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -42,16 +42,20 @@
implements TunerService.Tunable {
private static final String KEY_DOCK_WINDOW_GESTURE = "overview_nav_bar_gesture";
+ /**
+ * When dragging from the navigation bar, we drag in recents.
+ */
+ public static final int DRAG_MODE_NONE = -1;
/**
* When dragging from the navigation bar, we drag in recents.
*/
- private static final int DRAG_MODE_RECENTS = 0;
+ public static final int DRAG_MODE_RECENTS = 0;
/**
* When dragging from the navigation bar, we drag the divider.
*/
- private static final int DRAG_MODE_DIVIDER = 1;
+ public static final int DRAG_MODE_DIVIDER = 1;
private RecentsComponent mRecentsComponent;
private Divider mDivider;
@@ -207,12 +211,11 @@
< mContext.getResources().getDisplayMetrics().widthPixels / 2) {
createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
}
- boolean docked = mRecentsComponent.dockTopTask(dragMode == DRAG_MODE_RECENTS,
- createMode, initialBounds);
+ boolean docked = mRecentsComponent.dockTopTask(dragMode, createMode, initialBounds);
if (docked) {
mDragMode = dragMode;
if (mDragMode == DRAG_MODE_DIVIDER) {
- mDivider.getView().startDragging(false /* animate */);
+ mDivider.getView().startDragging(false /* animate */, true /* touching*/);
}
mDockWindowTouchSlopExceeded = true;
MetricsLogger.action(mContext,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index beeee0b..7395a33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -43,8 +43,6 @@
private static final String RECENT = "recent";
private static final String NAVSPACE = "space";
- private static final String APP_SHELF = "app_shelf";
-
public static final String GRAVITY_SEPARATOR = ";";
public static final String BUTTON_SEPARATOR = ",";
@@ -141,19 +139,13 @@
inflateButtons(start, (ViewGroup) mRot90.findViewById(R.id.ends_group),
(ViewGroup) mRot90.findViewById(R.id.ends_group_lightsout), true);
- if (center.length == 1 && APP_SHELF.equals(center[0])) {
- inflateShelf((LinearLayout) mRot0.findViewById(R.id.ends_group),
- (LinearLayout) mRot0.findViewById(R.id.ends_group_lightsout), false);
- inflateShelf((LinearLayout) mRot90.findViewById(R.id.ends_group),
- (LinearLayout) mRot90.findViewById(R.id.ends_group_lightsout), true);
- } else {
- inflateButtons(center, (ViewGroup) mRot0.findViewById(R.id.center_group),
- (ViewGroup) mRot0.findViewById(R.id.center_group_lightsout), false);
- inflateButtons(center, (ViewGroup) mRot90.findViewById(R.id.center_group),
- (ViewGroup) mRot90.findViewById(R.id.center_group_lightsout), true);
- addGravitySpacer((LinearLayout) mRot0.findViewById(R.id.ends_group));
- addGravitySpacer((LinearLayout) mRot90.findViewById(R.id.ends_group));
- }
+ inflateButtons(center, (ViewGroup) mRot0.findViewById(R.id.center_group),
+ (ViewGroup) mRot0.findViewById(R.id.center_group_lightsout), false);
+ inflateButtons(center, (ViewGroup) mRot90.findViewById(R.id.center_group),
+ (ViewGroup) mRot90.findViewById(R.id.center_group_lightsout), true);
+
+ addGravitySpacer((LinearLayout) mRot0.findViewById(R.id.ends_group));
+ addGravitySpacer((LinearLayout) mRot90.findViewById(R.id.ends_group));
inflateButtons(end, (ViewGroup) mRot0.findViewById(R.id.ends_group),
(ViewGroup) mRot0.findViewById(R.id.ends_group_lightsout), false);
@@ -161,14 +153,6 @@
(ViewGroup) mRot90.findViewById(R.id.ends_group_lightsout), true);
}
- private void inflateShelf(LinearLayout layout, LinearLayout lightsOut, boolean landscape) {
- View v = (landscape ? mLandscapeInflater : mLayoutInflater)
- .inflate(R.layout.apps_bar, layout, false);
- layout.addView(v);
- addToDispatchers(v);
- copyToLightsout(v, lightsOut);
- }
-
private void addGravitySpacer(LinearLayout layout) {
layout.addView(new Space(mContext), new LinearLayout.LayoutParams(0, 0, 1));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 839b579..d86629f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -263,11 +263,6 @@
return mButtonDisatchers.get(R.id.ime_switcher);
}
- @Nullable
- public View getAppShelf() {
- return getCurrentView().findViewById(R.id.app_shelf);
- }
-
private void getCarModeIcons(Context ctx) {
mBackCarModeIcon = ctx.getDrawable(R.drawable.ic_sysbar_back_carmode);
mBackLandCarModeIcon = mBackCarModeIcon;
@@ -395,12 +390,6 @@
getBackButton().setVisibility(disableBack ? View.INVISIBLE : View.VISIBLE);
getHomeButton().setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE);
getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE);
-
- // The app shelf, if it exists, follows the visibility of the home button.
- View appShelf = getAppShelf();
- if (appShelf != null) {
- appShelf.setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE);
- }
}
private boolean inLockTask() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index ba20679..8e89efd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -39,11 +39,11 @@
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.widget.FrameLayout;
import android.widget.TextView;
+
import com.android.internal.logging.MetricsLogger;
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.DejankUtils;
@@ -57,6 +57,7 @@
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.GestureRecorder;
+import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.StatusBarState;
@@ -104,7 +105,6 @@
private View mQsNavbarScrim;
private NotificationsQuickSettingsContainer mNotificationContainerParent;
private NotificationStackScrollLayout mNotificationStackScroller;
- private int mNotificationTopPadding;
private boolean mAnimateNextTopPaddingChange;
private int mTrackingPointer;
@@ -151,9 +151,6 @@
private int mUnlockMoveDistance;
private float mEmptyDragAmount;
- private Interpolator mFastOutSlowInInterpolator;
- private Interpolator mFastOutLinearInterpolator;
- private Interpolator mDozeAnimationInterpolator;
private ObjectAnimator mClockAnimator;
private int mClockAnimationTarget = -1;
private int mTopPaddingAdjustment;
@@ -253,12 +250,6 @@
mNotificationStackScroller.setOverscrollTopChangedListener(this);
mNotificationStackScroller.setOnEmptySpaceClickListener(this);
mNotificationStackScroller.setScrollView(mScrollView);
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
- android.R.interpolator.fast_out_slow_in);
- mFastOutLinearInterpolator = AnimationUtils.loadInterpolator(getContext(),
- android.R.interpolator.fast_out_linear_in);
- mDozeAnimationInterpolator = AnimationUtils.loadInterpolator(getContext(),
- android.R.interpolator.linear_out_slow_in);
mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
mQsNavbarScrim = findViewById(R.id.qs_navbar_scrim);
mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext());
@@ -281,8 +272,6 @@
@Override
protected void loadDimens() {
super.loadDimens();
- mNotificationTopPadding = getResources().getDimensionPixelSize(
- R.dimen.notifications_top_padding);
mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.4f);
mStatusBarMinHeight = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height);
@@ -371,7 +360,7 @@
}
mQsSizeChangeAnimator = ValueAnimator.ofInt(oldHeight, newHeight);
mQsSizeChangeAnimator.setDuration(300);
- mQsSizeChangeAnimator.setInterpolator(mFastOutSlowInInterpolator);
+ mQsSizeChangeAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mQsSizeChangeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
@@ -400,8 +389,8 @@
if (mStatusBarState != StatusBarState.KEYGUARD) {
int bottom = mHeader.getCollapsedHeight();
stackScrollerPadding = mStatusBarState == StatusBarState.SHADE
- ? bottom + mQsPeekHeight + mNotificationTopPadding
- : mKeyguardStatusBar.getHeight() + mNotificationTopPadding;
+ ? bottom + mQsPeekHeight
+ : mKeyguardStatusBar.getHeight();
mTopPaddingAdjustment = 0;
} else {
mClockPositionAlgorithm.setup(
@@ -433,8 +422,8 @@
public int computeMaxKeyguardNotifications(int maximum) {
float minPadding = mClockPositionAlgorithm.getMinStackScrollerPadding(getHeight(),
mKeyguardStatusView.getHeight());
- int keyguardPadding = getResources().getDimensionPixelSize(
- R.dimen.notification_padding_dimmed);
+ int notificationPadding = Math.max(1, getResources().getDimensionPixelSize(
+ R.dimen.notification_divider_height));
final int overflowheight = getResources().getDimensionPixelSize(
R.dimen.notification_summary_height);
float bottomStackSize = mNotificationStackScroller.getKeyguardBottomStackSize();
@@ -446,7 +435,7 @@
if (!(child instanceof ExpandableNotificationRow)) {
continue;
}
- availableSpace -= child.getMinHeight() + keyguardPadding;
+ availableSpace -= child.getMinHeight() + notificationPadding;
if (availableSpace >= 0 && count < maximum) {
count++;
} else {
@@ -471,7 +460,7 @@
}
mClockAnimator = ObjectAnimator
.ofFloat(mKeyguardStatusView, View.Y, mClockAnimationTarget);
- mClockAnimator.setInterpolator(mFastOutSlowInInterpolator);
+ mClockAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mClockAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
mClockAnimator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -1107,7 +1096,7 @@
.translationY(0f)
.setStartDelay(delay)
.setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE)
- .setInterpolator(mFastOutSlowInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.start();
mQsContainer.setY(-mQsContainer.getHeight());
mQsContainerAnimator = ObjectAnimator.ofFloat(mQsContainer, View.TRANSLATION_Y,
@@ -1116,7 +1105,7 @@
- mQsContainer.getTop());
mQsContainerAnimator.setStartDelay(delay);
mQsContainerAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
- mQsContainerAnimator.setInterpolator(mFastOutSlowInInterpolator);
+ mQsContainerAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mQsContainerAnimator.addListener(mAnimateHeaderSlidingInListener);
mQsContainerAnimator.start();
mQsContainer.addOnLayoutChangeListener(mQsContainerAnimatorUpdater);
@@ -1138,7 +1127,7 @@
mHeader.animate().y(-mHeader.getHeight())
.setStartDelay(0)
.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
- .setInterpolator(mFastOutSlowInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -1152,7 +1141,7 @@
.y(-mQsContainer.getHeight())
.setStartDelay(0)
.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD)
- .setInterpolator(mFastOutSlowInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.start();
}
@@ -1174,7 +1163,7 @@
anim.setDuration(mStatusBar.isKeyguardFadingAway()
? mStatusBar.getKeyguardFadingAwayDuration() / 2
: StackStateAnimator.ANIMATION_DURATION_STANDARD);
- anim.setInterpolator(mDozeAnimationInterpolator);
+ anim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -1199,7 +1188,7 @@
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
anim.addUpdateListener(mStatusBarAnimateAlphaListener);
anim.setDuration(duration);
- anim.setInterpolator(mDozeAnimationInterpolator);
+ anim.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
anim.start();
}
@@ -1218,7 +1207,7 @@
.alpha(0f)
.setStartDelay(mStatusBar.getKeyguardFadingAwayDelay())
.setDuration(mStatusBar.getKeyguardFadingAwayDuration() / 2)
- .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+ .setInterpolator(Interpolators.ALPHA_OUT)
.withEndAction(mAnimateKeyguardBottomAreaInvisibleEndRunnable)
.start();
} else if (statusBarState == StatusBarState.KEYGUARD
@@ -1245,7 +1234,7 @@
.alpha(0f)
.setStartDelay(0)
.setDuration(160)
- .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+ .setInterpolator(Interpolators.ALPHA_OUT)
.withEndAction(mAnimateKeyguardStatusViewInvisibleEndRunnable);
if (keyguardFadingAway) {
mKeyguardStatusView.animate()
@@ -1263,7 +1252,7 @@
.alpha(1f)
.setStartDelay(0)
.setDuration(320)
- .setInterpolator(PhoneStatusBar.ALPHA_IN)
+ .setInterpolator(Interpolators.ALPHA_IN)
.withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable);
} else if (statusBarState == StatusBarState.KEYGUARD) {
mKeyguardStatusView.animate().cancel();
@@ -1380,8 +1369,7 @@
// on Keyguard, maxQs denotes the top padding from the quick settings panel. We need to
// take the maximum and linearly interpolate with the panel expansion for a nice motion.
int maxNotifications = mClockPositionResult.stackScrollerPadding
- - mClockPositionResult.stackScrollerPaddingAdjustment
- - mNotificationTopPadding;
+ - mClockPositionResult.stackScrollerPaddingAdjustment;
int maxQs = getTempQsMaxExpansion();
int max = mStatusBarState == StatusBarState.KEYGUARD
? Math.max(maxNotifications, maxQs)
@@ -1395,7 +1383,7 @@
// We can only do the smoother transition on Keyguard when we also are not collapsing
// from a scrolled quick settings.
return interpolate(getQsExpansionFraction(),
- mNotificationStackScroller.getIntrinsicPadding() - mNotificationTopPadding,
+ mNotificationStackScroller.getIntrinsicPadding(),
mQsMaxExpansionHeight);
} else {
return mQsExpansionHeight;
@@ -1625,15 +1613,13 @@
maxQsHeight = (int) mQsSizeChangeAnimator.getAnimatedValue();
}
float totalHeight = Math.max(
- maxQsHeight + mNotificationStackScroller.getNotificationTopPadding(),
- mStatusBarState == StatusBarState.KEYGUARD
+ maxQsHeight, mStatusBarState == StatusBarState.KEYGUARD
? mClockPositionResult.stackScrollerPadding - mTopPaddingAdjustment
: 0)
+ notificationHeight;
if (totalHeight > mNotificationStackScroller.getHeight()) {
float fullyCollapsedHeight = maxQsHeight
+ mNotificationStackScroller.getMinStackHeight()
- + mNotificationStackScroller.getNotificationTopPadding()
- getScrollViewScrollY();
totalHeight = Math.max(fullyCollapsedHeight, mNotificationStackScroller.getHeight());
}
@@ -1680,14 +1666,14 @@
boolean active = getMaxPanelHeight() - getExpandedHeight() > mUnlockMoveDistance;
KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon();
if (active && !mUnlockIconActive && mTracking) {
- lockIcon.setImageAlpha(1.0f, true, 150, mFastOutLinearInterpolator, null);
+ lockIcon.setImageAlpha(1.0f, true, 150, Interpolators.FAST_OUT_LINEAR_IN, null);
lockIcon.setImageScale(LOCK_ICON_ACTIVE_SCALE, true, 150,
- mFastOutLinearInterpolator);
+ Interpolators.FAST_OUT_LINEAR_IN);
} else if (!active && mUnlockIconActive && mTracking) {
lockIcon.setImageAlpha(lockIcon.getRestingAlpha(), true /* animate */,
- 150, mFastOutLinearInterpolator, null);
+ 150, Interpolators.FAST_OUT_LINEAR_IN, null);
lockIcon.setImageScale(1.0f, true, 150,
- mFastOutLinearInterpolator);
+ Interpolators.FAST_OUT_LINEAR_IN);
}
mUnlockIconActive = active;
}
@@ -1727,7 +1713,7 @@
float translation = stackTranslation / HEADER_RUBBERBAND_FACTOR;
if (mHeadsUpManager.hasPinnedHeadsUp() || mIsExpansionFromHeadsUp) {
translation = mNotificationStackScroller.getTopPadding() + stackTranslation
- - mNotificationTopPadding - mQsMinExpansionHeight;
+ - mQsMinExpansionHeight;
}
return Math.min(0, translation);
}
@@ -1892,8 +1878,8 @@
if (!expand && (mStatusBar.getBarState() == StatusBarState.KEYGUARD
|| mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED)) {
KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon();
- lockIcon.setImageAlpha(0.0f, true, 100, mFastOutLinearInterpolator, null);
- lockIcon.setImageScale(2.0f, true, 100, mFastOutLinearInterpolator);
+ lockIcon.setImageAlpha(0.0f, true, 100, Interpolators.FAST_OUT_LINEAR_IN, null);
+ lockIcon.setImageScale(2.0f, true, 100, Interpolators.FAST_OUT_LINEAR_IN);
}
}
@@ -2033,12 +2019,12 @@
*/
private void startHighlightIconAnimation(final KeyguardAffordanceView icon) {
icon.setImageAlpha(1.0f, true, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
- mFastOutSlowInInterpolator, new Runnable() {
+ Interpolators.FAST_OUT_SLOW_IN, new Runnable() {
@Override
public void run() {
icon.setImageAlpha(icon.getRestingAlpha(),
true /* animate */, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
- mFastOutSlowInInterpolator, null);
+ Interpolators.FAST_OUT_SLOW_IN, null);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index f0b7894..f036d04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -29,7 +29,6 @@
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.ViewTreeObserver;
-import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
@@ -39,6 +38,7 @@
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.statusbar.FlingAnimationUtils;
+import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -100,8 +100,6 @@
private float mInitialTouchX;
private boolean mTouchDisabled;
- private Interpolator mLinearOutSlowInInterpolator;
- private Interpolator mFastOutSlowInInterpolator;
private Interpolator mBounceInterpolator;
protected KeyguardBottomAreaView mKeyguardBottomArea;
@@ -161,7 +159,7 @@
}
mPeekAnimator = ObjectAnimator.ofFloat(this, "expandedHeight", mPeekHeight)
.setDuration(250);
- mPeekAnimator.setInterpolator(mLinearOutSlowInInterpolator);
+ mPeekAnimator.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
mPeekAnimator.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
@@ -187,10 +185,6 @@
public PanelView(Context context, AttributeSet attrs) {
super(context, attrs);
mFlingAnimationUtils = new FlingAnimationUtils(context, 0.6f);
- mFastOutSlowInInterpolator =
- AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
- mLinearOutSlowInInterpolator =
- AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
mBounceInterpolator = new BounceInterpolator();
mFalsingManager = FalsingManager.getInstance(context);
}
@@ -951,7 +945,7 @@
float target = Math.max(0, getMaxPanelHeight() - mHintDistance);
ValueAnimator animator = createHeightAnimator(target);
animator.setDuration(250);
- animator.setInterpolator(mFastOutSlowInInterpolator);
+ animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
animator.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
@@ -975,7 +969,7 @@
mKeyguardBottomArea.getIndicationView().animate()
.translationY(-mHintDistance)
.setDuration(250)
- .setInterpolator(mFastOutSlowInInterpolator)
+ .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.withEndAction(new Runnable() {
@Override
public void run() {
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 e2a6184..6fa1f5df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -47,6 +47,7 @@
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.hardware.display.DisplayManager;
import android.inputmethodservice.InputMethodService;
import android.media.AudioAttributes;
import android.media.MediaMetadata;
@@ -87,13 +88,11 @@
import android.view.ViewStub;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
-import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
-import android.view.animation.PathInterpolator;
import android.widget.ImageView;
import android.widget.TextView;
+
import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.statusbar.StatusBarIcon;
@@ -114,6 +113,8 @@
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.recents.ScreenPinningRequest;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.DockingTopTaskEvent;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.ActivatableNotificationView;
import com.android.systemui.statusbar.BackDropView;
@@ -124,6 +125,7 @@
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.GestureRecorder;
+import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationData.Entry;
@@ -131,7 +133,6 @@
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.SignalClusterView;
-import com.android.systemui.statusbar.SpeedBumpView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
import com.android.systemui.statusbar.policy.AccessibilityController;
@@ -438,10 +439,8 @@
private boolean mDozingRequested;
protected boolean mScrimSrcModeEnabled;
- private Interpolator mLinearInterpolator = new LinearInterpolator();
- private Interpolator mBackdropInterpolator = new AccelerateDecelerateInterpolator();
- public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
- public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
+ public static final Interpolator ALPHA_IN = Interpolators.ALPHA_IN;
+ public static final Interpolator ALPHA_OUT = Interpolators.ALPHA_OUT;
private BackDropView mBackdrop;
private ImageView mBackdropFront, mBackdropBack;
@@ -744,9 +743,7 @@
mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener);
mStackScroller.setOverflowContainer(mKeyguardIconOverflowContainer);
- SpeedBumpView speedBump = (SpeedBumpView) LayoutInflater.from(mContext).inflate(
- R.layout.status_bar_notification_speed_bump, mStackScroller, false);
- mStackScroller.setSpeedBumpView(speedBump);
+
mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
R.layout.status_bar_no_notifications, mStackScroller, false);
mStackScroller.setEmptyShadeView(mEmptyShadeView);
@@ -1108,9 +1105,22 @@
@Override
public boolean onLongClick(View v) {
if (mRecents != null) {
- boolean docked = mRecents.dockTopTask(false /* draggingInRecents */,
+ Point realSize = new Point();
+ mContext.getSystemService(DisplayManager.class).getDisplay(Display.DEFAULT_DISPLAY)
+ .getRealSize(realSize);
+ Rect initialBounds;
+
+ // Hack level over 9000: Make it one pixel smaller so activity manager doesn't
+ // dismiss it immediately again. Remove once b/26777526 is fixed.
+ if (mContext.getResources().getConfiguration().orientation
+ == Configuration.ORIENTATION_LANDSCAPE) {
+ initialBounds = new Rect(0, 0, realSize.x - 1, realSize.y);
+ } else {
+ initialBounds = new Rect(0, 0, realSize.x, realSize.y - 1);
+ }
+ boolean docked = mRecents.dockTopTask(NavigationBarGestureHelper.DRAG_MODE_NONE,
ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
- null /* initialBounds */);
+ initialBounds);
if (docked) {
MetricsLogger.action(mContext,
MetricsLogger.ACTION_WINDOW_DOCK_LONGPRESS);
@@ -1256,7 +1266,7 @@
}
if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) {
- if (mNotificationData.shouldSuppressScreenOn(notification.getKey())) {
+ if (shouldSupressFullScreenIntent(notification.getKey())) {
if (DEBUG) {
Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + notification.getKey());
}
@@ -1283,6 +1293,14 @@
setAreThereNotifications();
}
+ private boolean shouldSupressFullScreenIntent(String key) {
+ if (mPowerManager.isInteractive()) {
+ return mNotificationData.shouldSuppressPeek(key);
+ } else {
+ return mNotificationData.shouldSuppressScreenOn(key);
+ }
+ }
+
@Override
protected void updateNotificationRanking(RankingMap ranking) {
mNotificationData.updateRanking(ranking);
@@ -1841,7 +1859,7 @@
// if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in
// libhwui.
.alpha(0.002f)
- .setInterpolator(mBackdropInterpolator)
+ .setInterpolator(Interpolators.ACCELERATE_DECELERATE)
.setDuration(300)
.setStartDelay(0)
.withEndAction(new Runnable() {
@@ -1860,7 +1878,7 @@
// behind.
.setDuration(mKeyguardFadingAwayDuration / 2)
.setStartDelay(mKeyguardFadingAwayDelay)
- .setInterpolator(mLinearInterpolator)
+ .setInterpolator(Interpolators.LINEAR)
.start();
}
}
@@ -3740,7 +3758,7 @@
mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade);
updateDozingState();
updatePublicMode();
- updateStackScrollerState(goingToFullShade);
+ updateStackScrollerState(goingToFullShade, fromShadeLocked);
updateNotifications();
checkBarModes();
updateMediaMetaData(false);
@@ -3761,11 +3779,11 @@
!= FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING, animate);
}
- public void updateStackScrollerState(boolean goingToFullShade) {
+ public void updateStackScrollerState(boolean goingToFullShade, boolean fromShadeLocked) {
if (mStackScroller == null) return;
boolean onKeyguard = mState == StatusBarState.KEYGUARD;
mStackScroller.setHideSensitive(isLockscreenPublicMode(), goingToFullShade);
- mStackScroller.setDimmed(onKeyguard, false /* animate */);
+ mStackScroller.setDimmed(onKeyguard, fromShadeLocked /* animate */);
mStackScroller.setExpandingEnabled(!onKeyguard);
ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild();
mStackScroller.setActivatedChild(null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 403199a..f310c2c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -22,6 +22,7 @@
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Color;
+import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.DecelerateInterpolator;
@@ -497,4 +498,16 @@
public void dontAnimateBouncerChangesUntilNextFrame() {
mDontAnimateBouncerChanges = true;
}
+
+ public void setExcludedBackgroundArea(Rect area) {
+ mScrimBehind.setExcludedArea(area);
+ }
+
+ public int getScrimBehindColor() {
+ return mScrimBehind.getScrimColorWithAlpha();
+ }
+
+ public void setScrimBehindChangeRunnable(Runnable changeRunnable) {
+ mScrimBehind.setChangeRunnable(changeRunnable);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
index 512af1b..7247b57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
@@ -26,7 +26,9 @@
import android.view.ViewConfiguration;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
+
import com.android.keyguard.AlphaOptimizedImageButton;
+import com.android.systemui.statusbar.Interpolators;
public class SettingsButton extends AlphaOptimizedImageButton {
@@ -157,8 +159,7 @@
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
mUpToSpeed = true;
mAnimator = ObjectAnimator.ofFloat(this, View.ROTATION, 0, 360);
- mAnimator.setInterpolator(AnimationUtils.loadInterpolator(mContext,
- android.R.interpolator.linear));
+ mAnimator.setInterpolator(Interpolators.LINEAR);
mAnimator.setDuration(FULL_SPEED_LENGTH);
mAnimator.setRepeatCount(Animation.INFINITE);
mAnimator.start();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 64fb066..c6537e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -32,15 +32,15 @@
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
+
import com.android.internal.statusbar.StatusBarIcon;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
+import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarIconView;
@@ -63,8 +63,6 @@
private Context mContext;
private PhoneStatusBar mPhoneStatusBar;
- private Interpolator mLinearOutSlowIn;
- private Interpolator mFastOutSlowIn;
private DemoStatusIcons mDemoStatusIcons;
private LinearLayout mSystemIconArea;
@@ -129,10 +127,6 @@
maybeScaleBatteryMeterView(context);
mClock = (TextView) statusBar.findViewById(R.id.clock);
- mLinearOutSlowIn = AnimationUtils.loadInterpolator(mContext,
- android.R.interpolator.linear_out_slow_in);
- mFastOutSlowIn = AnimationUtils.loadInterpolator(mContext,
- android.R.interpolator.fast_out_slow_in);
mDarkModeIconColorSingleTone = context.getColor(R.color.dark_mode_icon_color_single_tone);
mLightModeIconColorSingleTone = context.getColor(R.color.light_mode_icon_color_single_tone);
mHandler = new Handler();
@@ -348,7 +342,7 @@
.alpha(0f)
.setDuration(160)
.setStartDelay(0)
- .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+ .setInterpolator(Interpolators.ALPHA_OUT)
.withEndAction(new Runnable() {
@Override
public void run() {
@@ -370,7 +364,7 @@
v.animate()
.alpha(1f)
.setDuration(320)
- .setInterpolator(PhoneStatusBar.ALPHA_IN)
+ .setInterpolator(Interpolators.ALPHA_IN)
.setStartDelay(50)
// We need to clean up any pending end action from animateHide if we call
@@ -382,7 +376,7 @@
if (mPhoneStatusBar.isKeyguardFadingAway()) {
v.animate()
.setDuration(mPhoneStatusBar.getKeyguardFadingAwayDuration())
- .setInterpolator(mLinearOutSlowIn)
+ .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
.setStartDelay(mPhoneStatusBar.getKeyguardFadingAwayDelay())
.start();
}
@@ -419,7 +413,7 @@
});
mTintAnimator.setDuration(duration);
mTintAnimator.setStartDelay(delay);
- mTintAnimator.setInterpolator(mFastOutSlowIn);
+ mTintAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
mTintAnimator.start();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java
index 56c1e10..1aae496 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java
@@ -16,8 +16,6 @@
package com.android.systemui.statusbar.phone;
-import com.android.systemui.R;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -31,10 +29,11 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.Interpolators;
+
public class TrustDrawable extends Drawable {
private static final long ENTERING_FROM_UNSET_START_DELAY = 200;
@@ -69,10 +68,6 @@
private final Animator mVisibleAnimator;
- private final Interpolator mLinearOutSlowInInterpolator;
- private final Interpolator mFastOutSlowInInterpolator;
- private final Interpolator mAccelerateDecelerateInterpolator;
-
public TrustDrawable(Context context) {
Resources r = context.getResources();
mInnerRadiusVisibleMin = r.getDimension(R.dimen.trust_circle_inner_radius_visible_min);
@@ -83,12 +78,6 @@
mCurInnerRadius = mInnerRadiusEnter;
- mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(
- context, android.R.interpolator.linear_out_slow_in);
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(
- context, android.R.interpolator.fast_out_slow_in);
- mAccelerateDecelerateInterpolator = new AccelerateDecelerateInterpolator();
-
mVisibleAnimator = makeVisibleAnimator();
mPaint = new Paint();
@@ -212,19 +201,19 @@
private Animator makeVisibleAnimator() {
return makeAnimators(mInnerRadiusVisibleMax, mInnerRadiusVisibleMin,
ALPHA_VISIBLE_MAX, ALPHA_VISIBLE_MIN, VISIBLE_DURATION,
- mAccelerateDecelerateInterpolator,
+ Interpolators.ACCELERATE_DECELERATE,
true /* repeating */, false /* stateUpdateListener */);
}
private Animator makeEnterAnimator(float radius, int alpha) {
return makeAnimators(radius, mInnerRadiusVisibleMax,
- alpha, ALPHA_VISIBLE_MAX, ENTER_DURATION, mLinearOutSlowInInterpolator,
+ alpha, ALPHA_VISIBLE_MAX, ENTER_DURATION, Interpolators.LINEAR_OUT_SLOW_IN,
false /* repeating */, true /* stateUpdateListener */);
}
private Animator makeExitAnimator(float radius, int alpha) {
return makeAnimators(radius, mInnerRadiusExit,
- alpha, 0, EXIT_DURATION, mFastOutSlowInInterpolator,
+ alpha, 0, EXIT_DURATION, Interpolators.FAST_OUT_SLOW_IN,
false /* repeating */, true /* stateUpdateListener */);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index 4ae0321..59d54ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -16,15 +16,15 @@
package com.android.systemui.statusbar.policy;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.ScrimView;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
-import com.android.systemui.statusbar.phone.StatusBarWindowView;
-
import android.view.View;
import android.view.ViewPropertyAnimator;
import android.widget.FrameLayout;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.Interpolators;
+import com.android.systemui.statusbar.ScrimView;
+import com.android.systemui.statusbar.phone.StatusBarWindowView;
+
/**
* Controls showing and hiding of the brightness mirror.
*/
@@ -46,13 +46,13 @@
public void showMirror() {
mBrightnessMirror.setVisibility(View.VISIBLE);
- mScrimBehind.animateViewAlpha(0.0f, TRANSITION_DURATION_OUT, PhoneStatusBar.ALPHA_OUT);
+ mScrimBehind.animateViewAlpha(0.0f, TRANSITION_DURATION_OUT, Interpolators.ALPHA_OUT);
outAnimation(mNotificationPanel.animate())
.withLayer();
}
public void hideMirror() {
- mScrimBehind.animateViewAlpha(1.0f, TRANSITION_DURATION_IN, PhoneStatusBar.ALPHA_IN);
+ mScrimBehind.animateViewAlpha(1.0f, TRANSITION_DURATION_IN, Interpolators.ALPHA_IN);
inAnimation(mNotificationPanel.animate())
.withLayer()
.withEndAction(new Runnable() {
@@ -66,12 +66,12 @@
private ViewPropertyAnimator outAnimation(ViewPropertyAnimator a) {
return a.alpha(0.0f)
.setDuration(TRANSITION_DURATION_OUT)
- .setInterpolator(PhoneStatusBar.ALPHA_OUT);
+ .setInterpolator(Interpolators.ALPHA_OUT);
}
private ViewPropertyAnimator inAnimation(ViewPropertyAnimator a) {
return a.alpha(1.0f)
.setDuration(TRANSITION_DURATION_IN)
- .setInterpolator(PhoneStatusBar.ALPHA_IN);
+ .setInterpolator(Interpolators.ALPHA_IN);
}
@@ -103,10 +103,5 @@
lp.gravity = mBrightnessMirror.getResources().getInteger(
R.integer.notification_panel_layout_gravity);
mBrightnessMirror.setLayoutParams(lp);
-
- int padding = mBrightnessMirror.getResources().getDimensionPixelSize(
- R.dimen.notification_side_padding);
- mBrightnessMirror.setPadding(padding, mBrightnessMirror.getPaddingTop(),
- padding, mBrightnessMirror.getPaddingBottom());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index dd7bd56..f065522 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -84,7 +84,6 @@
private final View mStatusBarWindowView;
private final int mStatusBarHeight;
- private final int mNotificationsTopPadding;
private final Context mContext;
private final NotificationGroupManager mGroupManager;
private PhoneStatusBar mBar;
@@ -138,8 +137,6 @@
mGroupManager = groupManager;
mStatusBarHeight = resources.getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height);
- mNotificationsTopPadding = context.getResources()
- .getDimensionPixelSize(R.dimen.notifications_top_padding);
}
private void updateTouchableRegionListener() {
@@ -399,7 +396,7 @@
}
info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
- info.touchableRegion.set(minX, 0, maxX, maxY + mNotificationsTopPadding);
+ info.touchableRegion.set(minX, 0, maxX, maxY);
} else if (mHeadsUpGoingAway || mWaitingOnCollapseWhenGoingAway) {
info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
info.touchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
index 3f63b5f..d739d6c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonRipple.java
@@ -32,7 +32,7 @@
import android.view.animation.Interpolator;
import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.Interpolators;
import java.util.ArrayList;
import java.util.HashSet;
@@ -59,7 +59,6 @@
private int mMaxWidth;
private final Interpolator mInterpolator = new LogInterpolator();
- private final Interpolator mAlphaExitInterpolator = PhoneStatusBar.ALPHA_OUT;
private boolean mSupportHardware;
private final View mTargetView;
@@ -225,7 +224,7 @@
private void exitSoftware() {
ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(this, "glowAlpha", mGlowAlpha, 0f);
- alphaAnimator.setInterpolator(mAlphaExitInterpolator);
+ alphaAnimator.setInterpolator(Interpolators.ALPHA_OUT);
alphaAnimator.setDuration(ANIMATION_DURATION_FADE);
alphaAnimator.addListener(mAnimatorListener);
alphaAnimator.start();
@@ -331,7 +330,7 @@
final RenderNodeAnimator opacityAnim = new RenderNodeAnimator(mPaintProp,
RenderNodeAnimator.PAINT_ALPHA, 0);
opacityAnim.setDuration(ANIMATION_DURATION_FADE);
- opacityAnim.setInterpolator(mAlphaExitInterpolator);
+ opacityAnim.setInterpolator(Interpolators.ALPHA_OUT);
opacityAnim.addListener(mAnimatorListener);
opacityAnim.setTarget(mTargetView);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index 5cf6156..0959b0c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -21,6 +21,7 @@
import android.animation.ObjectAnimator;
import android.content.Context;
import android.database.DataSetObserver;
+import android.graphics.Interpolator;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -33,9 +34,9 @@
import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.systemui.R;
import com.android.systemui.qs.tiles.UserDetailItemView;
+import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
import com.android.systemui.statusbar.phone.NotificationPanelView;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
/**
* Manages the user switcher on the Keyguard.
@@ -73,8 +74,7 @@
mAdapter.registerDataSetObserver(mDataSetObserver);
mUserSwitcherController = userSwitcherController;
mAppearAnimationUtils = new AppearAnimationUtils(context, 400, -0.5f, 0.5f,
- AnimationUtils.loadInterpolator(
- context, android.R.interpolator.fast_out_slow_in));
+ Interpolators.FAST_OUT_SLOW_IN);
mUserSwitcherContainer.setKeyguardUserSwitcher(this);
} else {
mUserSwitcherContainer = null;
@@ -158,7 +158,7 @@
mAnimating = true;
mBgAnimator = ObjectAnimator.ofInt(mBackground, "alpha", 0, 255);
mBgAnimator.setDuration(400);
- mBgAnimator.setInterpolator(PhoneStatusBar.ALPHA_IN);
+ mBgAnimator.setInterpolator(Interpolators.ALPHA_IN);
mBgAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -174,7 +174,7 @@
mUserSwitcher.animate()
.alpha(0f)
.setDuration(300)
- .setInterpolator(PhoneStatusBar.ALPHA_OUT)
+ .setInterpolator(Interpolators.ALPHA_OUT)
.withEndAction(new Runnable() {
@Override
public void run() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index dbb0295..107a904 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -817,11 +817,11 @@
public static class SubscriptionDefaults {
public int getDefaultVoiceSubId() {
- return SubscriptionManager.getDefaultVoiceSubId();
+ return SubscriptionManager.getDefaultVoiceSubscriptionId();
}
public int getDefaultDataSubId() {
- return SubscriptionManager.getDefaultDataSubId();
+ return SubscriptionManager.getDefaultDataSubscriptionId();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
index 56f6564..561b18a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
@@ -25,12 +25,12 @@
boolean animateAlpha;
boolean animateY;
boolean animateZ;
- boolean animateScale;
boolean animateHeight;
boolean animateTopInset;
boolean animateDimmed;
boolean animateDark;
boolean animateHideSensitive;
+ public boolean animateShadowAlpha;
boolean hasDelays;
boolean hasGoToFullShadeEvent;
boolean hasDarkEvent;
@@ -57,11 +57,6 @@
return this;
}
- public AnimationFilter animateScale() {
- animateScale = true;
- return this;
- }
-
public AnimationFilter animateHeight() {
animateHeight = true;
return this;
@@ -87,6 +82,11 @@
return this;
}
+ public AnimationFilter animateShadowAlpha() {
+ animateShadowAlpha = true;
+ return this;
+ }
+
/**
* Combines multiple filters into {@code this} filter, using or as the operand .
*
@@ -118,12 +118,12 @@
animateAlpha |= filter.animateAlpha;
animateY |= filter.animateY;
animateZ |= filter.animateZ;
- animateScale |= filter.animateScale;
animateHeight |= filter.animateHeight;
animateTopInset |= filter.animateTopInset;
animateDimmed |= filter.animateDimmed;
animateDark |= filter.animateDark;
animateHideSensitive |= filter.animateHideSensitive;
+ animateShadowAlpha |= filter.animateShadowAlpha;
hasDelays |= filter.hasDelays;
}
@@ -131,8 +131,8 @@
animateAlpha = false;
animateY = false;
animateZ = false;
- animateScale = false;
animateHeight = false;
+ animateShadowAlpha = false;
animateTopInset = false;
animateDimmed = false;
animateDark = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index dc40fb0..409dac1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -76,8 +76,8 @@
super(context, attrs, defStyleAttr, defStyleRes);
mChildPadding = getResources().getDimensionPixelSize(
R.dimen.notification_children_padding);
- mDividerHeight = getResources().getDimensionPixelSize(
- R.dimen.notification_children_divider_height);
+ mDividerHeight = Math.max(1, getResources().getDimensionPixelSize(
+ R.dimen.notification_divider_height));
mMaxNotificationHeight = getResources().getDimensionPixelSize(
R.dimen.notification_max_height);
mNotificationAppearDistance = getResources().getDimensionPixelSize(
@@ -324,7 +324,6 @@
childState.dark = parentState.dark;
childState.hideSensitive = parentState.hideSensitive;
childState.belowSpeedBump = parentState.belowSpeedBump;
- childState.scale = 1.0f;
childState.clipTopAmount = 0;
childState.topOverLap = 0;
boolean visible = i <= lastVisibleIndex;
@@ -384,30 +383,8 @@
* @param state the new state we animate to
*/
public void prepareExpansionChanged(StackScrollState state) {
- if (true) {
- // TODO: do something that makes sense
- return;
- }
- int childCount = mChildren.size();
- StackViewState sourceState = new StackViewState();
- ViewState dividerState = new ViewState();
- for (int i = 0; i < childCount; i++) {
- ExpandableNotificationRow child = mChildren.get(i);
- StackViewState viewState = state.getViewStateForView(child);
- sourceState.copyFrom(viewState);
- sourceState.alpha = 0;
- sourceState.yTranslation += mNotificationAppearDistance;
- state.applyState(child, sourceState);
-
- // layout the divider
- View divider = mDividers.get(i);
- dividerState.initFrom(divider);
- dividerState.yTranslation = viewState.yTranslation - mDividerHeight
- + mNotificationAppearDistance;
- dividerState.alpha = 0;
- state.applyViewState(divider, dividerState);
-
- }
+ // TODO: do something that makes sense, like placing the invisible views correctly
+ return;
}
public void startAnimationToState(StackScrollState state, StackStateAnimator stateAnimator,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 36b2810..d5b57ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -16,12 +16,22 @@
package com.android.systemui.statusbar.stack;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.TimeAnimator;
+import android.animation.ValueAnimator;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Pair;
@@ -32,6 +42,7 @@
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import android.widget.OverScroller;
import com.android.systemui.ExpandHelper;
@@ -43,9 +54,8 @@
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
-import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.NotificationOverflowContainer;
-import com.android.systemui.statusbar.SpeedBumpView;
import com.android.systemui.statusbar.StackScrollerDecorView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -64,6 +74,7 @@
implements SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter,
ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener {
+ public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
private static final String TAG = "NotificationStackScrollLayout";
private static final boolean DEBUG = false;
private static final float RUBBER_BAND_FACTOR_NORMAL = 0.35f;
@@ -79,6 +90,7 @@
private SwipeHelper mSwipeHelper;
private boolean mSwipingInProgress;
private int mCurrentStackHeight = Integer.MAX_VALUE;
+ private final Paint mBackgroundPaint = new Paint();
/**
* mCurrentStackHeight is the actual stack height, mLastSetStackHeight is the stack height set
@@ -103,15 +115,13 @@
private float mInitialTouchX;
private float mInitialTouchY;
- private int mSidePaddings;
private Paint mDebugPaint;
private int mContentHeight;
private int mCollapsedSize;
private int mBottomStackSlowDownHeight;
private int mBottomStackPeekSize;
private int mPaddingBetweenElements;
- private int mPaddingBetweenElementsDimmed;
- private int mPaddingBetweenElementsNormal;
+ private int mIncreasedPaddingBetweenElements;
private int mTopPadding;
private int mCollapseSecondCardPadding;
@@ -163,7 +173,6 @@
private boolean mGoToFullShadeNeedsAnimation;
private boolean mIsExpanded = true;
private boolean mChildrenUpdateRequested;
- private SpeedBumpView mSpeedBumpView;
private boolean mIsExpansionChanging;
private boolean mPanelTracking;
private boolean mExpandingNotification;
@@ -183,7 +192,6 @@
*/
private float mMinTopOverScrollToEscape;
private int mIntrinsicPadding;
- private int mNotificationTopPadding;
private float mStackTranslation;
private float mTopPaddingOverflow;
private boolean mDontReportNextOverScroll;
@@ -234,6 +242,45 @@
private NotificationOverflowContainer mOverflowContainer;
private final ArrayList<Pair<ExpandableNotificationRow, Boolean>> mTmpList = new ArrayList<>();
private FalsingManager mFalsingManager;
+ private boolean mAnimationRunning;
+ private ViewTreeObserver.OnPreDrawListener mBackgroundUpdater
+ = new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ // if it needs animation
+ if (!mNeedsAnimation && !mChildrenUpdateRequested) {
+ updateBackground();
+ }
+ return true;
+ }
+ };
+ private Rect mBackgroundBounds = new Rect();
+ private Rect mStartAnimationRect = new Rect();
+ private Rect mEndAnimationRect = new Rect();
+ private Rect mCurrentBounds = new Rect(-1, -1, -1, -1);
+ private boolean mAnimateNextBackgroundBottom;
+ private boolean mAnimateNextBackgroundTop;
+ private ObjectAnimator mBottomAnimator = null;
+ private ObjectAnimator mTopAnimator = null;
+ private ActivatableNotificationView mFirstVisibleBackgroundChild = null;
+ private ActivatableNotificationView mLastVisibleBackgroundChild = null;
+ private int mBgColor;
+ private float mDimAmount;
+ private ValueAnimator mDimAnimator;
+ private Animator.AnimatorListener mDimEndListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mDimAnimator = null;
+ }
+ };
+ private ValueAnimator.AnimatorUpdateListener mDimUpdateListener
+ = new ValueAnimator.AnimatorUpdateListener() {
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ setDimAmount((Float) animation.getAnimatedValue());
+ }
+ };
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -250,6 +297,7 @@
public NotificationStackScrollLayout(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
+ mBgColor = context.getColor(R.color.notification_shade_background_color);
int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height);
int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_max_height);
mExpandHelper = new ExpandHelper(getContext(), this,
@@ -261,18 +309,20 @@
mSwipeHelper.setLongPressListener(mLongPressListener);
mStackScrollAlgorithm = new StackScrollAlgorithm(context);
initView(context);
+ setWillNotDraw(false);
if (DEBUG) {
- setWillNotDraw(false);
mDebugPaint = new Paint();
mDebugPaint.setColor(0xffff0000);
mDebugPaint.setStrokeWidth(2);
mDebugPaint.setStyle(Paint.Style.STROKE);
}
mFalsingManager = FalsingManager.getInstance(context);
+ mBackgroundPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
}
@Override
protected void onDraw(Canvas canvas) {
+ canvas.drawRect(0, mCurrentBounds.top, getWidth(), mCurrentBounds.bottom, mBackgroundPaint);
if (DEBUG) {
int y = mTopPadding;
canvas.drawLine(0, y, getWidth(), y, mDebugPaint);
@@ -288,6 +338,20 @@
}
}
+ private void updateBackgroundDimming() {
+ float alpha = BACKGROUND_ALPHA_DIMMED + (1 - BACKGROUND_ALPHA_DIMMED) * (1.0f - mDimAmount);
+ // We need to manually blend in the background color
+ int scrimColor = mScrimController.getScrimBehindColor();
+ // SRC_OVER blending Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc
+ float alphaInv = 1 - alpha;
+ int color = Color.argb((int) (alpha * 255 + alphaInv * Color.alpha(scrimColor)),
+ (int) (Color.red(mBgColor) + alphaInv * Color.red(scrimColor)),
+ (int) (Color.green(mBgColor) + alphaInv * Color.green(scrimColor)),
+ (int) (Color.blue(mBgColor) + alphaInv * Color.blue(scrimColor)));
+ mBackgroundPaint.setColor(color);
+ invalidate();
+ }
+
private void initView(Context context) {
mScroller = new OverScroller(getContext());
setFocusable(true);
@@ -298,36 +362,23 @@
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
mOverflingDistance = configuration.getScaledOverflingDistance();
-
- mSidePaddings = context.getResources()
- .getDimensionPixelSize(R.dimen.notification_side_padding);
mCollapsedSize = context.getResources()
.getDimensionPixelSize(R.dimen.notification_min_height);
mBottomStackPeekSize = context.getResources()
.getDimensionPixelSize(R.dimen.bottom_stack_peek_amount);
mStackScrollAlgorithm.initView(context);
- mPaddingBetweenElementsDimmed = context.getResources()
- .getDimensionPixelSize(R.dimen.notification_padding_dimmed);
- mPaddingBetweenElementsNormal = context.getResources()
- .getDimensionPixelSize(R.dimen.notification_padding);
- updatePadding(mAmbientState.isDimmed());
+ mPaddingBetweenElements = Math.max(1, context.getResources()
+ .getDimensionPixelSize(R.dimen.notification_divider_height));
+ mIncreasedPaddingBetweenElements = context.getResources()
+ .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
+
+ mBottomStackSlowDownHeight = mStackScrollAlgorithm.getBottomStackSlowDownLength();
mMinTopOverScrollToEscape = getResources().getDimensionPixelSize(
R.dimen.min_top_overscroll_to_qs);
- mNotificationTopPadding = getResources().getDimensionPixelSize(
- R.dimen.notifications_top_padding);
mCollapseSecondCardPadding = getResources().getDimensionPixelSize(
R.dimen.notification_collapse_second_card_padding);
}
- private void updatePadding(boolean dimmed) {
- mPaddingBetweenElements = dimmed && mStackScrollAlgorithm.shouldScaleDimmed()
- ? mPaddingBetweenElementsDimmed
- : mPaddingBetweenElementsNormal;
- mBottomStackSlowDownHeight = mStackScrollAlgorithm.getBottomStackSlowDownLength();
- updateContentHeight();
- notifyHeightChangeListener(null);
- }
-
private void notifyHeightChangeListener(ExpandableView view) {
if (mOnHeightChangedListener != null) {
mOnHeightChangedListener.onHeightChanged(view, false /* needsAnimation */);
@@ -337,10 +388,7 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- int mode = MeasureSpec.getMode(widthMeasureSpec);
- int size = MeasureSpec.getSize(widthMeasureSpec);
- int childMeasureSpec = MeasureSpec.makeMeasureSpec(size - 2 * mSidePaddings, mode);
- measureChildren(childMeasureSpec, heightMeasureSpec);
+ measureChildren(widthMeasureSpec, heightMeasureSpec);
}
@Override
@@ -368,6 +416,7 @@
mRequestViewResizeAnimationOnLayout = false;
}
requestChildrenUpdate();
+ updateFirstAndLastBackgroundViews();
}
private void requestAnimationOnViewResize(ExpandableNotificationRow row) {
@@ -378,18 +427,6 @@
}
public void updateSpeedBumpIndex(int newIndex) {
- int currentIndex = indexOfChild(mSpeedBumpView);
-
- // If we are currently layouted before the new speed bump index, we have to decrease it.
- boolean validIndex = newIndex > 0;
- if (newIndex > getChildCount() - 1) {
- validIndex = false;
- newIndex = -1;
- }
- if (validIndex && currentIndex != newIndex) {
- changeViewPosition(mSpeedBumpView, newIndex);
- }
- updateSpeedBump(validIndex);
mAmbientState.setSpeedBumpIndex(newIndex);
}
@@ -686,8 +723,7 @@
for (int childIdx = 0; childIdx < count; childIdx++) {
ExpandableView slidingChild = (ExpandableView) getChildAt(childIdx);
if (slidingChild.getVisibility() == GONE
- || slidingChild instanceof StackScrollerDecorView
- || slidingChild == mSpeedBumpView) {
+ || slidingChild instanceof StackScrollerDecorView) {
continue;
}
float childTop = slidingChild.getTranslationY();
@@ -714,8 +750,7 @@
for (int childIdx = 0; childIdx < count; childIdx++) {
ExpandableView slidingChild = (ExpandableView) getChildAt(childIdx);
if (slidingChild.getVisibility() == GONE
- || slidingChild instanceof StackScrollerDecorView
- || slidingChild == mSpeedBumpView) {
+ || slidingChild instanceof StackScrollerDecorView) {
continue;
}
float childTop = slidingChild.getTranslationY();
@@ -1412,22 +1447,251 @@
private void updateContentHeight() {
int height = 0;
+ boolean previousNeedsIncreasedPaddings = false;
for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
- if (child.getVisibility() != View.GONE) {
+ ExpandableView expandableView = (ExpandableView) getChildAt(i);
+ if (expandableView.getVisibility() != View.GONE) {
+ boolean needsIncreasedPaddings = expandableView.needsIncreasedPadding();
if (height != 0) {
- // add the padding before this element
- height += mPaddingBetweenElements;
+ int padding = needsIncreasedPaddings || previousNeedsIncreasedPaddings
+ ? mIncreasedPaddingBetweenElements
+ : mPaddingBetweenElements;
+ height += padding;
}
- if (child instanceof ExpandableView) {
- ExpandableView expandableView = (ExpandableView) child;
- height += expandableView.getIntrinsicHeight();
- }
+ previousNeedsIncreasedPaddings = needsIncreasedPaddings;
+ height += expandableView.getIntrinsicHeight();
}
}
mContentHeight = height + mTopPadding;
}
+ private void updateBackground() {
+ if (mAmbientState.isDark()) {
+ return;
+ }
+ updateBackgroundBounds();
+ if (!mCurrentBounds.equals(mBackgroundBounds)) {
+ if (mAnimateNextBackgroundTop || mAnimateNextBackgroundBottom || areBoundsAnimating()) {
+ startBackgroundAnimation();
+ } else {
+ mCurrentBounds.set(mBackgroundBounds);
+ applyCurrentBackgroundBounds();
+ }
+ } else {
+ if (mBottomAnimator != null) {
+ mBottomAnimator.cancel();
+ }
+ if (mTopAnimator != null) {
+ mTopAnimator.cancel();
+ }
+ }
+ mAnimateNextBackgroundBottom = false;
+ mAnimateNextBackgroundTop = false;
+ }
+
+ private boolean areBoundsAnimating() {
+ return mBottomAnimator != null || mTopAnimator != null;
+ }
+
+ private void startBackgroundAnimation() {
+ startBottomAnimation();
+ startTopAnimation();
+ }
+
+ private void startTopAnimation() {
+ int previousEndValue = mEndAnimationRect.top;
+ int newEndValue = mBackgroundBounds.top;
+ ObjectAnimator previousAnimator = mTopAnimator;
+ if (previousAnimator != null && previousEndValue == newEndValue) {
+ return;
+ }
+ if (!mAnimateNextBackgroundTop) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ int previousStartValue = mStartAnimationRect.top;
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ values[0].setIntValues(previousStartValue, newEndValue);
+ mStartAnimationRect.top = previousStartValue;
+ mEndAnimationRect.top = newEndValue;
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ setBackgroundTop(newEndValue);
+ return;
+ }
+ }
+ if (previousAnimator != null) {
+ previousAnimator.cancel();
+ }
+ ObjectAnimator animator = ObjectAnimator.ofInt(this, "backgroundTop",
+ mCurrentBounds.top, newEndValue);
+ Interpolator interpolator = Interpolators.FAST_OUT_SLOW_IN;
+ animator.setInterpolator(interpolator);
+ animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mStartAnimationRect.top = -1;
+ mEndAnimationRect.top = -1;
+ mTopAnimator = null;
+ }
+ });
+ animator.start();
+ mStartAnimationRect.top = mCurrentBounds.top;
+ mEndAnimationRect.top = newEndValue;
+ mTopAnimator = animator;
+ }
+
+ private void startBottomAnimation() {
+ int previousStartValue = mStartAnimationRect.bottom;
+ int previousEndValue = mEndAnimationRect.bottom;
+ int newEndValue = mBackgroundBounds.bottom;
+ ObjectAnimator previousAnimator = mBottomAnimator;
+ if (previousAnimator != null && previousEndValue == newEndValue) {
+ return;
+ }
+ if (!mAnimateNextBackgroundBottom) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ values[0].setIntValues(previousStartValue, newEndValue);
+ mStartAnimationRect.bottom = previousStartValue;
+ mEndAnimationRect.bottom = newEndValue;
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ setBackgroundBottom(newEndValue);
+ return;
+ }
+ }
+ if (previousAnimator != null) {
+ previousAnimator.cancel();
+ }
+ ObjectAnimator animator = ObjectAnimator.ofInt(this, "backgroundBottom",
+ mCurrentBounds.bottom, newEndValue);
+ Interpolator interpolator = Interpolators.FAST_OUT_SLOW_IN;
+ animator.setInterpolator(interpolator);
+ animator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mStartAnimationRect.bottom = -1;
+ mEndAnimationRect.bottom = -1;
+ mBottomAnimator = null;
+ }
+ });
+ animator.start();
+ mStartAnimationRect.bottom = mCurrentBounds.bottom;
+ mEndAnimationRect.bottom = newEndValue;
+ mBottomAnimator = animator;
+ }
+
+ private void setBackgroundTop(int top) {
+ mCurrentBounds.top = top;
+ applyCurrentBackgroundBounds();
+ }
+
+ public void setBackgroundBottom(int bottom) {
+ mCurrentBounds.bottom = bottom;
+ applyCurrentBackgroundBounds();
+ }
+
+ private void applyCurrentBackgroundBounds() {
+ mScrimController.setExcludedBackgroundArea(mCurrentBounds);
+ invalidate();
+ }
+
+ /**
+ * Update the background bounds to the new desired bounds
+ */
+ private void updateBackgroundBounds() {
+ mBackgroundBounds.left = (int) getX();
+ mBackgroundBounds.right = (int) (getX() + getWidth());
+ if (!mIsExpanded) {
+ mBackgroundBounds.top = 0;
+ mBackgroundBounds.bottom = 0;
+ }
+ ActivatableNotificationView firstView = mFirstVisibleBackgroundChild;
+ int top = 0;
+ if (firstView != null) {
+ int finalTranslationY = (int) StackStateAnimator.getFinalTranslationY(firstView);
+ if (mAnimateNextBackgroundTop
+ || mTopAnimator == null && mCurrentBounds.top == finalTranslationY
+ || mTopAnimator != null && mEndAnimationRect.top == finalTranslationY) {
+ // we're ending up at the same location as we are now, lets just skip the animation
+ top = finalTranslationY;
+ } else {
+ top = (int) firstView.getTranslationY();
+ }
+ }
+ ActivatableNotificationView lastView = mLastVisibleBackgroundChild;
+ int bottom = 0;
+ if (lastView != null) {
+ int finalTranslationY = (int) StackStateAnimator.getFinalTranslationY(lastView);
+ int finalHeight = StackStateAnimator.getFinalActualHeight(lastView);
+ int finalBottom = finalTranslationY + finalHeight;
+ finalBottom = Math.min(finalBottom, getHeight());
+ if (mAnimateNextBackgroundBottom
+ || mBottomAnimator == null && mCurrentBounds.bottom == finalBottom
+ || mBottomAnimator != null && mEndAnimationRect.bottom == finalBottom) {
+ // we're ending up at the same location as we are now, lets just skip the animation
+ bottom = finalBottom;
+ } else {
+ bottom = (int) (lastView.getTranslationY() + lastView.getActualHeight());
+ bottom = Math.min(bottom, getHeight());
+ }
+ }
+ mBackgroundBounds.top = top;
+ mBackgroundBounds.bottom = bottom;
+ }
+
+ private ActivatableNotificationView getFirstPinnedHeadsUp() {
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = getChildAt(i);
+ if (child.getVisibility() != View.GONE
+ && child instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ if (row.isPinned()) {
+ return row;
+ }
+ }
+ }
+ return null;
+ }
+
+ private ActivatableNotificationView getLastChildWithBackground() {
+ int childCount = getChildCount();
+ for (int i = childCount - 1; i >= 0; i--) {
+ View child = getChildAt(i);
+ if (child.getVisibility() != View.GONE
+ && child instanceof ActivatableNotificationView) {
+ return (ActivatableNotificationView) child;
+ }
+ }
+ return null;
+ }
+
+ private ActivatableNotificationView getFirstChildWithBackground() {
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = getChildAt(i);
+ if (child.getVisibility() != View.GONE
+ && child instanceof ActivatableNotificationView) {
+ return (ActivatableNotificationView) child;
+ }
+ }
+ return null;
+ }
+
/**
* Fling the scroll view
*
@@ -1489,7 +1753,7 @@
*/
public void updateTopPadding(float qsHeight, int scrollY, boolean animate,
boolean ignoreIntrinsicPadding) {
- float start = qsHeight - scrollY + mNotificationTopPadding;
+ float start = qsHeight - scrollY;
float stackHeight = getHeight() - start;
int minStackHeight = getMinStackHeight();
if (stackHeight <= minStackHeight) {
@@ -1505,10 +1769,6 @@
setStackHeight(mLastSetStackHeight);
}
- public int getNotificationTopPadding() {
- return mNotificationTopPadding;
- }
-
public int getMinStackHeight() {
final ExpandableView firstChild = getFirstChildNotGone();
final int firstChildMinHeight = firstChild != null ? firstChild.getMinHeight()
@@ -1655,7 +1915,7 @@
}
((ExpandableView) child).setOnHeightChangedListener(null);
mCurrentStackScrollState.removeViewStateForView(child);
- updateScrollStateForRemovedChild(child);
+ updateScrollStateForRemovedChild((ExpandableView) child);
boolean animationGenerated = generateRemoveAnimation(child);
if (animationGenerated && !mSwipedOutViews.contains(child)) {
// Add this view to an overlay in order to ensure that it will still be temporary
@@ -1754,9 +2014,12 @@
*
* @param removedChild the removed child
*/
- private void updateScrollStateForRemovedChild(View removedChild) {
+ private void updateScrollStateForRemovedChild(ExpandableView removedChild) {
int startingPosition = getPositionInLinearLayout(removedChild);
- int childHeight = getIntrinsicHeight(removedChild) + mPaddingBetweenElements;
+ int padding = removedChild.needsIncreasedPadding()
+ ? mIncreasedPaddingBetweenElements :
+ mPaddingBetweenElements;
+ int childHeight = getIntrinsicHeight(removedChild) + padding;
int endPosition = startingPosition + childHeight;
if (endPosition <= mOwnScrollY) {
// This child is fully scrolled of the top, so we have to deduct its height from the
@@ -1779,16 +2042,25 @@
private int getPositionInLinearLayout(View requestedChild) {
int position = 0;
+ boolean previousNeedsIncreasedPaddings = false;
for (int i = 0; i < getChildCount(); i++) {
- View child = getChildAt(i);
+ ExpandableView child = (ExpandableView) getChildAt(i);
+ boolean notGone = child.getVisibility() != View.GONE;
+ if (notGone) {
+ boolean needsIncreasedPaddings = child.needsIncreasedPadding();
+ if (position != 0) {
+ int padding = needsIncreasedPaddings || previousNeedsIncreasedPaddings
+ ? mIncreasedPaddingBetweenElements :
+ mPaddingBetweenElements;
+ position += padding;
+ }
+ previousNeedsIncreasedPaddings = needsIncreasedPaddings;
+ }
if (child == requestedChild) {
return position;
}
- if (child.getVisibility() != View.GONE) {
+ if (notGone) {
position += getIntrinsicHeight(child);
- if (i < getChildCount()-1) {
- position += mPaddingBetweenElements;
- }
}
}
return 0;
@@ -1800,6 +2072,20 @@
onViewAddedInternal(child);
}
+ private void updateFirstAndLastBackgroundViews() {
+ ActivatableNotificationView firstChild = getFirstChildWithBackground();
+ ActivatableNotificationView lastChild = getLastChildWithBackground();
+ if (mAnimationsEnabled && mIsExpanded) {
+ mAnimateNextBackgroundTop = firstChild != mFirstVisibleBackgroundChild;
+ mAnimateNextBackgroundBottom = lastChild != mLastVisibleBackgroundChild;
+ } else {
+ mAnimateNextBackgroundTop = false;
+ mAnimateNextBackgroundBottom = false;
+ }
+ mFirstVisibleBackgroundChild = firstChild;
+ mLastVisibleBackgroundChild = lastChild;
+ }
+
private void onViewAddedInternal(View child) {
updateHideSensitiveForChild(child);
mStackScrollAlgorithm.notifyChildrenChanged(this);
@@ -1910,7 +2196,9 @@
if (!mAnimationEvents.isEmpty() || isCurrentlyAnimating()) {
mStateAnimator.startAnimationForEvents(mAnimationEvents, mCurrentStackScrollState,
mGoToFullShadeDelay);
+ setAnimationRunning(true);
mAnimationEvents.clear();
+ updateBackground();
} else {
applyCurrentState();
}
@@ -2396,6 +2684,7 @@
}
public void onChildAnimationFinished() {
+ setAnimationRunning(false);
requestChildrenUpdate();
runAnimationFinishedRunnables();
clearViewOverlays();
@@ -2418,16 +2707,38 @@
* See {@link AmbientState#setDimmed}.
*/
public void setDimmed(boolean dimmed, boolean animate) {
- mStackScrollAlgorithm.setDimmed(dimmed);
mAmbientState.setDimmed(dimmed);
- updatePadding(dimmed);
if (animate && mAnimationsEnabled) {
mDimmedNeedsAnimation = true;
mNeedsAnimation = true;
+ animateDimmed(dimmed);
+ } else {
+ setDimAmount(dimmed ? 1.0f : 0.0f);
}
requestChildrenUpdate();
}
+ private void setDimAmount(float dimAmount) {
+ mDimAmount = dimAmount;
+ updateBackgroundDimming();
+ }
+
+ private void animateDimmed(boolean dimmed) {
+ if (mDimAnimator != null) {
+ mDimAnimator.cancel();
+ }
+ float target = dimmed ? 1.0f : 0.0f;
+ if (target == mDimAmount) {
+ return;
+ }
+ mDimAnimator = TimeAnimator.ofFloat(mDimAmount, target);
+ mDimAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_DIMMED_ACTIVATED);
+ mDimAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ mDimAnimator.addListener(mDimEndListener);
+ mDimAnimator.addUpdateListener(mDimUpdateListener);
+ mDimAnimator.start();
+ }
+
public void setHideSensitive(boolean hideSensitive, boolean animate) {
if (hideSensitive != mAmbientState.isHideSensitive()) {
int childCount = getChildCount();
@@ -2466,30 +2777,10 @@
mListener.onChildLocationsChanged(this);
}
runAnimationFinishedRunnables();
- }
-
- public void setSpeedBumpView(SpeedBumpView speedBumpView) {
- mSpeedBumpView = speedBumpView;
- addView(speedBumpView);
- }
-
- private void updateSpeedBump(boolean visible) {
- boolean notGoneBefore = mSpeedBumpView.getVisibility() != GONE;
- if (visible != notGoneBefore) {
- int newVisibility = visible ? VISIBLE : GONE;
- mSpeedBumpView.setVisibility(newVisibility);
- if (visible) {
- // Make invisible to ensure that the appear animation is played.
- mSpeedBumpView.setInvisible();
- } else {
- // TODO: This doesn't really work, because the view is already set to GONE above.
- generateRemoveAnimation(mSpeedBumpView);
- }
- }
+ updateBackground();
}
public void goToFullShade(long delay) {
- updateSpeedBump(true /* visibility */);
mDismissView.setInvisible();
mEmptyShadeView.setInvisible();
mGoToFullShadeNeedsAnimation = true;
@@ -2533,6 +2824,14 @@
mNeedsAnimation = true;
}
requestChildrenUpdate();
+ if (dark) {
+ setWillNotDraw(!DEBUG);
+ mScrimController.setExcludedBackgroundArea(null);
+ } else {
+ updateBackground();
+ setWillNotDraw(false);
+ // TODO: fade in background
+ }
}
private int findDarkAnimationOriginIndex(@Nullable PointF screenLocation) {
@@ -2731,7 +3030,7 @@
}
public int getDismissViewHeight() {
- int height = mDismissView.getHeight() + mPaddingBetweenElementsNormal;
+ int height = mDismissView.getHeight() + mPaddingBetweenElements;
// Hack: Accommodate for additional distance when we only have one notification and the
// dismiss all button.
@@ -2881,6 +3180,12 @@
public void setScrimController(ScrimController scrimController) {
mScrimController = scrimController;
+ mScrimController.setScrimBehindChangeRunnable(new Runnable() {
+ @Override
+ public void run() {
+ updateBackgroundDimming();
+ }
+ });
}
public void forceNoOverlappingRendering(boolean force) {
@@ -2892,6 +3197,17 @@
return !mForceNoOverlappingRendering && super.hasOverlappingRendering();
}
+ public void setAnimationRunning(boolean animationRunning) {
+ if (animationRunning != mAnimationRunning) {
+ if (animationRunning) {
+ getViewTreeObserver().addOnPreDrawListener(mBackgroundUpdater);
+ } else {
+ getViewTreeObserver().removeOnPreDrawListener(mBackgroundUpdater);
+ }
+ mAnimationRunning = animationRunning;
+ }
+ }
+
/**
* A listener that is notified when some child locations might have changed.
*/
@@ -2937,7 +3253,7 @@
// ANIMATION_TYPE_ADD
new AnimationFilter()
- .animateAlpha()
+ .animateShadowAlpha()
.animateHeight()
.animateTopInset()
.animateY()
@@ -2946,7 +3262,7 @@
// ANIMATION_TYPE_REMOVE
new AnimationFilter()
- .animateAlpha()
+ .animateShadowAlpha()
.animateHeight()
.animateTopInset()
.animateY()
@@ -2955,7 +3271,7 @@
// ANIMATION_TYPE_REMOVE_SWIPED_OUT
new AnimationFilter()
- .animateAlpha()
+ .animateShadowAlpha()
.animateHeight()
.animateTopInset()
.animateY()
@@ -2964,37 +3280,35 @@
// ANIMATION_TYPE_TOP_PADDING_CHANGED
new AnimationFilter()
- .animateAlpha()
+ .animateShadowAlpha()
.animateHeight()
.animateTopInset()
.animateY()
.animateDimmed()
- .animateScale()
.animateZ(),
// ANIMATION_TYPE_START_DRAG
new AnimationFilter()
- .animateAlpha(),
+ .animateShadowAlpha(),
// ANIMATION_TYPE_SNAP_BACK
new AnimationFilter()
- .animateAlpha()
+ .animateShadowAlpha()
.animateHeight(),
// ANIMATION_TYPE_ACTIVATED_CHILD
new AnimationFilter()
- .animateScale()
- .animateAlpha(),
+ .animateZ(),
// ANIMATION_TYPE_DIMMED
new AnimationFilter()
.animateY()
- .animateScale()
.animateDimmed(),
// ANIMATION_TYPE_CHANGE_POSITION
new AnimationFilter()
- .animateAlpha()
+ .animateAlpha() // maybe the children change positions
+ .animateShadowAlpha()
.animateHeight()
.animateTopInset()
.animateY()
@@ -3007,12 +3321,11 @@
// ANIMATION_TYPE_GO_TO_FULL_SHADE
new AnimationFilter()
- .animateAlpha()
+ .animateShadowAlpha()
.animateHeight()
.animateTopInset()
.animateY()
.animateDimmed()
- .animateScale()
.animateZ()
.hasDelays(),
@@ -3022,7 +3335,7 @@
// ANIMATION_TYPE_VIEW_RESIZE
new AnimationFilter()
- .animateAlpha()
+ .animateShadowAlpha()
.animateHeight()
.animateTopInset()
.animateY()
@@ -3031,6 +3344,7 @@
// ANIMATION_TYPE_GROUP_EXPANSION_CHANGED
new AnimationFilter()
.animateAlpha()
+ .animateShadowAlpha()
.animateHeight()
.animateTopInset()
.animateY()
@@ -3038,7 +3352,7 @@
// ANIMATION_TYPE_HEADS_UP_APPEAR
new AnimationFilter()
- .animateAlpha()
+ .animateShadowAlpha()
.animateHeight()
.animateTopInset()
.animateY()
@@ -3046,7 +3360,7 @@
// ANIMATION_TYPE_HEADS_UP_DISAPPEAR
new AnimationFilter()
- .animateAlpha()
+ .animateShadowAlpha()
.animateHeight()
.animateTopInset()
.animateY()
@@ -3054,7 +3368,7 @@
// ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
new AnimationFilter()
- .animateAlpha()
+ .animateShadowAlpha()
.animateHeight()
.animateTopInset()
.animateY()
@@ -3063,7 +3377,7 @@
// ANIMATION_TYPE_HEADS_UP_OTHER
new AnimationFilter()
- .animateAlpha()
+ .animateShadowAlpha()
.animateHeight()
.animateTopInset()
.animateY()
@@ -3072,8 +3386,8 @@
// ANIMATION_TYPE_EVERYTHING
new AnimationFilter()
.animateAlpha()
+ .animateShadowAlpha()
.animateDark()
- .animateScale()
.animateDimmed()
.animateHideSensitive()
.animateHeight()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 822012d..f6959f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.stack;
import android.content.Context;
-import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -27,6 +26,7 @@
import com.android.systemui.statusbar.ExpandableView;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
/**
@@ -41,15 +41,13 @@
private static final int MAX_ITEMS_IN_BOTTOM_STACK = 3;
private static final int MAX_ITEMS_IN_TOP_STACK = 3;
- public static final float DIMMED_SCALE = 0.98f;
-
private int mPaddingBetweenElements;
+ private int mIncreasedPaddingBetweenElements;
private int mCollapsedSize;
private int mTopStackPeekSize;
private int mBottomStackPeekSize;
private int mZDistanceBetweenElements;
private int mZBasicHeight;
- private int mRoundedRectCornerRadius;
private StackIndentationFunctor mTopStackIndentationFunctor;
private StackIndentationFunctor mBottomStackIndentationFunctor;
@@ -61,16 +59,11 @@
private ExpandableView mFirstChildWhileExpanding;
private boolean mExpandedOnStart;
private int mTopStackTotalSize;
- private int mPaddingBetweenElementsDimmed;
- private int mPaddingBetweenElementsNormal;
- private int mNotificationsTopPadding;
private int mBottomStackSlowDownLength;
private int mTopStackSlowDownLength;
private int mCollapseSecondCardPadding;
- private boolean mScaleDimmed;
private ExpandableView mFirstChild;
private int mFirstChildMinHeight;
- private boolean mDimmed;
public StackScrollAlgorithm(Context context) {
initView(context);
@@ -82,9 +75,6 @@
}
private void updatePadding() {
- mPaddingBetweenElements = mDimmed && mScaleDimmed
- ? mPaddingBetweenElementsDimmed
- : mPaddingBetweenElementsNormal;
mTopStackTotalSize = mTopStackSlowDownLength + mPaddingBetweenElements
+ mTopStackPeekSize;
mTopStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
@@ -104,35 +94,25 @@
}
private void initConstants(Context context) {
- mPaddingBetweenElementsDimmed = context.getResources()
- .getDimensionPixelSize(R.dimen.notification_padding_dimmed);
- mPaddingBetweenElementsNormal = context.getResources()
- .getDimensionPixelSize(R.dimen.notification_padding);
- mNotificationsTopPadding = context.getResources()
- .getDimensionPixelSize(R.dimen.notifications_top_padding);
+ mPaddingBetweenElements = Math.max(1, context.getResources()
+ .getDimensionPixelSize(R.dimen.notification_divider_height));
+ mIncreasedPaddingBetweenElements = context.getResources()
+ .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
mCollapsedSize = context.getResources()
.getDimensionPixelSize(R.dimen.notification_min_height);
mTopStackPeekSize = context.getResources()
.getDimensionPixelSize(R.dimen.top_stack_peek_amount);
mBottomStackPeekSize = context.getResources()
.getDimensionPixelSize(R.dimen.bottom_stack_peek_amount);
- mZDistanceBetweenElements = context.getResources()
- .getDimensionPixelSize(R.dimen.z_distance_between_notifications);
+ mZDistanceBetweenElements = Math.max(1, context.getResources()
+ .getDimensionPixelSize(R.dimen.z_distance_between_notifications));
mZBasicHeight = (MAX_ITEMS_IN_BOTTOM_STACK + 1) * mZDistanceBetweenElements;
mBottomStackSlowDownLength = context.getResources()
.getDimensionPixelSize(R.dimen.bottom_stack_slow_down_length);
mTopStackSlowDownLength = context.getResources()
.getDimensionPixelSize(R.dimen.top_stack_slow_down_length);
- mRoundedRectCornerRadius = context.getResources().getDimensionPixelSize(
- R.dimen.notification_material_rounded_rect_radius);
mCollapseSecondCardPadding = context.getResources().getDimensionPixelSize(
R.dimen.notification_collapse_second_card_padding);
- mScaleDimmed = context.getResources().getDisplayMetrics().densityDpi
- >= DisplayMetrics.DENSITY_420;
- }
-
- public boolean shouldScaleDimmed() {
- return mScaleDimmed;
}
public void getStackScrollState(AmbientState ambientState, StackScrollState resultState) {
@@ -159,7 +139,7 @@
scrollY = Math.max(0, scrollY);
algorithmState.scrollY = (int) (scrollY + mFirstChildMinHeight + bottomOverScroll);
- updateVisibleChildren(resultState, algorithmState);
+ initAlgorithmState(resultState, algorithmState);
// Phase 1:
findNumberOfItemsInTopStackAndUpdateState(resultState, algorithmState, ambientState);
@@ -212,8 +192,8 @@
for (int i = 0; i < childCount; i++) {
ExpandableView child = algorithmState.visibleChildren.get(i);
StackViewState state = resultState.getViewStateForView(child);
- float newYTranslation = state.yTranslation + state.height * (1f - state.scale) / 2f;
- float newHeight = state.height * state.scale;
+ float newYTranslation = state.yTranslation;
+ float newHeight = state.height;
// apply clipping and shadow
float newNotificationEnd = newYTranslation + newHeight;
@@ -225,16 +205,6 @@
} else {
clipHeight = newNotificationEnd - previousNotificationEnd;
clipHeight = Math.max(0.0f, clipHeight);
- if (clipHeight != 0.0f) {
-
- // In the unlocked shade we have to clip a little bit higher because of the rounded
- // corners of the notifications, but only if we are not fully overlapped by
- // the top card.
- float clippingCorrection = state.dimmed
- ? 0
- : mRoundedRectCornerRadius * state.scale;
- clipHeight += clippingCorrection;
- }
}
updateChildClippingAndBackground(state, newHeight, clipHeight,
@@ -252,7 +222,7 @@
} else {
previousNotificationIsSwiped = ambientState.getDraggedViews().contains(child);
previousNotificationEnd = newNotificationEnd;
- previousNotificationStart = newYTranslation + state.clipTopAmount * state.scale;
+ previousNotificationStart = newYTranslation + state.clipTopAmount;
}
}
}
@@ -276,13 +246,13 @@
float clipHeight, float backgroundHeight) {
if (realHeight > clipHeight) {
// Rather overlap than create a hole.
- state.topOverLap = (int) Math.floor((realHeight - clipHeight) / state.scale);
+ state.topOverLap = (int) Math.floor(realHeight - clipHeight);
} else {
state.topOverLap = 0;
}
if (realHeight > backgroundHeight) {
// Rather overlap than create a hole.
- state.clipTopAmount = (int) Math.floor((realHeight - backgroundHeight) / state.scale);
+ state.clipTopAmount = (int) Math.floor(realHeight - backgroundHeight);
} else {
state.clipTopAmount = 0;
}
@@ -305,9 +275,6 @@
childViewState.dark = dark;
childViewState.hideSensitive = hideSensitive;
boolean isActivatedChild = activatedChild == child;
- childViewState.scale = !mScaleDimmed || !dimmed || isActivatedChild
- ? 1.0f
- : DIMMED_SCALE;
if (dimmed && isActivatedChild) {
childViewState.zTranslation += 2.0f * mZDistanceBetweenElements;
}
@@ -331,7 +298,8 @@
nextChild);
// The child below the dragged one must be fully visible
if (ambientState.isShadeExpanded()) {
- viewState.alpha = 1;
+ viewState.shadowAlpha = 1;
+ viewState.hidden = false;
}
}
@@ -344,19 +312,28 @@
}
/**
- * Update the visible children on the state.
+ * Initialize the algorithm state like updating the visible children.
*/
- private void updateVisibleChildren(StackScrollState resultState,
+ private void initAlgorithmState(StackScrollState resultState,
StackScrollAlgorithmState state) {
ViewGroup hostView = resultState.getHostView();
int childCount = hostView.getChildCount();
state.visibleChildren.clear();
state.visibleChildren.ensureCapacity(childCount);
+ state.increasedPaddingSet.clear();
int notGoneIndex = 0;
+ ExpandableView lastView = null;
for (int i = 0; i < childCount; i++) {
ExpandableView v = (ExpandableView) hostView.getChildAt(i);
if (v.getVisibility() != View.GONE) {
notGoneIndex = updateNotGoneIndex(resultState, state, notGoneIndex, v);
+ boolean needsIncreasedPadding = v.needsIncreasedPadding();
+ if (needsIncreasedPadding) {
+ state.increasedPaddingSet.add(v);
+ if (lastView != null) {
+ state.increasedPaddingSet.add(lastView);
+ }
+ }
if (v instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
@@ -374,6 +351,7 @@
}
}
}
+ lastView = v;
}
}
}
@@ -414,15 +392,17 @@
int numberOfElementsCompletelyIn = algorithmState.partialInTop == 1.0f
? algorithmState.lastTopStackIndex
: (int) algorithmState.itemsInTopStack;
+ int paddingAfterChild;
for (int i = 0; i < childCount; i++) {
ExpandableView child = algorithmState.visibleChildren.get(i);
StackViewState childViewState = resultState.getViewStateForView(child);
childViewState.location = StackViewState.LOCATION_UNKNOWN;
+ paddingAfterChild = getPaddingAfterChild(algorithmState, child);
int childHeight = getMaxAllowedChildHeight(child);
int minHeight = child.getMinHeight();
float yPositionInScrollViewAfterElement = yPositionInScrollView
+ childHeight
- + mPaddingBetweenElements;
+ + paddingAfterChild;
float scrollOffset = yPositionInScrollView - algorithmState.scrollY +
mFirstChildMinHeight;
@@ -437,20 +417,20 @@
// The y position after this element
float nextYPosition = currentYPosition + childHeight +
- mPaddingBetweenElements;
+ paddingAfterChild;
if (i <= algorithmState.lastTopStackIndex) {
// Case 1:
// We are in the top Stack
- updateStateForTopStackChild(algorithmState,
+ updateStateForTopStackChild(algorithmState, child,
numberOfElementsCompletelyIn, i, childHeight, childViewState, scrollOffset);
clampPositionToTopStackEnd(childViewState, childHeight);
// check if we are overlapping with the bottom stack
- if (childViewState.yTranslation + childHeight + mPaddingBetweenElements
+ if (childViewState.yTranslation + childHeight + paddingAfterChild
>= bottomStackStart && !mIsExpansionChanging && i != 0) {
// we just collapse this element slightly
- int newSize = (int) Math.max(bottomStackStart - mPaddingBetweenElements -
+ int newSize = (int) Math.max(bottomStackStart - paddingAfterChild -
childViewState.yTranslation, minHeight);
childViewState.height = newSize;
updateStateForChildTransitioningInBottom(algorithmState, bottomStackStart,
@@ -466,7 +446,7 @@
// According to the regular scroll view we are fully translated out of the
// bottom of the screen so we are fully in the bottom stack
updateStateForChildFullyInBottomStack(algorithmState,
- bottomStackStart, childViewState, minHeight, ambientState);
+ bottomStackStart, childViewState, minHeight, ambientState, child);
} else {
// According to the regular scroll view we are currently translating out of /
// into the bottom of the screen
@@ -483,7 +463,8 @@
// The first card is always rendered.
if (i == 0) {
- childViewState.alpha = 1.0f;
+ childViewState.hidden = false;
+ childViewState.shadowAlpha = 1.0f;
childViewState.yTranslation = Math.max(
mFirstChildMinHeight - algorithmState.scrollY, 0);
if (childViewState.yTranslation + childViewState.height
@@ -497,7 +478,7 @@
if (childViewState.location == StackViewState.LOCATION_UNKNOWN) {
Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
}
- currentYPosition = childViewState.yTranslation + childHeight + mPaddingBetweenElements;
+ currentYPosition = childViewState.yTranslation + childHeight + paddingAfterChild;
yPositionInScrollView = yPositionInScrollViewAfterElement;
childViewState.yTranslation += ambientState.getTopPadding()
@@ -506,6 +487,13 @@
updateHeadsUpStates(resultState, algorithmState, ambientState);
}
+ private int getPaddingAfterChild(StackScrollAlgorithmState algorithmState,
+ ExpandableView child) {
+ return algorithmState.increasedPaddingSet.contains(child)
+ ? mIncreasedPaddingBetweenElements
+ : mPaddingBetweenElements;
+ }
+
private void updateHeadsUpStates(StackScrollState resultState,
StackScrollAlgorithmState algorithmState, AmbientState ambientState) {
int childCount = algorithmState.visibleChildren.size();
@@ -530,8 +518,7 @@
bottomPosition);
}
if (row.isPinned()) {
- childState.yTranslation = Math.max(childState.yTranslation,
- mNotificationsTopPadding);
+ childState.yTranslation = Math.max(childState.yTranslation, 0);
childState.height = Math.max(row.getIntrinsicHeight(), childState.height);
if (!isTopEntry) {
// Ensure that a headsUp doesn't vertically extend further than the heads-up at
@@ -610,7 +597,7 @@
// This is the transitioning element on top of bottom stack, calculate how far we are in.
algorithmState.partialInBottom = 1.0f - (
(transitioningPositionStart - currentYPosition) / (childHeight +
- mPaddingBetweenElements));
+ getPaddingAfterChild(algorithmState, child)));
// the offset starting at the transitionPosition of the bottom stack
float offset = mBottomStackIndentationFunctor.getValue(algorithmState.partialInBottom);
@@ -618,12 +605,12 @@
int newHeight = childHeight;
if (childHeight > child.getMinHeight()) {
newHeight = (int) Math.max(Math.min(transitioningPositionStart + offset -
- mPaddingBetweenElements - currentYPosition, childHeight),
+ getPaddingAfterChild(algorithmState, child) - currentYPosition, childHeight),
child.getMinHeight());
childViewState.height = newHeight;
}
childViewState.yTranslation = transitioningPositionStart + offset - newHeight
- - mPaddingBetweenElements;
+ - getPaddingAfterChild(algorithmState, child);
// We want at least to be at the end of the top stack when collapsing
clampPositionToTopStackEnd(childViewState, newHeight);
@@ -632,22 +619,23 @@
private void updateStateForChildFullyInBottomStack(StackScrollAlgorithmState algorithmState,
float transitioningPositionStart, StackViewState childViewState,
- int minHeight, AmbientState ambientState) {
+ int minHeight, AmbientState ambientState, ExpandableView child) {
float currentYPosition;
algorithmState.itemsInBottomStack += 1.0f;
if (algorithmState.itemsInBottomStack < MAX_ITEMS_IN_BOTTOM_STACK) {
// We are visually entering the bottom stack
currentYPosition = transitioningPositionStart
+ mBottomStackIndentationFunctor.getValue(algorithmState.itemsInBottomStack)
- - mPaddingBetweenElements;
+ - getPaddingAfterChild(algorithmState, child);
childViewState.location = StackViewState.LOCATION_BOTTOM_STACK_PEEKING;
} else {
// we are fully inside the stack
if (algorithmState.itemsInBottomStack > MAX_ITEMS_IN_BOTTOM_STACK + 2) {
- childViewState.alpha = 0.0f;
+ childViewState.hidden = true;
+ childViewState.shadowAlpha = 0.0f;
} else if (algorithmState.itemsInBottomStack
> MAX_ITEMS_IN_BOTTOM_STACK + 1) {
- childViewState.alpha = 1.0f - algorithmState.partialInBottom;
+ childViewState.shadowAlpha = 1.0f - algorithmState.partialInBottom;
}
childViewState.location = StackViewState.LOCATION_BOTTOM_STACK_HIDDEN;
currentYPosition = ambientState.getInnerHeight();
@@ -658,7 +646,7 @@
}
private void updateStateForTopStackChild(StackScrollAlgorithmState algorithmState,
- int numberOfElementsCompletelyIn, int i, int childHeight,
+ ExpandableView child, int numberOfElementsCompletelyIn, int i, int childHeight,
StackViewState childViewState, float scrollOffset) {
@@ -669,10 +657,11 @@
if (paddedIndex >= 0) {
// We are currently visually entering the top stack
- float distanceToStack = (childHeight + mPaddingBetweenElements)
+ float distanceToStack = (childHeight + getPaddingAfterChild(algorithmState, child))
- algorithmState.scrolledPixelsTop;
if (i == algorithmState.lastTopStackIndex
- && distanceToStack > (mTopStackTotalSize + mPaddingBetweenElements)) {
+ && distanceToStack > (mTopStackTotalSize
+ + getPaddingAfterChild(algorithmState, child))) {
// Child is currently translating into stack but not yet inside slow down zone.
// Handle it like the regular scrollview.
@@ -682,7 +671,8 @@
float numItemsBefore;
if (i == algorithmState.lastTopStackIndex) {
numItemsBefore = 1.0f
- - (distanceToStack / (mTopStackTotalSize + mPaddingBetweenElements));
+ - (distanceToStack / (mTopStackTotalSize
+ + getPaddingAfterChild(algorithmState, child)));
} else {
numItemsBefore = algorithmState.itemsInTopStack - i;
}
@@ -694,10 +684,11 @@
childViewState.location = StackViewState.LOCATION_TOP_STACK_PEEKING;
} else {
if (paddedIndex == -1) {
- childViewState.alpha = 1.0f - algorithmState.partialInTop;
+ childViewState.shadowAlpha = 1.0f - algorithmState.partialInTop;
} else {
// We are hidden behind the top card and faded out, so we can hide ourselves.
- childViewState.alpha = 0.0f;
+ childViewState.hidden = true;
+ childViewState.shadowAlpha = 0.0f;
}
childViewState.yTranslation = mFirstChildMinHeight - childHeight;
childViewState.location = StackViewState.LOCATION_TOP_STACK_HIDDEN;
@@ -718,15 +709,15 @@
// The y Position if the element would be in a regular scrollView
float yPositionInScrollView = 0.0f;
int childCount = algorithmState.visibleChildren.size();
-
// find the number of elements in the top stack.
for (int i = 0; i < childCount; i++) {
ExpandableView child = algorithmState.visibleChildren.get(i);
StackViewState childViewState = resultState.getViewStateForView(child);
int childHeight = getMaxAllowedChildHeight(child);
+ int paddingAfterChild = getPaddingAfterChild(algorithmState, child);
float yPositionInScrollViewAfterElement = yPositionInScrollView
+ childHeight
- + mPaddingBetweenElements;
+ + paddingAfterChild;
if (yPositionInScrollView < algorithmState.scrollY) {
if (i == 0 && algorithmState.scrollY <= mFirstChildMinHeight) {
@@ -754,7 +745,7 @@
algorithmState.scrolledPixelsTop = algorithmState.scrollY
- yPositionInScrollView;
algorithmState.partialInTop = (algorithmState.scrolledPixelsTop) / (childHeight
- + mPaddingBetweenElements);
+ + paddingAfterChild);
// Our element can be expanded, so this can get negative
algorithmState.partialInTop = Math.max(0.0f, algorithmState.partialInTop);
@@ -763,7 +754,7 @@
if (i == 0) {
// If it is expanded we have to collapse it to a new size
float newSize = yPositionInScrollViewAfterElement
- - mPaddingBetweenElements
+ - paddingAfterChild
- algorithmState.scrollY + mFirstChildMinHeight;
newSize = Math.max(mFirstChildMinHeight, newSize);
algorithmState.itemsInTopStack = 1.0f;
@@ -917,11 +908,6 @@
}
}
- public void setDimmed(boolean dimmed) {
- mDimmed = dimmed;
- updatePadding();
- }
-
public void onReset(ExpandableView view) {
if (view.equals(mFirstChildWhileExpanding)) {
updateFirstChildMaxSizeToMaxHeight();
@@ -969,6 +955,11 @@
* The children from the host view which are not gone.
*/
public final ArrayList<ExpandableView> visibleChildren = new ArrayList<ExpandableView>();
+
+ /**
+ * The children from the host that need an increased padding after them.
+ */
+ public final HashSet<ExpandableView> increasedPaddingSet = new HashSet<>();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index e155d70..1fedc1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -25,7 +25,6 @@
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
-import com.android.systemui.statusbar.SpeedBumpView;
import java.util.HashMap;
import java.util.List;
@@ -83,8 +82,10 @@
// initialize with the default values of the view
viewState.height = view.getIntrinsicHeight();
viewState.gone = view.getVisibility() == View.GONE;
- viewState.alpha = 1;
+ viewState.alpha = 1f;
+ viewState.shadowAlpha = 1f;
viewState.notGoneIndex = -1;
+ viewState.hidden = false;
}
public StackViewState getViewStateForView(View requestedView) {
@@ -107,9 +108,7 @@
if (!applyState(child, state)) {
continue;
}
- if(child instanceof SpeedBumpView) {
- performSpeedBumpAnimation(i, (SpeedBumpView) child, state, 0);
- } else if (child instanceof DismissView) {
+ if (child instanceof DismissView) {
DismissView dismissView = (DismissView) child;
boolean visible = state.topOverLap < mClearAllTopPadding;
dismissView.performVisibilityAnimation(visible && !dismissView.willBeGone());
@@ -146,6 +145,14 @@
view.setActualHeight(newHeight, false /* notifyListeners */);
}
+ float shadowAlpha = view.getShadowAlpha();
+ float newShadowAlpha = state.shadowAlpha;
+
+ // apply shadowAlpha
+ if (shadowAlpha != newShadowAlpha) {
+ view.setShadowAlpha(newShadowAlpha);
+ }
+
// apply dimming
view.setDimmed(state.dimmed, false /* animate */);
@@ -183,12 +190,10 @@
float yTranslation = view.getTranslationY();
float xTranslation = view.getTranslationX();
float zTranslation = view.getTranslationZ();
- float scale = view.getScaleX();
float newAlpha = state.alpha;
float newYTranslation = state.yTranslation;
float newZTranslation = state.zTranslation;
- float newScale = state.scale;
- boolean becomesInvisible = newAlpha == 0.0f;
+ boolean becomesInvisible = newAlpha == 0.0f || state.hidden;
if (alpha != newAlpha && xTranslation == 0) {
// apply layer type
boolean becomesFullyVisible = newAlpha == 1.0f;
@@ -225,34 +230,5 @@
if (zTranslation != newZTranslation) {
view.setTranslationZ(newZTranslation);
}
-
- // apply scale
- if (scale != newScale) {
- view.setScaleX(newScale);
- view.setScaleY(newScale);
- }
}
-
- public void performSpeedBumpAnimation(int i, SpeedBumpView speedBump, StackViewState state,
- long delay) {
- View nextChild = getNextChildNotGone(i);
- if (nextChild != null) {
- float lineEnd = state.yTranslation + state.height / 2;
- StackViewState nextState = getViewStateForView(nextChild);
- boolean startIsAboveNext = nextState.yTranslation > lineEnd;
- speedBump.animateDivider(startIsAboveNext, delay, null /* onFinishedRunnable */);
- }
- }
-
- private View getNextChildNotGone(int childIndex) {
- int childCount = mHostView.getChildCount();
- for (int i = childIndex + 1; i < childCount; i++) {
- View child = mHostView.getChildAt(i);
- if (child.getVisibility() != View.GONE) {
- return child;
- }
- }
- return null;
- }
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 9d5e072..e75e8e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -22,13 +22,12 @@
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.view.View;
-import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
-import com.android.systemui.statusbar.SpeedBumpView;
+import com.android.systemui.statusbar.Interpolators;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import java.util.ArrayList;
@@ -55,24 +54,23 @@
private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag;
- private static final int TAG_ANIMATOR_SCALE = R.id.scale_animator_tag;
private static final int TAG_ANIMATOR_ALPHA = R.id.alpha_animator_tag;
private static final int TAG_ANIMATOR_HEIGHT = R.id.height_animator_tag;
private static final int TAG_ANIMATOR_TOP_INSET = R.id.top_inset_animator_tag;
+ private static final int TAG_ANIMATOR_SHADOW_ALPHA = R.id.shadow_alpha_animator_tag;
private static final int TAG_END_TRANSLATION_Y = R.id.translation_y_animator_end_value_tag;
private static final int TAG_END_TRANSLATION_Z = R.id.translation_z_animator_end_value_tag;
- private static final int TAG_END_SCALE = R.id.scale_animator_end_value_tag;
private static final int TAG_END_ALPHA = R.id.alpha_animator_end_value_tag;
private static final int TAG_END_HEIGHT = R.id.height_animator_end_value_tag;
private static final int TAG_END_TOP_INSET = R.id.top_inset_animator_end_value_tag;
+ private static final int TAG_END_SHADOW_ALPHA = R.id.shadow_alpha_animator_end_value_tag;
private static final int TAG_START_TRANSLATION_Y = R.id.translation_y_animator_start_value_tag;
private static final int TAG_START_TRANSLATION_Z = R.id.translation_z_animator_start_value_tag;
- private static final int TAG_START_SCALE = R.id.scale_animator_start_value_tag;
private static final int TAG_START_ALPHA = R.id.alpha_animator_start_value_tag;
private static final int TAG_START_HEIGHT = R.id.height_animator_start_value_tag;
private static final int TAG_START_TOP_INSET = R.id.top_inset_animator_start_value_tag;
+ private static final int TAG_START_SHADOW_ALPHA = R.id.shadow_alpha_animator_start_value_tag;
- private final Interpolator mFastOutSlowInInterpolator;
private final Interpolator mHeadsUpAppearInterpolator;
private final int mGoToFullShadeAppearingTranslation;
private final StackViewState mTmpState = new StackViewState();
@@ -99,8 +97,6 @@
public StackStateAnimator(NotificationStackScrollLayout hostLayout) {
mHostLayout = hostLayout;
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(hostLayout.getContext(),
- android.R.interpolator.fast_out_slow_in);
mGoToFullShadeAppearingTranslation =
hostLayout.getContext().getResources().getDimensionPixelSize(
R.dimen.go_to_full_shade_appearing_translation);
@@ -200,7 +196,6 @@
*/
public void startStackAnimations(final ExpandableView child, StackViewState viewState,
StackScrollState finalState, int i, long fixedDelay) {
- final float alpha = viewState.alpha;
boolean wasAdded = mNewAddChildren.contains(child);
long duration = mCurrentLength;
if (wasAdded && mAnimationFilter.hasGoToFullShadeEvent) {
@@ -212,14 +207,14 @@
}
boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation;
boolean zTranslationChanging = child.getTranslationZ() != viewState.zTranslation;
- boolean scaleChanging = child.getScaleX() != viewState.scale;
- boolean alphaChanging = alpha != child.getAlpha();
+ boolean alphaChanging = viewState.alpha != child.getAlpha();
boolean heightChanging = viewState.height != child.getActualHeight();
+ boolean shadowAlphaChanging = viewState.shadowAlpha != child.getShadowAlpha();
boolean darkChanging = viewState.dark != child.isDark();
boolean topInsetChanging = viewState.clipTopAmount != child.getClipTopAmount();
boolean hasDelays = mAnimationFilter.hasDelays;
- boolean isDelayRelevant = yTranslationChanging || zTranslationChanging || scaleChanging ||
- alphaChanging || heightChanging || topInsetChanging || darkChanging;
+ boolean isDelayRelevant = yTranslationChanging || zTranslationChanging || alphaChanging
+ || heightChanging || topInsetChanging || darkChanging || shadowAlphaChanging;
long delay = 0;
if (fixedDelay != -1) {
delay = fixedDelay;
@@ -234,6 +229,11 @@
startHeightAnimation(child, viewState, duration, delay);
}
+ // start shadow alpha animation
+ if (shadowAlphaChanging) {
+ startShadowAlphaAnimation(child, viewState, duration, delay);
+ }
+
// start top inset animation
if (topInsetChanging) {
startInsetAnimation(child, viewState, duration, delay);
@@ -255,10 +255,7 @@
if (wasAdded) {
child.performAddAnimation(delay, mCurrentLength);
}
- if (child instanceof SpeedBumpView) {
- finalState.performSpeedBumpAnimation(i, (SpeedBumpView) child, viewState,
- delay + duration);
- } else if (child instanceof ExpandableNotificationRow) {
+ if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
row.startChildAnimation(finalState, this, delay, duration);
}
@@ -275,13 +272,12 @@
public void startViewAnimations(View child, ViewState viewState, long delay, long duration) {
boolean wasVisible = child.getVisibility() == View.VISIBLE;
final float alpha = viewState.alpha;
- if (!wasVisible && alpha != 0 && !viewState.gone) {
+ if (!wasVisible && alpha != 0 && !viewState.gone && !viewState.hidden) {
child.setVisibility(View.VISIBLE);
}
boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation;
boolean zTranslationChanging = child.getTranslationZ() != viewState.zTranslation;
- boolean scaleChanging = child.getScaleX() != viewState.scale;
- float childAlpha = child.getVisibility() == View.INVISIBLE ? 0.0f : child.getAlpha();
+ float childAlpha = child.getAlpha();
boolean alphaChanging = viewState.alpha != childAlpha;
if (child instanceof ExpandableView) {
// We don't want views to change visibility when they are animating to GONE
@@ -298,11 +294,6 @@
startZTranslationAnimation(child, viewState, duration, delay);
}
- // start scale animation
- if (scaleChanging) {
- startScaleAnimation(child, viewState, duration);
- }
-
// start alpha animation
if (alphaChanging && child.getTranslationX() == 0) {
startAlphaAnimation(child, viewState, duration, delay);
@@ -384,6 +375,64 @@
return (long) (index * ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE);
}
+ private void startShadowAlphaAnimation(final ExpandableView child,
+ StackViewState viewState, long duration, long delay) {
+ Float previousStartValue = getChildTag(child, TAG_START_SHADOW_ALPHA);
+ Float previousEndValue = getChildTag(child, TAG_END_SHADOW_ALPHA);
+ float newEndValue = viewState.shadowAlpha;
+ if (previousEndValue != null && previousEndValue == newEndValue) {
+ return;
+ }
+ ValueAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_SHADOW_ALPHA);
+ if (!mAnimationFilter.animateShadowAlpha) {
+ // just a local update was performed
+ if (previousAnimator != null) {
+ // we need to increase all animation keyframes of the previous animator by the
+ // relative change to the end value
+ PropertyValuesHolder[] values = previousAnimator.getValues();
+ float relativeDiff = newEndValue - previousEndValue;
+ float newStartValue = previousStartValue + relativeDiff;
+ values[0].setFloatValues(newStartValue, newEndValue);
+ child.setTag(TAG_START_SHADOW_ALPHA, newStartValue);
+ child.setTag(TAG_END_SHADOW_ALPHA, newEndValue);
+ previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
+ return;
+ } else {
+ // no new animation needed, let's just apply the value
+ child.setShadowAlpha(newEndValue);
+ return;
+ }
+ }
+
+ ValueAnimator animator = ValueAnimator.ofFloat(child.getShadowAlpha(), newEndValue);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ child.setShadowAlpha((float) animation.getAnimatedValue());
+ }
+ });
+ animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
+ animator.setDuration(newDuration);
+ if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
+ animator.setStartDelay(delay);
+ }
+ animator.addListener(getGlobalAnimationFinishedListener());
+ // remove the tag when the animation is finished
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ child.setTag(TAG_ANIMATOR_SHADOW_ALPHA, null);
+ child.setTag(TAG_START_SHADOW_ALPHA, null);
+ child.setTag(TAG_END_SHADOW_ALPHA, null);
+ }
+ });
+ startAnimator(animator);
+ child.setTag(TAG_ANIMATOR_SHADOW_ALPHA, animator);
+ child.setTag(TAG_START_SHADOW_ALPHA, child.getShadowAlpha());
+ child.setTag(TAG_END_SHADOW_ALPHA, newEndValue);
+ }
+
private void startHeightAnimation(final ExpandableView child,
StackViewState viewState, long duration, long delay) {
Integer previousStartValue = getChildTag(child, TAG_START_HEIGHT);
@@ -421,7 +470,7 @@
false /* notifyListeners */);
}
});
- animator.setInterpolator(mFastOutSlowInInterpolator);
+ animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
animator.setDuration(newDuration);
if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
@@ -479,7 +528,7 @@
child.setClipTopAmount((int) animation.getAnimatedValue());
}
});
- animator.setInterpolator(mFastOutSlowInInterpolator);
+ animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
animator.setDuration(newDuration);
if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
@@ -534,7 +583,7 @@
ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.ALPHA,
child.getAlpha(), newEndValue);
- animator.setInterpolator(mFastOutSlowInInterpolator);
+ animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
// Handle layer type
child.setLayerType(View.LAYER_TYPE_HARDWARE, null);
animator.addListener(new AnimatorListenerAdapter() {
@@ -605,7 +654,7 @@
ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Z,
child.getTranslationZ(), newEndValue);
- animator.setInterpolator(mFastOutSlowInInterpolator);
+ animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
animator.setDuration(newDuration);
if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
@@ -659,7 +708,7 @@
ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Y,
child.getTranslationY(), newEndValue);
Interpolator interpolator = mHeadsUpAppearChildren.contains(child) ?
- mHeadsUpAppearInterpolator :mFastOutSlowInInterpolator;
+ mHeadsUpAppearInterpolator :Interpolators.FAST_OUT_SLOW_IN;
animator.setInterpolator(interpolator);
long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
animator.setDuration(newDuration);
@@ -683,60 +732,6 @@
child.setTag(TAG_END_TRANSLATION_Y, newEndValue);
}
- private void startScaleAnimation(final View child,
- ViewState viewState, long duration) {
- Float previousStartValue = getChildTag(child, TAG_START_SCALE);
- Float previousEndValue = getChildTag(child, TAG_END_SCALE);
- float newEndValue = viewState.scale;
- if (previousEndValue != null && previousEndValue == newEndValue) {
- return;
- }
- ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_SCALE);
- if (!mAnimationFilter.animateScale) {
- // just a local update was performed
- if (previousAnimator != null) {
- // we need to increase all animation keyframes of the previous animator by the
- // relative change to the end value
- PropertyValuesHolder[] values = previousAnimator.getValues();
- float relativeDiff = newEndValue - previousEndValue;
- float newStartValue = previousStartValue + relativeDiff;
- values[0].setFloatValues(newStartValue, newEndValue);
- values[1].setFloatValues(newStartValue, newEndValue);
- child.setTag(TAG_START_SCALE, newStartValue);
- child.setTag(TAG_END_SCALE, newEndValue);
- previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
- return;
- } else {
- // no new animation needed, let's just apply the value
- child.setScaleX(newEndValue);
- child.setScaleY(newEndValue);
- }
- }
-
- PropertyValuesHolder holderX =
- PropertyValuesHolder.ofFloat(View.SCALE_X, child.getScaleX(), newEndValue);
- PropertyValuesHolder holderY =
- PropertyValuesHolder.ofFloat(View.SCALE_Y, child.getScaleY(), newEndValue);
- ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(child, holderX, holderY);
- animator.setInterpolator(mFastOutSlowInInterpolator);
- long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
- animator.setDuration(newDuration);
- animator.addListener(getGlobalAnimationFinishedListener());
- // remove the tag when the animation is finished
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- child.setTag(TAG_ANIMATOR_SCALE, null);
- child.setTag(TAG_START_SCALE, null);
- child.setTag(TAG_END_SCALE, null);
- }
- });
- startAnimator(animator);
- child.setTag(TAG_ANIMATOR_SCALE, animator);
- child.setTag(TAG_START_SCALE, child.getScaleX());
- child.setTag(TAG_END_SCALE, newEndValue);
- }
-
private void startAnimator(ValueAnimator animator) {
mAnimatorSet.add(animator);
animator.start();
@@ -934,7 +929,7 @@
isRubberbanded);
}
});
- overScrollAnimator.setInterpolator(mFastOutSlowInInterpolator);
+ overScrollAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
overScrollAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -976,6 +971,22 @@
}
}
+ /**
+ * Get the end value of the height animation running on a view or the actualHeight
+ * if no animation is running.
+ */
+ public static float getFinalTranslationY(ExpandableView view) {
+ if (view == null) {
+ return 0;
+ }
+ ValueAnimator yAnimator = getChildTag(view, TAG_ANIMATOR_TRANSLATION_Y);
+ if (yAnimator == null) {
+ return view.getTranslationY();
+ } else {
+ return getChildTag(view, TAG_END_TRANSLATION_Y);
+ }
+ }
+
public void setHeadsUpAppearHeightBottom(int headsUpAppearHeightBottom) {
mHeadsUpAppearHeightBottom = headsUpAppearHeightBottom;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
index 55ef440..41824ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackViewState.java
@@ -42,6 +42,7 @@
public boolean dark;
public boolean hideSensitive;
public boolean belowSpeedBump;
+ public float shadowAlpha;
/**
* The amount which the view should be clipped from the top. This is calculated to
@@ -74,6 +75,7 @@
StackViewState svs = (StackViewState) viewState;
height = svs.height;
dimmed = svs.dimmed;
+ shadowAlpha = svs.shadowAlpha;
dark = svs.dark;
hideSensitive = svs.hideSensitive;
belowSpeedBump = svs.belowSpeedBump;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
index 3e538df..5beaac3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/ViewState.java
@@ -29,21 +29,21 @@
public float yTranslation;
public float zTranslation;
public boolean gone;
- public float scale;
+ public boolean hidden;
public void copyFrom(ViewState viewState) {
alpha = viewState.alpha;
yTranslation = viewState.yTranslation;
zTranslation = viewState.zTranslation;
gone = viewState.gone;
- scale = viewState.scale;
+ hidden = viewState.hidden;
}
public void initFrom(View view) {
- alpha = view.getVisibility() == View.INVISIBLE ? 0.0f : view.getAlpha();
+ alpha = view.getAlpha();
yTranslation = view.getTranslationY();
zTranslation = view.getTranslationZ();
gone = view.getVisibility() == View.GONE;
- scale = view.getScaleX();
+ hidden = false;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index b237400..e947ed5 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -94,6 +94,12 @@
}
}
};
+ private final Runnable mOnPinnedActivityRestartAttempt = new Runnable() {
+ @Override
+ public void run() {
+ movePipToFullscreen();
+ }
+ };
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -315,6 +321,8 @@
@Override
public void onPinnedActivityRestartAttempt() {
+ // Post the message back to the UI thread.
+ mHandler.post(mOnPinnedActivityRestartAttempt);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/IconPulser.java b/packages/SystemUI/src/com/android/systemui/volume/IconPulser.java
deleted file mode 100644
index 9438af1..0000000
--- a/packages/SystemUI/src/com/android/systemui/volume/IconPulser.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.volume;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.content.Context;
-import android.view.View;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-public class IconPulser {
- private static final float PULSE_SCALE = 1.1f;
-
- private final Interpolator mFastOutSlowInInterpolator;
-
- public IconPulser(Context context) {
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- android.R.interpolator.fast_out_slow_in);
- }
-
- public void start(final View target) {
- if (target == null || target.getScaleX() != 1) return; // n/a, or already running
- target.animate().cancel();
- target.animate().scaleX(PULSE_SCALE).scaleY(PULSE_SCALE)
- .setInterpolator(mFastOutSlowInInterpolator)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- target.animate().scaleX(1).scaleY(1).setListener(null);
- }
- });
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index ed6fc9e..b005a2b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -258,7 +258,6 @@
if (w > max) {
w = max;
}
- w -= mContext.getResources().getDimensionPixelSize(R.dimen.notification_side_padding) * 2;
lp.width = w;
mDialogView.setLayoutParams(lp);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java
deleted file mode 100644
index f51e8ff..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import org.mockito.InOrder;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.ActivityInfo;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.pm.UserInfo;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.test.AndroidTestCase;
-
-import java.util.Arrays;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.HashMap;
-import java.util.Map;
-
-/** Tests for the data model for the navigation bar app icons. */
-public class NavigationBarAppsModelTest extends AndroidTestCase {
- private PackageManager mMockPackageManager;
- private IPackageManager mMockIPackageManager;
- private SharedPreferences mMockPrefs;
- private SharedPreferences.Editor mMockEdit;
- private UserManager mMockUserManager;
-
- private NavigationBarAppsModel mModel;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- // Mockito setup boilerplate.
- System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());
- Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
-
- final Context context = mock(Context.class);
- mMockPackageManager = mock(PackageManager.class);
- mMockIPackageManager = mock(IPackageManager.class);
- mMockPrefs = mock(SharedPreferences.class);
- mMockEdit = mock(SharedPreferences.Editor.class);
- mMockUserManager = mock(UserManager.class);
-
- when(context.getSharedPreferences(
- "com.android.systemui.navbarapps", Context.MODE_PRIVATE)).thenReturn(mMockPrefs);
- when(context.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager);
- when(context.getPackageManager()).thenReturn(mMockPackageManager);
-
- setContext(context);
-
- when(mMockUserManager.getUsers()).thenReturn(new ArrayList<UserInfo>());
- // Assume the version pref is present and equal to the current version.
- when(mMockPrefs.getInt("version", -1)).thenReturn(3);
- when(mMockPrefs.edit()).thenReturn(mMockEdit);
-
- when(mMockUserManager.getSerialNumberForUser(new UserHandle(2))).thenReturn(222L);
- when(mMockUserManager.getSerialNumberForUser(new UserHandle(4))).thenReturn(444L);
- when(mMockUserManager.getSerialNumberForUser(new UserHandle(5))).thenReturn(555L);
- when(mMockUserManager.getUserForSerialNumber(222L)).thenReturn(new UserHandle(2));
- when(mMockUserManager.getUserForSerialNumber(444L)).thenReturn(new UserHandle(4));
- when(mMockUserManager.getUserForSerialNumber(555L)).thenReturn(new UserHandle(5));
-
- UserInfo ui2 = new UserInfo();
- ui2.profileGroupId = 999;
- UserInfo ui4 = new UserInfo();
- ui4.profileGroupId = 999;
- UserInfo ui5 = new UserInfo();
- ui5.profileGroupId = 999;
- when(mMockUserManager.getUserInfo(2)).thenReturn(ui2);
- when(mMockUserManager.getUserInfo(4)).thenReturn(ui4);
- when(mMockUserManager.getUserInfo(5)).thenReturn(ui5);
-
- mModel = new NavigationBarAppsModel(context) {
- @Override
- protected IPackageManager getPackageManager() {
- return mMockIPackageManager;
- }
- };
- }
-
- /** Tests resolveApp(). */
- public void testResolveApp() {
- ActivityInfo mockNonExportedActivityInfo = new ActivityInfo();
- mockNonExportedActivityInfo.exported = false;
- ActivityInfo mockExportedActivityInfo = new ActivityInfo();
- mockExportedActivityInfo.exported = true;
- try {
- when(mMockIPackageManager.getActivityInfo(
- new ComponentName("package1", "class1"), 0, 4)).
- thenReturn(mockNonExportedActivityInfo);
- when(mMockIPackageManager.getActivityInfo(
- new ComponentName("package2", "class2"), 0, 5)).
- thenThrow(new RemoteException());
- when(mMockIPackageManager.getActivityInfo(
- new ComponentName("package3", "class3"), 0, 6)).
- thenReturn(mockExportedActivityInfo);
- when(mMockIPackageManager.getActivityInfo(
- new ComponentName("package4", "class4"), 0, 7)).
- thenReturn(mockExportedActivityInfo);
- } catch (RemoteException e) {
- fail("RemoteException can't happen in the test, but it happened.");
- }
-
- // Assume some installed activities.
- ActivityInfo ai0 = new ActivityInfo();
- ai0.packageName = "package0";
- ai0.name = "class0";
- ActivityInfo ai1 = new ActivityInfo();
- ai1.packageName = "package4";
- ai1.name = "class4";
- ResolveInfo ri0 = new ResolveInfo();
- ri0.activityInfo = ai0;
- ResolveInfo ri1 = new ResolveInfo();
- ri1.activityInfo = ai1;
- when(mMockPackageManager
- .queryIntentActivitiesAsUser(any(Intent.class), eq(0), any(int.class)))
- .thenReturn(Arrays.asList(ri0, ri1));
-
- mModel.setCurrentUser(3);
- // Unlauncheable (for various reasons) apps.
- assertEquals(null, mModel.resolveApp(
- new AppInfo(new ComponentName("package0", "class0"), new UserHandle(3))));
- mModel.setCurrentUser(4);
- assertEquals(null, mModel.resolveApp(
- new AppInfo(new ComponentName("package1", "class1"), new UserHandle(4))));
- mModel.setCurrentUser(5);
- assertEquals(null, mModel.resolveApp(
- new AppInfo(new ComponentName("package2", "class2"), new UserHandle(5))));
- mModel.setCurrentUser(6);
- assertEquals(null, mModel.resolveApp(
- new AppInfo(new ComponentName("package3", "class3"), new UserHandle(6))));
-
- // A launcheable app.
- mModel.setCurrentUser(7);
- NavigationBarAppsModel.ResolvedApp resolvedApp = mModel.resolveApp(
- new AppInfo(new ComponentName("package4", "class4"), new UserHandle(7)));
- assertNotNull(resolvedApp);
- Intent intent = resolvedApp.launchIntent;
- assertEquals(new ComponentName("package4", "class4"), intent.getComponent());
- assertEquals("package4", intent.getPackage());
- assertEquals(ri1, resolvedApp.ri);
- }
-
- /** Initializes the model from SharedPreferences for a few app activites. */
- private void initializeModelFromPrefs() {
- // Assume several apps are stored.
- when(mMockPrefs.getInt("222|app_count", -1)).thenReturn(2);
- when(mMockPrefs.getString("222|app_0", null)).thenReturn("package1/class1");
- when(mMockPrefs.getLong("222|app_user_0", -1)).thenReturn(444L);
- when(mMockPrefs.getString("222|app_1", null)).thenReturn("package2/class2");
- when(mMockPrefs.getLong("222|app_user_1", -1)).thenReturn(555L);
-
- ActivityInfo mockActivityInfo = new ActivityInfo();
- mockActivityInfo.exported = true;
- try {
- when(mMockIPackageManager.getActivityInfo(
- new ComponentName("package0", "class0"), 0, 5)).thenReturn(mockActivityInfo);
- when(mMockIPackageManager.getActivityInfo(
- new ComponentName("package1", "class1"), 0, 4)).thenReturn(mockActivityInfo);
- when(mMockIPackageManager.getActivityInfo(
- new ComponentName("package2", "class2"), 0, 5)).thenReturn(mockActivityInfo);
- } catch (RemoteException e) {
- fail("RemoteException can't happen in the test, but it happened.");
- }
-
- // Assume some installed activities.
- ActivityInfo ai0 = new ActivityInfo();
- ai0.packageName = "package0";
- ai0.name = "class0";
- ActivityInfo ai1 = new ActivityInfo();
- ai1.packageName = "package1";
- ai1.name = "class1";
- ActivityInfo ai2 = new ActivityInfo();
- ai2.packageName = "package2";
- ai2.name = "class2";
- ResolveInfo ri0 = new ResolveInfo();
- ri0.activityInfo = ai0;
- ResolveInfo ri1 = new ResolveInfo();
- ri1.activityInfo = ai1;
- ResolveInfo ri2 = new ResolveInfo();
- ri2.activityInfo = ai2;
- when(mMockPackageManager
- .queryIntentActivitiesAsUser(any(Intent.class), eq(0), any(int.class)))
- .thenReturn(Arrays.asList(ri0, ri1, ri2));
-
- mModel.setCurrentUser(2);
- }
-
- /** Tests initializing the model from SharedPreferences. */
- public void testInitializeFromPrefs() {
- initializeModelFromPrefs();
- List<AppInfo> apps = mModel.getApps();
- assertEquals(2, apps.size());
- assertEquals("package1/class1", apps.get(0).getComponentName().flattenToString());
- assertEquals(new UserHandle(4), apps.get(0).getUser());
- assertEquals("package2/class2", apps.get(1).getComponentName().flattenToString());
- assertEquals(new UserHandle(5), apps.get(1).getUser());
- }
-
- /** Tests initializing the model when the SharedPreferences aren't available. */
- public void testInitializeDefaultApps() {
- // Assume the user's app count pref isn't available.
- when(mMockPrefs.getInt("222|app_count", -1)).thenReturn(-1);
-
- // Assume some installed activities.
- ActivityInfo ai1 = new ActivityInfo();
- ai1.packageName = "package1";
- ai1.name = "class1";
- ActivityInfo ai2 = new ActivityInfo();
- ai2.packageName = "package2";
- ai2.name = "class2";
- ResolveInfo ri1 = new ResolveInfo();
- ri1.activityInfo = ai1;
- ResolveInfo ri2 = new ResolveInfo();
- ri2.activityInfo = ai2;
- when(mMockPackageManager
- .queryIntentActivitiesAsUser(any(Intent.class), eq(0), eq(2)))
- .thenReturn(Arrays.asList(ri1, ri2));
-
- // Setting the user should load the installed activities.
- mModel.setCurrentUser(2);
- List<AppInfo> apps = mModel.getApps();
- assertEquals(2, apps.size());
- assertEquals("package1/class1", apps.get(0).getComponentName().flattenToString());
- assertEquals(new UserHandle(2), apps.get(0).getUser());
- assertEquals("package2/class2", apps.get(1).getComponentName().flattenToString());
- assertEquals(new UserHandle(2), apps.get(1).getUser());
- InOrder order = inOrder(mMockEdit);
- order.verify(mMockEdit).apply();
- order.verify(mMockEdit).putInt("222|app_count", 2);
- order.verify(mMockEdit).putString("222|app_0", "package1/class1");
- order.verify(mMockEdit).putLong("222|app_user_0", 222L);
- order.verify(mMockEdit).putString("222|app_1", "package2/class2");
- order.verify(mMockEdit).putLong("222|app_user_1", 222L);
- order.verify(mMockEdit).apply();
- verifyNoMoreInteractions(mMockEdit);
- }
-
- /** Tests initializing the model if one of the prefs is missing. */
- public void testInitializeWithMissingPref() {
- // Assume two apps are nominally stored.
- when(mMockPrefs.getInt("222|app_count", -1)).thenReturn(2);
- when(mMockPrefs.getString("222|app_0", null)).thenReturn("package0/class0");
- when(mMockPrefs.getLong("222|app_user_0", -1)).thenReturn(555L);
-
- // But assume one pref is missing.
- when(mMockPrefs.getString("222|app_1", null)).thenReturn(null);
-
- ActivityInfo mockActivityInfo = new ActivityInfo();
- mockActivityInfo.exported = true;
- try {
- when(mMockIPackageManager.getActivityInfo(
- new ComponentName("package0", "class0"), 0, 5)).thenReturn(mockActivityInfo);
- } catch (RemoteException e) {
- fail("RemoteException can't happen in the test, but it happened.");
- }
-
- ActivityInfo ai0 = new ActivityInfo();
- ai0.packageName = "package0";
- ai0.name = "class0";
- ResolveInfo ri0 = new ResolveInfo();
- ri0.activityInfo = ai0;
- when(mMockPackageManager
- .queryIntentActivitiesAsUser(any(Intent.class), eq(0), any(int.class)))
- .thenReturn(Arrays.asList(ri0));
-
- // Initializing the model should load from prefs and skip the missing one.
- mModel.setCurrentUser(2);
- List<AppInfo> apps = mModel.getApps();
- assertEquals(1, apps.size());
- assertEquals("package0/class0", apps.get(0).getComponentName().flattenToString());
- assertEquals(new UserHandle(5), apps.get(0).getUser());
- InOrder order = inOrder(mMockEdit);
- order.verify(mMockEdit).putInt("222|app_count", 1);
- order.verify(mMockEdit).putString("222|app_0", "package0/class0");
- order.verify(mMockEdit).putLong("222|app_user_0", 555L);
- order.verify(mMockEdit).apply();
- verifyNoMoreInteractions(mMockEdit);
- }
-
- /** Tests initializing the model if one of the apps is unlauncheable. */
- public void testInitializeWithUnlauncheableApp() {
- // Assume two apps are nominally stored.
- when(mMockPrefs.getInt("222|app_count", -1)).thenReturn(2);
- when(mMockPrefs.getString("222|app_0", null)).thenReturn("package0/class0");
- when(mMockPrefs.getLong("222|app_user_0", -1)).thenReturn(555L);
- when(mMockPrefs.getString("222|app_1", null)).thenReturn("package1/class1");
- when(mMockPrefs.getLong("222|app_user_1", -1)).thenReturn(444L);
-
- ActivityInfo mockActivityInfo = new ActivityInfo();
- mockActivityInfo.exported = true;
- try {
- when(mMockIPackageManager.getActivityInfo(
- new ComponentName("package0", "class0"), 0, 5)).thenReturn(mockActivityInfo);
- } catch (RemoteException e) {
- fail("RemoteException can't happen in the test, but it happened.");
- }
-
- ActivityInfo ai0 = new ActivityInfo();
- ai0.packageName = "package0";
- ai0.name = "class0";
- ResolveInfo ri0 = new ResolveInfo();
- ri0.activityInfo = ai0;
- when(mMockPackageManager
- .queryIntentActivitiesAsUser(any(Intent.class), eq(0), any(int.class)))
- .thenReturn(Arrays.asList(ri0));
-
- // Initializing the model should load from prefs and skip the unlauncheable one.
- mModel.setCurrentUser(2);
- List<AppInfo> apps = mModel.getApps();
- assertEquals(1, apps.size());
- assertEquals("package0/class0", apps.get(0).getComponentName().flattenToString());
- assertEquals(new UserHandle(5), apps.get(0).getUser());
-
- // Once an unlauncheable app is detected, the model should save all apps excluding the
- // unlauncheable one.
- verify(mMockEdit).putInt("222|app_count", 1);
- verify(mMockEdit).putString("222|app_0", "package0/class0");
- verify(mMockEdit).putLong("222|app_user_0", 555L);
- verify(mMockEdit).apply();
- verifyNoMoreInteractions(mMockEdit);
- }
-
- /** Tests saving the model to SharedPreferences. */
- public void testSavePrefs() {
- initializeModelFromPrefs();
-
- mModel.setApps(mModel.getApps());
- verify(mMockEdit).putInt("222|app_count", 2);
- verify(mMockEdit).putString("222|app_0", "package1/class1");
- verify(mMockEdit).putLong("222|app_user_0", 444L);
- verify(mMockEdit).putString("222|app_1", "package2/class2");
- verify(mMockEdit).putLong("222|app_user_1", 555L);
- verify(mMockEdit).apply();
- verifyNoMoreInteractions(mMockEdit);
- }
-
- /** Tests cleaning all prefs on a version change. */
- public void testVersionChange() {
- // Assume the version pref changed.
- when(mMockPrefs.getInt("version", -1)).thenReturn(1);
-
- new NavigationBarAppsModel(getContext());
- verify(mMockEdit).clear();
- verify(mMockEdit).putInt("version", 3);
- verify(mMockEdit).apply();
- verifyNoMoreInteractions(mMockEdit);
- }
-
- /** Tests cleaning prefs for deleted users. */
- public void testCleaningDeletedUsers() {
- // Users on the device.
- final UserInfo user1 = new UserInfo(11, "", 0);
- user1.serialNumber = 1111;
- final UserInfo user2 = new UserInfo(13, "", 0);
- user2.serialNumber = 1313;
-
- when(mMockUserManager.getUsers()).thenReturn(Arrays.asList(user1, user2));
-
- when(mMockPrefs.edit()).
- thenReturn(mMockEdit).
- thenReturn(mock(SharedPreferences.Editor.class));
-
- // Assume the user's app count pref isn't available. This will trigger clearing deleted
- // users' prefs.
- when(mMockPrefs.getInt("222|app_count", -1)).thenReturn(-1);
-
- final Map allPrefs = new HashMap<String, Object>();
- allPrefs.put("version", null);
- allPrefs.put("some_strange_pref", null);
- allPrefs.put("", null);
- allPrefs.put("|", null);
- allPrefs.put("1313|app_count", null);
- allPrefs.put("1212|app_count", null);
- when(mMockPrefs.getAll()).thenReturn(allPrefs);
-
- // Setting the user should remove prefs for deleted users.
- mModel.setCurrentUser(2);
- verify(mMockEdit).remove("some_strange_pref");
- verify(mMockEdit).remove("");
- verify(mMockEdit).remove("|");
- verify(mMockEdit).remove("1212|app_count");
- verify(mMockEdit).apply();
- verifyNoMoreInteractions(mMockEdit);
- }
-
- /** Tests the apps-changed listener. */
- public void testAppsChangedListeners() {
- NavigationBarAppsModel.OnAppsChangedListener listener =
- mock(NavigationBarAppsModel.OnAppsChangedListener.class);
-
- mModel.addOnAppsChangedListener(listener);
- mModel.setApps(new ArrayList<AppInfo>());
- verify(listener).onPinnedAppsChanged();
- verifyNoMoreInteractions(listener);
-
- mModel.removeOnAppsChangedListener(listener);
- mModel.setApps(new ArrayList<AppInfo>());
- verifyNoMoreInteractions(listener);
- }
-}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index d63dd0c..46198b0 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1920,7 +1920,9 @@
synchronized (mBackupParticipants) {
if (replacing) {
// This is the package-replaced case; we just remove the entry
- // under the old uid and fall through to re-add.
+ // under the old uid and fall through to re-add. If an app
+ // just added key/value backup participation, this picks it up
+ // as a known participant.
removePackageParticipantsLocked(pkgList, uid);
}
addPackageParticipantsLocked(pkgList);
@@ -1933,6 +1935,14 @@
if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) {
enqueueFullBackup(packageName, now);
scheduleNextFullBackupJob(0);
+ } else {
+ // The app might have just transitioned out of full-data into
+ // doing key/value backups, or might have just disabled backups
+ // entirely. Make sure it is no longer in the full-data queue.
+ synchronized (mQueueLock) {
+ dequeueFullBackupLocked(packageName);
+ }
+ writeFullBackupScheduleAsync();
}
// Transport maintenance: rebind to known existing transports that have
@@ -1964,6 +1974,9 @@
if (replacing) {
// The package is being updated. We'll receive a PACKAGE_ADDED shortly.
} else {
+ // Outright removal. In the full-data case, the app will be dropped
+ // from the queue when its (now obsolete) name comes up again for
+ // backup.
synchronized (mBackupParticipants) {
removePackageParticipantsLocked(pkgList, uid);
}
@@ -4190,11 +4203,21 @@
// as well as any explicit mention of the 'special' shared-storage agent
// package (we handle that one at the end).
if (MORE_DEBUG) {
- Slog.d(TAG, "Ignoring not eligible package " + pkg);
+ Slog.d(TAG, "Ignoring ineligible package " + pkg);
}
sendBackupOnResult(mBackupObserver, pkg,
BackupManager.ERROR_BACKUP_NOT_ALLOWED);
continue;
+ } else if (!appGetsFullBackup(info)) {
+ // Cull any packages that are found in the queue but now aren't supposed
+ // to get full-data backup operations.
+ if (MORE_DEBUG) {
+ Slog.d(TAG, "Ignoring full-data backup of key/value participant "
+ + pkg);
+ }
+ sendBackupOnResult(mBackupObserver, pkg,
+ BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+ continue;
} else if (appIsStopped(info.applicationInfo)) {
// Cull any packages in the 'stopped' state: they've either just been
// installed or have explicitly been force-stopped by the user. In both
@@ -4592,21 +4615,28 @@
}
/**
+ * Remove a package from the full-data queue.
+ */
+ void dequeueFullBackupLocked(String packageName) {
+ final int N = mFullBackupQueue.size();
+ for (int i = N-1; i >= 0; i--) {
+ final FullBackupEntry e = mFullBackupQueue.get(i);
+ if (packageName.equals(e.packageName)) {
+ mFullBackupQueue.remove(i);
+ }
+ }
+ }
+
+ /**
* Enqueue full backup for the given app, with a note about when it last ran.
*/
void enqueueFullBackup(String packageName, long lastBackedUp) {
FullBackupEntry newEntry = new FullBackupEntry(packageName, lastBackedUp);
synchronized (mQueueLock) {
- int N = mFullBackupQueue.size();
// First, sanity check that we aren't adding a duplicate. Slow but
// straightforward; we'll have at most on the order of a few hundred
// items in this list.
- for (int i = N-1; i >= 0; i--) {
- final FullBackupEntry e = mFullBackupQueue.get(i);
- if (packageName.equals(e.packageName)) {
- mFullBackupQueue.remove(i);
- }
- }
+ dequeueFullBackupLocked(packageName);
// This is also slow but easy for modest numbers of apps: work backwards
// from the end of the queue until we find an item whose last backup
@@ -4700,21 +4730,24 @@
return false;
}
- if (mFullBackupQueue.size() == 0) {
- // no work to do so just bow out
- if (DEBUG) {
- Slog.i(TAG, "Backup queue empty; doing nothing");
- }
- return false;
- }
-
- // At this point we know that we have work to do, but possibly not right now.
+ // At this point we think that we have work to do, but possibly not right now.
// Any exit without actually running backups will also require that we
// reschedule the job.
boolean runBackup = true;
boolean headBusy;
do {
+ // Recheck each time, because culling due to ineligibility may
+ // have emptied the queue.
+ if (mFullBackupQueue.size() == 0) {
+ // no work to do so just bow out
+ if (DEBUG) {
+ Slog.i(TAG, "Backup queue empty; doing nothing");
+ }
+ runBackup = false;
+ break;
+ }
+
headBusy = false;
if (!fullBackupAllowable(getTransport(mCurrentTransport))) {
@@ -4744,6 +4777,19 @@
try {
PackageInfo appInfo = mPackageManager.getPackageInfo(entry.packageName, 0);
+ if (!appGetsFullBackup(appInfo)) {
+ // The head app isn't supposed to get full-data backups [any more];
+ // so we cull it and force a loop around to consider the new head
+ // app.
+ if (MORE_DEBUG) {
+ Slog.i(TAG, "Culling package " + entry.packageName
+ + " in full-backup queue but not eligible");
+ }
+ mFullBackupQueue.remove(0);
+ headBusy = true; // force the while() condition
+ continue;
+ }
+
headBusy = mActivityManager.isAppForeground(appInfo.applicationInfo.uid);
if (headBusy) {
@@ -4762,7 +4808,6 @@
enqueueFullBackup(entry.packageName,
nextEligible - MIN_FULL_BACKUP_INTERVAL);
}
-
} catch (NameNotFoundException nnf) {
// So, we think we want to back this up, but it turns out the package
// in question is no longer installed. We want to drop it from the
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index c1a082b..499b706 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -114,13 +114,6 @@
private static final int SERVICE_IBLUETOOTH = 1;
private static final int SERVICE_IBLUETOOTHGATT = 2;
- private static final String[] DEVICE_TYPE_NAMES = new String[] {
- "???",
- "BR/EDR",
- "LE",
- "DUAL"
- };
-
private final Context mContext;
private static int mBleAppCount = 0;
@@ -131,6 +124,7 @@
private final ContentResolver mContentResolver;
private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
+ private IBinder mBluetoothBinder;
private IBluetooth mBluetooth;
private IBluetoothGatt mBluetoothGatt;
private boolean mBinding;
@@ -242,6 +236,7 @@
mContext = context;
mBluetooth = null;
+ mBluetoothBinder = null;
mBluetoothGatt = null;
mBinding = false;
mUnbinding = false;
@@ -678,6 +673,7 @@
}
if (DBG) Log.d(TAG, "Sending unbind request.");
+ mBluetoothBinder = null;
mBluetooth = null;
//Unbind
mContext.unbindService(mConnection);
@@ -1166,6 +1162,7 @@
mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
mBinding = false;
+ mBluetoothBinder = service;
mBluetooth = IBluetooth.Stub.asInterface(service);
try {
@@ -1674,44 +1671,15 @@
}
@Override
- public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
-
- writer.println("Bluetooth Status");
- writer.println(" enabled: " + mEnable);
- writer.println(" state: " + mState);
- writer.println(" address: " + mAddress);
- writer.println(" name: " + mName + "\n");
- writer.flush();
-
- if (mBluetooth == null) {
- writer.println("Bluetooth Service not connected");
- } else {
- ParcelFileDescriptor pfd = null;
- try {
- writer.println("Bonded devices:");
- for (BluetoothDevice device : mBluetooth.getBondedDevices()) {
- writer.println(" " + device.getAddress() +
- " [" + DEVICE_TYPE_NAMES[device.getType()] + "] " +
- device.getName());
- }
- writer.flush();
-
- pfd = ParcelFileDescriptor.dup(fd);
- mBluetooth.dump(pfd);
- } catch (RemoteException re) {
- writer.println("RemoteException while calling Bluetooth Service");
- } catch (IOException ioe) {
- writer.println("IOException attempting to dup() fd");
- } finally {
- if (pfd != null) {
- try {
- pfd.close();
- } catch (IOException ioe) {
- writer.println("IOException attempting to close() fd");
- }
- }
- }
+ public void dump(FileDescriptor fd, PrintWriter writer, String args[]) {
+ if (mBluetoothBinder == null) {
+ writer.println("Bluetooth Service not connected");
+ } else {
+ try {
+ mBluetoothBinder.dump(fd, args);
+ } catch (RemoteException re) {
+ writer.println("RemoteException while calling Bluetooth Service");
}
+ }
}
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index dd19c6a..95f5734 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -186,7 +186,6 @@
private final Handler mFgHandler;
private final Handler mDaemonHandler;
- private final PhoneStateListener mPhoneStateListener;
private IBatteryStats mBatteryStats;
@@ -283,22 +282,6 @@
mDaemonHandler = new Handler(FgThread.get().getLooper());
- mPhoneStateListener = new PhoneStateListener(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
- mDaemonHandler.getLooper()) {
- @Override
- public void onDataConnectionRealTimeInfoChanged(
- DataConnectionRealTimeInfo dcRtInfo) {
- if (DBG) Slog.d(TAG, "onDataConnectionRealTimeInfoChanged: " + dcRtInfo);
- notifyInterfaceClassActivity(ConnectivityManager.TYPE_MOBILE,
- dcRtInfo.getDcPowerState(), dcRtInfo.getTime(), true);
- }
- };
- TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
- if (tm != null) {
- tm.listen(mPhoneStateListener,
- PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO);
- }
-
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 19a4851..820551d 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -34,7 +34,6 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.telephony.CellLocation;
-import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.Rlog;
import android.telephony.TelephonyManager;
import android.telephony.SubscriptionManager;
@@ -179,8 +178,6 @@
private int mDefaultPhoneId = SubscriptionManager.INVALID_PHONE_INDEX;
- private DataConnectionRealTimeInfo mDcRtInfo = new DataConnectionRealTimeInfo();
-
private int mRingingCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
private int mForegroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
@@ -262,7 +259,8 @@
mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED, userHandle, 0));
} else if (action.equals(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED)) {
Integer newDefaultSubIdObj = new Integer(intent.getIntExtra(
- PhoneConstants.SUBSCRIPTION_KEY, SubscriptionManager.getDefaultSubId()));
+ PhoneConstants.SUBSCRIPTION_KEY,
+ SubscriptionManager.getDefaultSubscriptionId()));
int newDefaultPhoneId = intent.getIntExtra(PhoneConstants.SLOT_KEY,
SubscriptionManager.getPhoneId(mDefaultSubId));
if (DBG) {
@@ -624,13 +622,6 @@
remove(r.binder);
}
}
- if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO) != 0) {
- try {
- r.callback.onDataConnectionRealTimeInfoChanged(mDcRtInfo);
- } catch (RemoteException ex) {
- remove(r.binder);
- }
- }
if ((events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
try {
r.callback.onPreciseCallStateChanged(mPreciseCallState);
@@ -921,31 +912,6 @@
}
}
- public void notifyDataConnectionRealTimeInfo(DataConnectionRealTimeInfo dcRtInfo) {
- if (!checkNotifyPermission("notifyDataConnectionRealTimeInfo()")) {
- return;
- }
-
- synchronized (mRecords) {
- mDcRtInfo = dcRtInfo;
- for (Record r : mRecords) {
- if (validateEventsAndUserLocked(r,
- PhoneStateListener.LISTEN_DATA_CONNECTION_REAL_TIME_INFO)) {
- try {
- if (DBG_LOC) {
- log("notifyDataConnectionRealTimeInfo: mDcRtInfo="
- + mDcRtInfo + " r=" + r);
- }
- r.callback.onDataConnectionRealTimeInfoChanged(mDcRtInfo);
- } catch (RemoteException ex) {
- mRemoveList.add(r.binder);
- }
- }
- }
- handleRemoveListLocked();
- }
- }
-
@Override
public void notifyMessageWaitingChangedForPhoneId(int phoneId, int subId, boolean mwi) {
if (!checkNotifyPermission("notifyMessageWaitingChanged()")) {
@@ -1370,7 +1336,6 @@
pw.println(" mCellLocation=" + mCellLocation[i]);
pw.println(" mCellInfo=" + mCellInfo.get(i));
}
- pw.println(" mDcRtInfo=" + mDcRtInfo);
pw.println("registrations: count=" + recordCount);
for (Record r : mRecords) {
pw.println(" " + r);
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 2683be6..d0006aa 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -4266,21 +4266,6 @@
}
}
- private boolean isPermitted(String opPackageName, int callingUid, String... permissions) {
- for (String perm : permissions) {
- if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, " caller uid " + callingUid + " has " + perm);
- }
- final int opCode = AppOpsManager.permissionToOpCode(perm);
- if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
- opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
- return true;
- }
- }
- }
- return false;
- }
private int handleIncomingUser(int userId) {
try {
@@ -4355,12 +4340,50 @@
private List<String> getTypesVisibleToCaller(int callingUid, int userId,
String opPackageName) {
- boolean isPermitted =
- isPermitted(opPackageName, callingUid, Manifest.permission.GET_ACCOUNTS,
- Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
+ List<String> permissionsToCheck = new ArrayList<String>(2);
+ permissionsToCheck.add(Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
+ try {
+ ApplicationInfo appInfo = mPackageManager.getApplicationInfo(
+ opPackageName, 0 /* flags */);
+ /*
+ * At or before SDK 23, clients discover all the accounts in their
+ * user profile (via AccountManager.getAccounts(...)) by declaring
+ * the GET_ACCOUNTS permission.
+ *
+ * After SDK 23 the GET_ACCOUNTS permission is deprecated. Instead
+ * apps will be able to retrieve those accounts managed by
+ * authenticators sharing a package signature without any special
+ * permissions. The only clients able to discover all the accounts
+ * on the device will be those with the GET_ACCOUNTS_PRVILEGED
+ * system permission.
+ */
+ if (23 >= appInfo.targetSdkVersion) {
+ permissionsToCheck.add(Manifest.permission.GET_ACCOUNTS);
+ }
+ } catch (NameNotFoundException e) {
+ // No application associated with the specified package.
+ Log.w(TAG, "No application associated with package: " + opPackageName);
+ }
+ boolean isPermitted = isPermitted(opPackageName, callingUid, permissionsToCheck);
return getTypesForCaller(callingUid, userId, isPermitted);
}
+ private boolean isPermitted(String opPackageName, int callingUid, List<String> permissions) {
+ for (String perm : permissions) {
+ if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, " caller uid " + callingUid + " has " + perm);
+ }
+ final int opCode = AppOpsManager.permissionToOpCode(perm);
+ if (opCode == AppOpsManager.OP_NONE || mAppOpsManager.noteOp(
+ opCode, callingUid, opPackageName) == AppOpsManager.MODE_ALLOWED) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
private List<String> getTypesManagedByCaller(int callingUid, int userId) {
return getTypesForCaller(callingUid, userId, false);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 2ee74db..7f783ec 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1242,58 +1242,55 @@
}
@Override
- public void setTopicPriority(String pkg, int uid, Notification.Topic topic, int priority) {
+ public void setPriority(String pkg, int uid, Notification.Topic topic, int priority) {
checkCallerIsSystem();
- mRankingHelper.setTopicPriority(pkg, uid, topic, priority);
+ mRankingHelper.setPriority(pkg, uid, topic, priority);
savePolicyFile();
}
@Override
- public int getTopicPriority(String pkg, int uid, Notification.Topic topic) {
+ public int getPriority(String pkg, int uid, Notification.Topic topic) {
checkCallerIsSystem();
- return mRankingHelper.getTopicPriority(pkg, uid, topic);
+ return mRankingHelper.getPriority(pkg, uid, topic);
}
@Override
- public void setTopicVisibilityOverride(String pkg, int uid, Notification.Topic topic,
+ public void setVisibilityOverride(String pkg, int uid, Notification.Topic topic,
int visibility) {
checkCallerIsSystem();
- mRankingHelper.setTopicVisibilityOverride(pkg, uid, topic, visibility);
+ mRankingHelper.setVisibilityOverride(pkg, uid, topic, visibility);
savePolicyFile();
}
@Override
- public int getTopicVisibilityOverride(String pkg, int uid, Notification.Topic topic) {
+ public int getVisibilityOverride(String pkg, int uid, Notification.Topic topic) {
checkCallerIsSystem();
- return mRankingHelper.getTopicVisibilityOverride(pkg, uid, topic);
+ return mRankingHelper.getVisibilityOverride(pkg, uid, topic);
}
@Override
- public void setTopicImportance(String pkg, int uid, Notification.Topic topic,
+ public void setImportance(String pkg, int uid, Notification.Topic topic,
int importance) {
enforceSystemOrSystemUI("Caller not system or systemui");
- if (NotificationListenerService.Ranking.IMPORTANCE_NONE == importance) {
- cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true,
- UserHandle.getUserId(uid),
- REASON_TOPIC_BANNED, topic, null);
+ if (topic == null) {
+ // App wide, potentially store block in app ops.
+ setNotificationsEnabledForPackageImpl(pkg, uid,
+ importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
+ } else {
+ if (NotificationListenerService.Ranking.IMPORTANCE_NONE == importance) {
+ cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true,
+ UserHandle.getUserId(uid),
+ REASON_TOPIC_BANNED, topic, null);
+ }
}
- mRankingHelper.setTopicImportance(pkg, uid, topic, importance);
+ mRankingHelper.setImportance(pkg, uid, topic, importance);
savePolicyFile();
}
@Override
- public int getTopicImportance(String pkg, int uid, Notification.Topic topic) {
+ public int getImportance(String pkg, int uid, Notification.Topic topic) {
checkCallerIsSystem();
- return mRankingHelper.getTopicImportance(pkg, uid, topic);
- }
-
- @Override
- public void setAppImportance(String pkg, int uid, int importance) {
- enforceSystemOrSystemUI("Caller not system or systemui");
- setNotificationsEnabledForPackageImpl(pkg, uid,
- importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
- mRankingHelper.setAppImportance(pkg, uid, importance);
- savePolicyFile();
+ return mRankingHelper.getImportance(pkg, uid, topic);
}
@Override
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 490e890..484b0e9 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -33,6 +33,7 @@
import android.service.notification.StatusBarNotification;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
import com.android.server.EventLogTags;
import java.io.PrintWriter;
@@ -106,6 +107,7 @@
mCreationTimeMs = sbn.getPostTime();
mUpdateTimeMs = mCreationTimeMs;
mContext = context;
+ stats = new NotificationUsageStats.SingleNotificationStats();
mImportance = defaultImportance();
}
@@ -133,27 +135,22 @@
importance = IMPORTANCE_MAX;
break;
}
+ stats.requestedImportance = importance;
boolean isNoisy = (n.defaults & Notification.DEFAULT_SOUND) != 0
|| (n.defaults & Notification.DEFAULT_VIBRATE) != 0
|| n.sound != null
|| n.vibrate != null;
+ stats.isNoisy = isNoisy;
if (!isNoisy && importance > IMPORTANCE_DEFAULT) {
importance = IMPORTANCE_DEFAULT;
}
- // maybe only do this for target API < N?
- if (isNoisy) {
- if (importance >= IMPORTANCE_HIGH) {
- importance = IMPORTANCE_MAX;
- } else {
- importance = IMPORTANCE_HIGH;
- }
- }
if (n.fullScreenIntent != null) {
importance = IMPORTANCE_MAX;
}
+ stats.naturalImportance = importance;
return importance;
}
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index 1cdc6db..e75324f 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -16,6 +16,8 @@
package com.android.server.notification;
+import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
+
import android.app.Notification;
import android.content.ContentValues;
import android.content.Context;
@@ -101,7 +103,6 @@
* Called when a notification has been posted.
*/
public synchronized void registerPostedByApp(NotificationRecord notification) {
- notification.stats = new SingleNotificationStats();
notification.stats.posttimeElapsedMs = SystemClock.elapsedRealtime();
AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
@@ -119,13 +120,16 @@
* Called when a notification has been updated.
*/
public void registerUpdatedByApp(NotificationRecord notification, NotificationRecord old) {
- notification.stats = old.stats;
+ notification.stats.updateFrom(old.stats);
AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
for (AggregatedStats stats : aggregatedStatsArray) {
stats.numUpdatedByApp++;
stats.countApiUse(notification);
}
releaseAggregatedStatsLocked(aggregatedStatsArray);
+ if (ENABLE_SQLITE_LOG) {
+ mSQLiteLog.logPosted(notification);
+ }
}
/**
@@ -297,10 +301,6 @@
public int numWithActions;
public int numPrivate;
public int numSecret;
- public int numPriorityMax;
- public int numPriorityHigh;
- public int numPriorityLow;
- public int numPriorityMin;
public int numWithBigText;
public int numWithBigPicture;
public int numForegroundService;
@@ -314,11 +314,17 @@
public int numWithSubText;
public int numWithInfoText;
public int numInterrupt;
+ public ImportanceHistogram noisyImportance;
+ public ImportanceHistogram quietImportance;
+ public ImportanceHistogram finalImportance;
public AggregatedStats(Context context, String key) {
this.key = key;
mContext = context;
mCreated = SystemClock.elapsedRealtime();
+ noisyImportance = new ImportanceHistogram(context, "note_imp_noisy_");
+ quietImportance = new ImportanceHistogram(context, "note_imp_quiet_");
+ finalImportance = new ImportanceHistogram(context, "note_importance_");
}
public void countApiUse(NotificationRecord record) {
@@ -354,20 +360,12 @@
break;
}
- switch (n.priority) {
- case Notification.PRIORITY_MAX:
- numPriorityMax++;
- break;
- case Notification.PRIORITY_HIGH:
- numPriorityHigh++;
- break;
- case Notification.PRIORITY_LOW:
- numPriorityLow++;
- break;
- case Notification.PRIORITY_MIN:
- numPriorityMin++;
- break;
+ if (record.stats.isNoisy) {
+ noisyImportance.increment(record.stats.requestedImportance);
+ } else {
+ quietImportance.increment(record.stats.requestedImportance);
}
+ finalImportance.increment(record.getImportance());
final Set<String> names = n.extras.keySet();
if (names.contains(Notification.EXTRA_BIG_TEXT)) {
@@ -419,10 +417,6 @@
maybeCount("note_with_actions", (numWithActions - mPrevious.numWithActions));
maybeCount("note_private", (numPrivate - mPrevious.numPrivate));
maybeCount("note_secret", (numSecret - mPrevious.numSecret));
- maybeCount("note_prio_max", (numPriorityMax - mPrevious.numPriorityMax));
- maybeCount("note_prio_high", (numPriorityHigh - mPrevious.numPriorityHigh));
- maybeCount("note_prio_low", (numPriorityLow - mPrevious.numPriorityLow));
- maybeCount("note_prio_min", (numPriorityMin - mPrevious.numPriorityMin));
maybeCount("note_interupt", (numInterrupt - mPrevious.numInterrupt));
maybeCount("note_big_text", (numWithBigText - mPrevious.numWithBigText));
maybeCount("note_big_pic", (numWithBigPicture - mPrevious.numWithBigPicture));
@@ -436,6 +430,9 @@
maybeCount("note_text", (numWithText - mPrevious.numWithText));
maybeCount("note_sub_text", (numWithSubText - mPrevious.numWithSubText));
maybeCount("note_info_text", (numWithInfoText - mPrevious.numWithInfoText));
+ noisyImportance.maybeCount(mPrevious.noisyImportance);
+ quietImportance.maybeCount(mPrevious.quietImportance);
+ finalImportance.maybeCount(mPrevious.finalImportance);
mPrevious.numPostedByApp = numPostedByApp;
mPrevious.numUpdatedByApp = numUpdatedByApp;
@@ -448,10 +445,6 @@
mPrevious.numWithActions = numWithActions;
mPrevious.numPrivate = numPrivate;
mPrevious.numSecret = numSecret;
- mPrevious.numPriorityMax = numPriorityMax;
- mPrevious.numPriorityHigh = numPriorityHigh;
- mPrevious.numPriorityLow = numPriorityLow;
- mPrevious.numPriorityMin = numPriorityMin;
mPrevious.numInterrupt = numInterrupt;
mPrevious.numWithBigText = numWithBigText;
mPrevious.numWithBigPicture = numWithBigPicture;
@@ -465,6 +458,9 @@
mPrevious.numWithText = numWithText;
mPrevious.numWithSubText = numWithSubText;
mPrevious.numWithInfoText = numWithInfoText;
+ noisyImportance.update(mPrevious.noisyImportance);
+ quietImportance.update(mPrevious.quietImportance);
+ finalImportance.update(mPrevious.finalImportance);
}
void maybeCount(String name, int value) {
@@ -483,17 +479,64 @@
}
private String toStringWithIndent(String indent) {
- return indent + "AggregatedStats{\n" +
- indent + " key='" + key + "',\n" +
- indent + " numPostedByApp=" + numPostedByApp + ",\n" +
- indent + " numUpdatedByApp=" + numUpdatedByApp + ",\n" +
- indent + " numRemovedByApp=" + numRemovedByApp + ",\n" +
- indent + " numPeopleCacheHit=" + numPeopleCacheHit + ",\n" +
- indent + " numWithStaredPeople=" + numWithStaredPeople + ",\n" +
- indent + " numWithValidPeople=" + numWithValidPeople + ",\n" +
- indent + " numPeopleCacheMiss=" + numPeopleCacheMiss + ",\n" +
- indent + " numBlocked=" + numBlocked + ",\n" +
- indent + "}";
+ StringBuilder output = new StringBuilder();
+ output.append(indent).append("AggregatedStats{\n");
+ String indentPlusTwo = indent + " ";
+ output.append(indentPlusTwo);
+ output.append("key='").append(key).append("',\n");
+ output.append(indentPlusTwo);
+ output.append("numPostedByApp=").append(numPostedByApp).append(",\n");
+ output.append(indentPlusTwo);
+ output.append("numUpdatedByApp=").append(numUpdatedByApp).append(",\n");
+ output.append(indentPlusTwo);
+ output.append("numRemovedByApp=").append(numRemovedByApp).append(",\n");
+ output.append(indentPlusTwo);
+ output.append("numPeopleCacheHit=").append(numPeopleCacheHit).append(",\n");
+ output.append(indentPlusTwo);
+ output.append("numWithStaredPeople=").append(numWithStaredPeople).append(",\n");
+ output.append(indentPlusTwo);
+ output.append("numWithValidPeople=").append(numWithValidPeople).append(",\n");
+ output.append(indentPlusTwo);
+ output.append("numPeopleCacheMiss=").append(numPeopleCacheMiss).append(",\n");
+ output.append(indentPlusTwo);
+ output.append("numBlocked=").append(numBlocked).append(",\n");
+ output.append(indentPlusTwo);
+ output.append("numWithActions=").append(numWithActions).append(",\n");
+ output.append(indentPlusTwo);
+ output.append("numPrivate=").append(numPrivate).append(",\n");
+ output.append(indentPlusTwo);
+ output.append("numSecret=").append(numSecret).append(",\n");
+ output.append(indentPlusTwo);
+ output.append("numInterrupt=").append(numInterrupt).append(",\n");
+ output.append(indentPlusTwo);
+ output.append("numWithBigText=").append(numWithBigText).append(",\n");
+ output.append(indentPlusTwo);
+ output.append("numWithBigPicture=").append(numWithBigPicture).append("\n");
+ output.append(indentPlusTwo);
+ output.append("numForegroundService=").append(numForegroundService).append("\n");
+ output.append(indentPlusTwo);
+ output.append("numOngoing=").append(numOngoing).append("\n");
+ output.append(indentPlusTwo);
+ output.append("numAutoCancel=").append(numAutoCancel).append("\n");
+ output.append(indentPlusTwo);
+ output.append("numWithLargeIcon=").append(numWithLargeIcon).append("\n");
+ output.append(indentPlusTwo);
+ output.append("numWithInbox=").append(numWithInbox).append("\n");
+ output.append(indentPlusTwo);
+ output.append("numWithMediaSession=").append(numWithMediaSession).append("\n");
+ output.append(indentPlusTwo);
+ output.append("numWithTitle=").append(numWithTitle).append("\n");
+ output.append(indentPlusTwo);
+ output.append("numWithText=").append(numWithText).append("\n");
+ output.append(indentPlusTwo);
+ output.append("numWithSubText=").append(numWithSubText).append("\n");
+ output.append(indentPlusTwo);
+ output.append("numWithInfoText=").append(numWithInfoText).append("\n");
+ output.append(indentPlusTwo).append(noisyImportance.toString()).append("\n");
+ output.append(indentPlusTwo).append(quietImportance.toString()).append("\n");
+ output.append(indentPlusTwo).append(finalImportance.toString()).append("\n");
+ output.append(indent).append("}");
+ return output.toString();
}
public JSONObject dumpJson() throws JSONException {
@@ -511,10 +554,6 @@
maybePut(dump, "numWithActions", numWithActions);
maybePut(dump, "numPrivate", numPrivate);
maybePut(dump, "numSecret", numSecret);
- maybePut(dump, "numPriorityMax", numPriorityMax);
- maybePut(dump, "numPriorityHigh", numPriorityHigh);
- maybePut(dump, "numPriorityLow", numPriorityLow);
- maybePut(dump, "numPriorityMin", numPriorityMin);
maybePut(dump, "numInterrupt", numInterrupt);
maybePut(dump, "numWithBigText", numWithBigText);
maybePut(dump, "numWithBigPicture", numWithBigPicture);
@@ -528,6 +567,10 @@
maybePut(dump, "numWithText", numWithText);
maybePut(dump, "numWithSubText", numWithSubText);
maybePut(dump, "numWithInfoText", numWithInfoText);
+ noisyImportance.maybePut(dump, mPrevious.noisyImportance);
+ quietImportance.maybePut(dump, mPrevious.quietImportance);
+ finalImportance.maybePut(dump, mPrevious.finalImportance);
+
return dump;
}
@@ -538,6 +581,65 @@
}
}
+ private static class ImportanceHistogram {
+ // TODO define these somewhere else
+ private static final int NUM_IMPORTANCES = 5;
+ private static final String[] IMPORTANCE_NAMES = {"none", "low", "default", "high", "max"};
+ private final Context mContext;
+ private final String[] mCounterNames;
+ private final String mPrefix;
+ private int[] mCount;
+
+ ImportanceHistogram(Context context, String prefix) {
+ mContext = context;
+ mCount = new int[NUM_IMPORTANCES];
+ mCounterNames = new String[NUM_IMPORTANCES];
+ mPrefix = prefix;
+ for (int i = 0; i < NUM_IMPORTANCES; i++) {
+ mCounterNames[i] = mPrefix + IMPORTANCE_NAMES[i];
+ }
+ }
+
+ void increment(int imp) {
+ imp = imp < 0 ? 0 : imp > NUM_IMPORTANCES ? NUM_IMPORTANCES : imp;
+ mCount[imp] ++;
+ }
+
+ void maybeCount(ImportanceHistogram prev) {
+ for (int i = 0; i < NUM_IMPORTANCES; i++) {
+ final int value = mCount[i] - prev.mCount[i];
+ if (value > 0) {
+ MetricsLogger.count(mContext, mCounterNames[i], value);
+ }
+ }
+ }
+
+ void update(ImportanceHistogram that) {
+ for (int i = 0; i < NUM_IMPORTANCES; i++) {
+ mCount[i] = that.mCount[i];
+ }
+ }
+
+ public void maybePut(JSONObject dump, ImportanceHistogram prev)
+ throws JSONException {
+ dump.put(mPrefix, new JSONArray(mCount));
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder output = new StringBuilder();
+ output.append(mPrefix).append(": [");
+ for (int i = 0; i < NUM_IMPORTANCES; i++) {
+ output.append(mCount[i]);
+ if (i < (NUM_IMPORTANCES-1)) {
+ output.append(", ");
+ }
+ }
+ output.append("]");
+ return output.toString();
+ }
+ }
+
/**
* Tracks usage of an individual notification that is currently active.
*/
@@ -575,6 +677,12 @@
public long airtimeExpandedMs = 0;
/** Number of times the notification has been expanded by the user. */
public long userExpansionCount = 0;
+ /** Importance directly requested by the app. */
+ public int requestedImportance;
+ /** Did the app include sound or vibration on the notificaiton. */
+ public boolean isNoisy;
+ /** Importance after initial filtering for noise and other features */
+ public int naturalImportance;
public long getCurrentPosttimeMs() {
if (posttimeElapsedMs < 0) {
@@ -686,17 +794,40 @@
@Override
public String toString() {
- return "SingleNotificationStats{" +
- "posttimeElapsedMs=" + posttimeElapsedMs +
- ", posttimeToFirstClickMs=" + posttimeToFirstClickMs +
- ", posttimeToDismissMs=" + posttimeToDismissMs +
- ", airtimeCount=" + airtimeCount +
- ", airtimeMs=" + airtimeMs +
- ", currentAirtimeStartElapsedMs=" + currentAirtimeStartElapsedMs +
- ", airtimeExpandedMs=" + airtimeExpandedMs +
- ", posttimeToFirstVisibleExpansionMs=" + posttimeToFirstVisibleExpansionMs +
- ", currentAirtimeExpandedSEMs=" + currentAirtimeExpandedStartElapsedMs +
- '}';
+ StringBuilder output = new StringBuilder();
+ output.append("SingleNotificationStats{");
+
+ output.append("posttimeElapsedMs=").append(posttimeElapsedMs).append(", ");
+ output.append("posttimeToFirstClickMs=").append(posttimeToFirstClickMs).append(", ");
+ output.append("posttimeToDismissMs=").append(posttimeToDismissMs).append(", ");
+ output.append("airtimeCount=").append(airtimeCount).append(", ");
+ output.append("airtimeMs=").append(airtimeMs).append(", ");
+ output.append("currentAirtimeStartElapsedMs=").append(currentAirtimeStartElapsedMs)
+ .append(", ");
+ output.append("airtimeExpandedMs=").append(airtimeExpandedMs).append(", ");
+ output.append("posttimeToFirstVisibleExpansionMs=")
+ .append(posttimeToFirstVisibleExpansionMs).append(", ");
+ output.append("currentAirtimeExpandedStartElapsedMs=")
+ .append(currentAirtimeExpandedStartElapsedMs).append(", ");
+ output.append("requestedImportance=").append(requestedImportance).append(", ");
+ output.append("naturalImportance=").append(naturalImportance).append(", ");
+ output.append("isNoisy=").append(isNoisy);
+ output.append('}');
+ return output.toString();
+ }
+
+ /** Copy useful information out of the stats from the pre-update notifications. */
+ public void updateFrom(SingleNotificationStats old) {
+ posttimeElapsedMs = old.posttimeElapsedMs;
+ posttimeToFirstClickMs = old.posttimeToFirstClickMs;
+ airtimeCount = old.airtimeCount;
+ posttimeToFirstAirtimeMs = old.posttimeToFirstAirtimeMs;
+ currentAirtimeStartElapsedMs = old.currentAirtimeStartElapsedMs;
+ airtimeMs = old.airtimeMs;
+ posttimeToFirstVisibleExpansionMs = old.posttimeToFirstVisibleExpansionMs;
+ currentAirtimeExpandedStartElapsedMs = old.currentAirtimeExpandedStartElapsedMs;
+ airtimeExpandedMs = old.airtimeExpandedMs;
+ userExpansionCount = old.userExpansionCount;
}
}
@@ -741,7 +872,7 @@
private static final int MSG_DISMISS = 4;
private static final String DB_NAME = "notification_log.db";
- private static final int DB_VERSION = 4;
+ private static final int DB_VERSION = 5;
/** Age in ms after which events are pruned from the DB. */
private static final long HORIZON_MS = 7 * 24 * 60 * 60 * 1000L; // 1 week
@@ -762,7 +893,11 @@
private static final String COL_WHEN_MS = "when_ms";
private static final String COL_DEFAULTS = "defaults";
private static final String COL_FLAGS = "flags";
- private static final String COL_PRIORITY = "priority";
+ private static final String COL_IMPORTANCE_REQ = "importance_request";
+ private static final String COL_IMPORTANCE_FINAL = "importance_final";
+ private static final String COL_NOISY = "noisy";
+ private static final String COL_MUTED = "muted";
+ private static final String COL_DEMOTED = "demoted";
private static final String COL_CATEGORY = "category";
private static final String COL_ACTION_COUNT = "action_count";
private static final String COL_POSTTIME_MS = "posttime_ms";
@@ -776,14 +911,28 @@
private static final int EVENT_TYPE_CLICK = 2;
private static final int EVENT_TYPE_REMOVE = 3;
private static final int EVENT_TYPE_DISMISS = 4;
-
private static long sLastPruneMs;
+
private static long sNumWrites;
-
private final SQLiteOpenHelper mHelper;
- private final Handler mWriteHandler;
+ private final Handler mWriteHandler;
private static final long DAY_MS = 24 * 60 * 60 * 1000;
+ private static final String STATS_QUERY = "SELECT " +
+ COL_EVENT_USER_ID + ", " +
+ COL_PKG + ", " +
+ // Bucket by day by looking at 'floor((midnight - eventTimeMs) / dayMs)'
+ "CAST(((%d - " + COL_EVENT_TIME + ") / " + DAY_MS + ") AS int) " +
+ "AS day, " +
+ "COUNT(*) AS cnt, " +
+ "SUM(" + COL_MUTED + ") as muted, " +
+ "SUM(" + COL_NOISY + ") as noisy, " +
+ "SUM(" + COL_DEMOTED + ") as demoted " +
+ "FROM " + TAB_LOG + " " +
+ "WHERE " +
+ COL_EVENT_TYPE + "=" + EVENT_TYPE_POST +
+ " AND " + COL_EVENT_TIME + " > %d " +
+ " GROUP BY " + COL_EVENT_USER_ID + ", day, " + COL_PKG;
public SQLiteLog(Context context) {
HandlerThread backgroundThread = new HandlerThread("notification-sqlite-log",
@@ -828,7 +977,11 @@
COL_WHEN_MS + " INT," +
COL_DEFAULTS + " INT," +
COL_FLAGS + " INT," +
- COL_PRIORITY + " INT," +
+ COL_IMPORTANCE_REQ + " INT," +
+ COL_IMPORTANCE_FINAL + " INT," +
+ COL_NOISY + " INT," +
+ COL_MUTED + " INT," +
+ COL_DEMOTED + " INT," +
COL_CATEGORY + " TEXT," +
COL_ACTION_COUNT + " INT," +
COL_POSTTIME_MS + " INT," +
@@ -841,8 +994,7 @@
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- if (oldVersion <= 3) {
- // Version 3 creation left 'log' in a weird state. Just reset for now.
+ if (oldVersion != newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TAB_LOG);
onCreate(db);
}
@@ -866,22 +1018,11 @@
mWriteHandler.sendMessage(mWriteHandler.obtainMessage(MSG_DISMISS, notification));
}
- private JSONArray JsonPostFrequencies(DumpFilter filter) throws JSONException {
+ private JSONArray jsonPostFrequencies(DumpFilter filter) throws JSONException {
JSONArray frequencies = new JSONArray();
SQLiteDatabase db = mHelper.getReadableDatabase();
long midnight = getMidnightMs();
- String q = "SELECT " +
- COL_EVENT_USER_ID + ", " +
- COL_PKG + ", " +
- // Bucket by day by looking at 'floor((midnight - eventTimeMs) / dayMs)'
- "CAST(((" + midnight + " - " + COL_EVENT_TIME + ") / " + DAY_MS + ") AS int) " +
- "AS day, " +
- "COUNT(*) AS cnt " +
- "FROM " + TAB_LOG + " " +
- "WHERE " +
- COL_EVENT_TYPE + "=" + EVENT_TYPE_POST +
- " AND " + COL_EVENT_TIME + " > " + filter.since +
- " GROUP BY " + COL_EVENT_USER_ID + ", day, " + COL_PKG;
+ String q = String.format(STATS_QUERY, midnight, filter.since);
Cursor cursor = db.rawQuery(q, null);
try {
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
@@ -890,11 +1031,17 @@
if (filter != null && !filter.matches(pkg)) continue;
int day = cursor.getInt(2);
int count = cursor.getInt(3);
+ int muted = cursor.getInt(4);
+ int noisy = cursor.getInt(5);
+ int demoted = cursor.getInt(6);
JSONObject row = new JSONObject();
row.put("user_id", userId);
row.put("package", pkg);
row.put("day", day);
row.put("count", count);
+ row.put("noisy", noisy);
+ row.put("muted", muted);
+ row.put("demoted", demoted);
frequencies.put(row);
}
} finally {
@@ -906,17 +1053,7 @@
public void printPostFrequencies(PrintWriter pw, String indent, DumpFilter filter) {
SQLiteDatabase db = mHelper.getReadableDatabase();
long midnight = getMidnightMs();
- String q = "SELECT " +
- COL_EVENT_USER_ID + ", " +
- COL_PKG + ", " +
- // Bucket by day by looking at 'floor((midnight - eventTimeMs) / dayMs)'
- "CAST(((" + midnight + " - " + COL_EVENT_TIME + ") / " + DAY_MS + ") AS int) " +
- "AS day, " +
- "COUNT(*) AS cnt " +
- "FROM " + TAB_LOG + " " +
- "WHERE " +
- COL_EVENT_TYPE + "=" + EVENT_TYPE_POST + " " +
- "GROUP BY " + COL_EVENT_USER_ID + ", day, " + COL_PKG;
+ String q = String.format(STATS_QUERY, midnight, filter.since);
Cursor cursor = db.rawQuery(q, null);
try {
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
@@ -925,8 +1062,12 @@
if (filter != null && !filter.matches(pkg)) continue;
int day = cursor.getInt(2);
int count = cursor.getInt(3);
+ int muted = cursor.getInt(4);
+ int noisy = cursor.getInt(5);
+ int demoted = cursor.getInt(6);
pw.println(indent + "post_frequency{user_id=" + userId + ",pkg=" + pkg +
- ",day=" + day + ",count=" + count + "}");
+ ",day=" + day + ",count=" + count + ",muted=" + muted + "/" + noisy +
+ ",demoted=" + demoted + "}");
}
} finally {
cursor.close();
@@ -985,7 +1126,18 @@
}
outCv.put(COL_WHEN_MS, r.sbn.getPostTime());
outCv.put(COL_FLAGS, r.getNotification().flags);
- outCv.put(COL_PRIORITY, r.getNotification().priority);
+ final int before = r.stats.requestedImportance;
+ final int after = r.getImportance();
+ final boolean noisy = r.stats.isNoisy;
+ outCv.put(COL_IMPORTANCE_REQ, before);
+ outCv.put(COL_IMPORTANCE_FINAL, after);
+ outCv.put(COL_DEMOTED, after < before ? 1 : 0);
+ outCv.put(COL_NOISY, noisy);
+ if (noisy && after < IMPORTANCE_HIGH) {
+ outCv.put(COL_MUTED, 1);
+ } else {
+ outCv.put(COL_MUTED, 0);
+ }
if (r.getNotification().category != null) {
outCv.put(COL_CATEGORY, r.getNotification().category);
}
@@ -1008,7 +1160,9 @@
public JSONObject dumpJson(DumpFilter filter) {
JSONObject dump = new JSONObject();
try {
- dump.put("post_frequency", JsonPostFrequencies(filter));
+ dump.put("post_frequency", jsonPostFrequencies(filter));
+ dump.put("since", filter.since);
+ dump.put("now", System.currentTimeMillis());
} catch (JSONException e) {
// pass
}
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 9b10ef2..7f85e1f 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -23,20 +23,18 @@
List<Notification.Topic> getTopics(String packageName, int uid);
- int getTopicPriority(String packageName, int uid, Notification.Topic topic);
+ int getPriority(String packageName, int uid, Notification.Topic topic);
- void setTopicPriority(String packageName, int uid, Notification.Topic topic, int priority);
+ void setPriority(String packageName, int uid, Notification.Topic topic, int priority);
- int getTopicVisibilityOverride(String packageName, int uid, Notification.Topic topic);
+ int getVisibilityOverride(String packageName, int uid, Notification.Topic topic);
- void setTopicVisibilityOverride(String packageName, int uid, Notification.Topic topic,
+ void setVisibilityOverride(String packageName, int uid, Notification.Topic topic,
int visibility);
- void setTopicImportance(String packageName, int uid, Notification.Topic topic, int importance);
+ void setImportance(String packageName, int uid, Notification.Topic topic, int importance);
- int getTopicImportance(String packageName, int uid, Notification.Topic topic);
-
- void setAppImportance(String packageName, int uid, int importance);
+ int getImportance(String packageName, int uid, Notification.Topic topic);
boolean doesAppUseTopics(String packageName, int uid);
}
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index ce4ecd3..827482f 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -164,6 +164,8 @@
r = getOrCreateRecord(name, uid);
}
r.importance = safeInt(parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE);
+ r.priority = priority;
+ r.visibility = vis;
// Migrate package level settings to the default topic.
// Might be overwritten by parseTopics.
@@ -245,7 +247,15 @@
}
out.startTag(null, TAG_PACKAGE);
out.attribute(null, ATT_NAME, r.pkg);
- out.attribute(null, ATT_IMPORTANCE, Integer.toString(r.importance));
+ if (r.importance != DEFAULT_IMPORTANCE) {
+ out.attribute(null, ATT_IMPORTANCE, Integer.toString(r.importance));
+ }
+ if (r.priority != DEFAULT_PRIORITY) {
+ out.attribute(null, ATT_PRIORITY, Integer.toString(r.priority));
+ }
+ if (r.visibility != DEFAULT_VISIBILITY) {
+ out.attribute(null, ATT_VISIBILITY, Integer.toString(r.visibility));
+ }
if (!forBackup) {
out.attribute(null, ATT_UID, Integer.toString(r.uid));
@@ -373,66 +383,109 @@
public List<Notification.Topic> getTopics(String packageName, int uid) {
final Record r = getOrCreateRecord(packageName, uid);
List<Notification.Topic> topics = new ArrayList<>();
- for (Topic t : r.topics.values()) {
+ for (Topic t : r.topics.values()) {
topics.add(t.topic);
}
return topics;
}
+ /**
+ * Gets priority. If a topic is given, returns the priority of that topic. Otherwise, the
+ * priority of the app.
+ */
@Override
- public int getTopicPriority(String packageName, int uid, Notification.Topic topic) {
+ public int getPriority(String packageName, int uid, Notification.Topic topic) {
final Record r = getOrCreateRecord(packageName, uid);
+ if (topic == null) {
+ return r.priority;
+ }
return getOrCreateTopic(r, topic).priority;
}
+ /**
+ * Sets priority. If a topic is given, sets the priority of that topic. If not,
+ * sets the default priority for all new topics that appear in the future, and resets
+ * the priority of all current topics.
+ */
@Override
- public void setTopicPriority(String packageName, int uid, Notification.Topic topic,
+ public void setPriority(String packageName, int uid, Notification.Topic topic,
int priority) {
final Record r = getOrCreateRecord(packageName, uid);
- getOrCreateTopic(r, topic).priority = priority;
- updateConfig();
- }
-
- @Override
- public int getTopicVisibilityOverride(String packageName, int uid, Notification.Topic topic) {
- final Record r = getOrCreateRecord(packageName, uid);
- return getOrCreateTopic(r, topic).visibility;
- }
-
- @Override
- public void setTopicVisibilityOverride(String pkgName, int uid, Notification.Topic topic,
- int visibility) {
- final Record r = getOrCreateRecord(pkgName, uid);
- getOrCreateTopic(r, topic).visibility = visibility;
- updateConfig();
- }
-
- @Override
- public int getTopicImportance(String packageName, int uid, Notification.Topic topic) {
- final Record r = getOrCreateRecord(packageName, uid);
- return getOrCreateTopic(r, topic).importance;
- }
-
- @Override
- public void setTopicImportance(String pkgName, int uid, Notification.Topic topic,
- int importance) {
- final Record r = getOrCreateRecord(pkgName, uid);
- getOrCreateTopic(r, topic).importance = importance;
+ if (topic == null) {
+ r.priority = priority;
+ for (Topic t : r.topics.values()) {
+ t.priority = priority;
+ }
+ } else {
+ getOrCreateTopic(r, topic).priority = priority;
+ }
updateConfig();
}
/**
- * Sets the default importance for all new topics that appear in the future, and resets
+ * Gets visual override. If a topic is given, returns the override of that topic. Otherwise, the
+ * override of the app.
+ */
+ @Override
+ public int getVisibilityOverride(String packageName, int uid, Notification.Topic topic) {
+ final Record r = getOrCreateRecord(packageName, uid);
+ if (topic == null) {
+ return r.visibility;
+ }
+ return getOrCreateTopic(r, topic).visibility;
+ }
+
+ /**
+ * Sets visibility override. If a topic is given, sets the override of that topic. If not,
+ * sets the default override for all new topics that appear in the future, and resets
+ * the override of all current topics.
+ */
+ @Override
+ public void setVisibilityOverride(String pkgName, int uid, Notification.Topic topic,
+ int visibility) {
+ final Record r = getOrCreateRecord(pkgName, uid);
+ if (topic == null) {
+ r.visibility = visibility;
+ for (Topic t : r.topics.values()) {
+ t.visibility = visibility;
+ }
+ } else {
+ getOrCreateTopic(r, topic).visibility = visibility;
+ }
+ updateConfig();
+ }
+
+ /**
+ * Gets importance. If a topic is given, returns the importance of that topic. Otherwise, the
+ * importance of the app.
+ */
+ @Override
+ public int getImportance(String packageName, int uid, Notification.Topic topic) {
+ final Record r = getOrCreateRecord(packageName, uid);
+ if (topic == null) {
+ return r.importance;
+ }
+ return getOrCreateTopic(r, topic).importance;
+ }
+
+ /**
+ * Sets importance. If a topic is given, sets the importance of that topic. If not, sets the
+ * default importance for all new topics that appear in the future, and resets
* the importance of all current topics (unless the app is being blocked).
*/
@Override
- public void setAppImportance(String pkgName, int uid, int importance) {
+ public void setImportance(String pkgName, int uid, Notification.Topic topic,
+ int importance) {
final Record r = getOrCreateRecord(pkgName, uid);
- r.importance = importance;
- if (Ranking.IMPORTANCE_NONE != importance) {
- for (Topic t : r.topics.values()) {
- t.importance = importance;
+ if (topic == null) {
+ r.importance = importance;
+ if (Ranking.IMPORTANCE_NONE != importance) {
+ for (Topic t : r.topics.values()) {
+ t.importance = importance;
+ }
}
+ } else {
+ getOrCreateTopic(r, topic).importance = importance;
}
updateConfig();
}
@@ -459,6 +512,8 @@
} else {
t = new Topic(topic);
t.importance = r.importance;
+ t.priority = r.priority;
+ t.visibility = r.visibility;
r.topics.put(topic.getId(), t);
return t;
}
@@ -503,8 +558,18 @@
pw.print(" (");
pw.print(r.uid == Record.UNKNOWN_UID ? "UNKNOWN_UID" : Integer.toString(r.uid));
pw.print(')');
- pw.print(" importance=");
- pw.print(Ranking.importanceToString(r.importance));
+ if (r.importance != DEFAULT_IMPORTANCE) {
+ pw.print(" importance=");
+ pw.print(Ranking.importanceToString(r.importance));
+ }
+ if (r.priority != DEFAULT_PRIORITY) {
+ pw.print(" priority=");
+ pw.print(Ranking.importanceToString(r.priority));
+ }
+ if (r.visibility != DEFAULT_VISIBILITY) {
+ pw.print(" visibility=");
+ pw.print(Ranking.importanceToString(r.visibility));
+ }
pw.println();
for (Topic t : r.topics.values()) {
pw.print(prefix);
@@ -561,6 +626,8 @@
String pkg;
int uid = UNKNOWN_UID;
int importance = DEFAULT_IMPORTANCE;
+ int priority = DEFAULT_PRIORITY;
+ int visibility = DEFAULT_VISIBILITY;
Map<String, Topic> topics = new ArrayMap<>();
}
diff --git a/services/core/java/com/android/server/notification/TopicImportanceExtractor.java b/services/core/java/com/android/server/notification/TopicImportanceExtractor.java
index 01770d0..c6b3e0f 100644
--- a/services/core/java/com/android/server/notification/TopicImportanceExtractor.java
+++ b/services/core/java/com/android/server/notification/TopicImportanceExtractor.java
@@ -42,7 +42,7 @@
return null;
}
- final int topicImportance = mConfig.getTopicImportance(record.sbn.getPackageName(),
+ final int topicImportance = mConfig.getImportance(record.sbn.getPackageName(),
record.sbn.getUid(), record.sbn.getNotification().getTopic());
record.setTopicImportance(topicImportance);
diff --git a/services/core/java/com/android/server/notification/TopicPriorityExtractor.java b/services/core/java/com/android/server/notification/TopicPriorityExtractor.java
index 5bf989ae..1df5c2b 100644
--- a/services/core/java/com/android/server/notification/TopicPriorityExtractor.java
+++ b/services/core/java/com/android/server/notification/TopicPriorityExtractor.java
@@ -42,7 +42,7 @@
return null;
}
- final int packagePriority = mConfig.getTopicPriority(record.sbn.getPackageName(),
+ final int packagePriority = mConfig.getPriority(record.sbn.getPackageName(),
record.sbn.getUid(), record.sbn.getNotification().getTopic());
record.setPackagePriority(packagePriority);
diff --git a/services/core/java/com/android/server/notification/TopicVisibilityExtractor.java b/services/core/java/com/android/server/notification/TopicVisibilityExtractor.java
index e053382..eaa3ed3 100644
--- a/services/core/java/com/android/server/notification/TopicVisibilityExtractor.java
+++ b/services/core/java/com/android/server/notification/TopicVisibilityExtractor.java
@@ -42,7 +42,7 @@
return null;
}
- final int packageVisibility = mConfig.getTopicVisibilityOverride(
+ final int packageVisibility = mConfig.getVisibilityOverride(
record.sbn.getPackageName(), record.sbn.getUid(),
record.sbn.getNotification().getTopic());
record.setPackageVisibilityOverride(packageVisibility);
diff --git a/services/core/java/com/android/server/wm/DropPermissionsHandler.java b/services/core/java/com/android/server/wm/DropPermissionsHandler.java
index 68cfaab..5889fb8 100644
--- a/services/core/java/com/android/server/wm/DropPermissionsHandler.java
+++ b/services/core/java/com/android/server/wm/DropPermissionsHandler.java
@@ -27,7 +27,7 @@
import java.util.ArrayList;
-class DropPermissionsHandler extends IDropPermissions.Stub {
+class DropPermissionsHandler extends IDropPermissions.Stub implements IBinder.DeathRecipient {
private final int mSourceUid;
private final String mTargetPackage;
@@ -38,6 +38,7 @@
private final ArrayList<Uri> mUris = new ArrayList<Uri>();
private IBinder mActivityToken = null;
+ private IBinder mPermissionOwnerToken = null;
DropPermissionsHandler(ClipData clipData, int sourceUid, String targetPackage, int mode,
int sourceUserId, int targetUserId) {
@@ -52,7 +53,7 @@
@Override
public void take(IBinder activityToken) throws RemoteException {
- if (mActivityToken != null) {
+ if (mActivityToken != null || mPermissionOwnerToken != null) {
return;
}
mActivityToken = activityToken;
@@ -61,6 +62,10 @@
IBinder permissionOwner = ActivityManagerNative.getDefault().
getUriPermissionOwnerForActivity(mActivityToken);
+ doTake(permissionOwner);
+ }
+
+ private void doTake(IBinder permissionOwner) throws RemoteException {
long origId = Binder.clearCallingIdentity();
try {
for (int i = 0; i < mUris.size(); i++) {
@@ -74,20 +79,37 @@
}
@Override
+ public void takeTransient(IBinder permissionOwnerToken) throws RemoteException {
+ if (mActivityToken != null || mPermissionOwnerToken != null) {
+ return;
+ }
+ mPermissionOwnerToken = permissionOwnerToken;
+ mPermissionOwnerToken.linkToDeath(this, 0);
+
+ doTake(mPermissionOwnerToken);
+ }
+
+ @Override
public void release() throws RemoteException {
- if (mActivityToken == null) {
+ if (mActivityToken == null && mPermissionOwnerToken == null) {
return;
}
IBinder permissionOwner = null;
- try {
- permissionOwner = ActivityManagerNative.getDefault().
- getUriPermissionOwnerForActivity(mActivityToken);
- } catch (Exception e) {
- // Activity is destroyed, permissions already revoked.
- return;
- } finally {
- mActivityToken = null;
+ if (mActivityToken != null) {
+ try {
+ permissionOwner = ActivityManagerNative.getDefault().
+ getUriPermissionOwnerForActivity(mActivityToken);
+ } catch (Exception e) {
+ // Activity is destroyed, permissions already revoked.
+ return;
+ } finally {
+ mActivityToken = null;
+ }
+ } else {
+ permissionOwner = mPermissionOwnerToken;
+ mPermissionOwnerToken.unlinkToDeath(this, 0);
+ mPermissionOwnerToken = null;
}
for (int i = 0; i < mUris.size(); ++i) {
@@ -95,4 +117,13 @@
permissionOwner, mUris.get(i), mMode, mSourceUserId);
}
}
+
+ @Override
+ public void binderDied() {
+ try {
+ release();
+ } catch (RemoteException e) {
+ // Cannot happen, local call.
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 5adf627..93a1015 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5349,9 +5349,31 @@
rebuildAppWindowListLocked(displayContent);
}
mWindowPlacerLocked.performSurfacePlacement();
+
+ // Notify whether the docked stack exists for the current user
+ getDefaultDisplayContentLocked().mDividerControllerLocked
+ .notifyDockedStackExistsChanged(hasDockedTasksForUser(newUserId));
}
}
+ /**
+ * Returns whether there is a docked task for the current user.
+ */
+ boolean hasDockedTasksForUser(int userId) {
+ final TaskStack stack = mStackIdToStack.get(DOCKED_STACK_ID);
+ if (stack == null) {
+ return false;
+ }
+
+ final ArrayList<Task> tasks = stack.getTasks();
+ boolean hasUserTask = false;
+ for (int i = tasks.size() - 1; i >= 0 && !hasUserTask; i--) {
+ final Task task = tasks.get(i);
+ hasUserTask = (task.mUserId == userId);
+ }
+ return hasUserTask;
+ }
+
/* Called by WindowState */
boolean isCurrentProfileLocked(int userId) {
if (userId == mCurrentUserId) return true;
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 5abb6e7..e6f4177 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -20,6 +20,7 @@
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
import android.Manifest;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.content.ComponentName;
@@ -47,11 +48,11 @@
import android.print.PrinterId;
import android.printservice.PrintServiceInfo;
import android.provider.Settings;
-import android.text.TextUtils;
import android.util.SparseArray;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.Preconditions;
import com.android.server.SystemService;
import java.io.FileDescriptor;
@@ -108,6 +109,10 @@
@Override
public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
PrintAttributes attributes, String packageName, int appId, int userId) {
+ printJobName = Preconditions.checkStringNotEmpty(printJobName);
+ adapter = Preconditions.checkNotNull(adapter);
+ packageName = Preconditions.checkStringNotEmpty(packageName);
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final int resolvedAppId;
final UserState userState;
@@ -153,6 +158,10 @@
@Override
public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) {
+ if (printJobId == null) {
+ return null;
+ }
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final int resolvedAppId;
final UserState userState;
@@ -174,6 +183,8 @@
@Override
public Icon getCustomPrinterIcon(PrinterId printerId, int userId) {
+ printerId = Preconditions.checkNotNull(printerId);
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -193,6 +204,10 @@
@Override
public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
+ if (printJobId == null) {
+ return;
+ }
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final int resolvedAppId;
final UserState userState;
@@ -214,6 +229,10 @@
@Override
public void restartPrintJob(PrintJobId printJobId, int appId, int userId) {
+ if (printJobId == null) {
+ return;
+ }
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final int resolvedAppId;
final UserState userState;
@@ -279,6 +298,8 @@
@Override
public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
int userId) {
+ observer = Preconditions.checkNotNull(observer);
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -299,6 +320,8 @@
@Override
public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
int userId) {
+ observer = Preconditions.checkNotNull(observer);
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -319,6 +342,12 @@
@Override
public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
List<PrinterId> priorityList, int userId) {
+ observer = Preconditions.checkNotNull(observer);
+ if (priorityList != null) {
+ priorityList = Preconditions.checkCollectionElementsNotNull(priorityList,
+ "PrinterId");
+ }
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -338,6 +367,8 @@
@Override
public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId) {
+ observer = Preconditions.checkNotNull(observer);
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -357,6 +388,8 @@
@Override
public void validatePrinters(List<PrinterId> printerIds, int userId) {
+ printerIds = Preconditions.checkCollectionElementsNotNull(printerIds, "PrinterId");
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -376,6 +409,8 @@
@Override
public void startPrinterStateTracking(PrinterId printerId, int userId) {
+ printerId = Preconditions.checkNotNull(printerId);
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -395,6 +430,8 @@
@Override
public void stopPrinterStateTracking(PrinterId printerId, int userId) {
+ printerId = Preconditions.checkNotNull(printerId);
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -415,6 +452,8 @@
@Override
public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
int appId, int userId) throws RemoteException {
+ listener = Preconditions.checkNotNull(listener);
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final int resolvedAppId;
final UserState userState;
@@ -437,6 +476,8 @@
@Override
public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener,
int userId) {
+ listener = Preconditions.checkNotNull(listener);
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -456,6 +497,9 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ fd = Preconditions.checkNotNull(fd);
+ pw = Preconditions.checkNotNull(pw);
+
if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump PrintManager from from pid="
@@ -707,10 +751,8 @@
return userId;
}
- private String resolveCallingPackageNameEnforcingSecurity(String packageName) {
- if (TextUtils.isEmpty(packageName)) {
- return null;
- }
+ private @NonNull String resolveCallingPackageNameEnforcingSecurity(
+ @NonNull String packageName) {
String[] packages = mContext.getPackageManager().getPackagesForUid(
Binder.getCallingUid());
final int packageCount = packages.length;
@@ -719,7 +761,7 @@
return packageName;
}
}
- return null;
+ throw new IllegalArgumentException("packageName has to belong to the caller");
}
private int getCurrentUserId () {
diff --git a/services/print/java/com/android/server/print/RemotePrintService.java b/services/print/java/com/android/server/print/RemotePrintService.java
index 5ee4066..9b99c67 100644
--- a/services/print/java/com/android/server/print/RemotePrintService.java
+++ b/services/print/java/com/android/server/print/RemotePrintService.java
@@ -409,7 +409,7 @@
}
}
- public void startPrinterStateTracking(PrinterId printerId) {
+ public void startPrinterStateTracking(@NonNull PrinterId printerId) {
mHandler.obtainMessage(MyHandler.MSG_START_PRINTER_STATE_TRACKING,
printerId).sendToTarget();
}
@@ -420,7 +420,7 @@
* @param printerId the id of the printer the icon should be loaded for
* @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
*/
- public void requestCustomPrinterIcon(PrinterId printerId) {
+ public void requestCustomPrinterIcon(@NonNull PrinterId printerId) {
try {
if (isBound()) {
mPrintService.requestCustomPrinterIcon(printerId);
@@ -430,7 +430,7 @@
}
}
- private void handleStartPrinterStateTracking(final PrinterId printerId) {
+ private void handleStartPrinterStateTracking(final @NonNull PrinterId printerId) {
throwIfDestroyed();
// Take a note we are tracking the printer.
if (mTrackedPrinterList == null) {
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 78edc4d..fcf2fc8 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -20,6 +20,7 @@
import static android.content.pm.PackageManager.GET_SERVICES;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -176,8 +177,8 @@
}
@SuppressWarnings("deprecation")
- public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
- PrintAttributes attributes, String packageName, int appId) {
+ public Bundle print(@NonNull String printJobName, @NonNull IPrintDocumentAdapter adapter,
+ @Nullable PrintAttributes attributes, @NonNull String packageName, int appId) {
// Create print job place holder.
final PrintJobInfo printJob = new PrintJobInfo();
printJob.setId(new PrintJobId());
@@ -267,7 +268,7 @@
return new ArrayList<PrintJobInfo>(result.values());
}
- public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
+ public PrintJobInfo getPrintJobInfo(@NonNull PrintJobId printJobId, int appId) {
PrintJobInfo printJob = mPrintJobForAppCache.getPrintJob(printJobId, appId);
if (printJob == null) {
printJob = mSpooler.getPrintJobInfo(printJobId, appId);
@@ -290,7 +291,7 @@
* not yet available
* @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
*/
- public Icon getCustomPrinterIcon(PrinterId printerId) {
+ public @Nullable Icon getCustomPrinterIcon(@NonNull PrinterId printerId) {
Icon icon = mSpooler.getCustomPrinterIcon(printerId);
if (icon == null) {
@@ -303,7 +304,7 @@
return icon;
}
- public void cancelPrintJob(PrintJobId printJobId, int appId) {
+ public void cancelPrintJob(@NonNull PrintJobId printJobId, int appId) {
PrintJobInfo printJobInfo = mSpooler.getPrintJobInfo(printJobId, appId);
if (printJobInfo == null) {
return;
@@ -313,15 +314,19 @@
mSpooler.setPrintJobCancelling(printJobId, true);
if (printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
- ComponentName printServiceName = printJobInfo.getPrinterId().getServiceName();
- RemotePrintService printService = null;
- synchronized (mLock) {
- printService = mActiveServices.get(printServiceName);
+ PrinterId printerId = printJobInfo.getPrinterId();
+
+ if (printerId != null) {
+ ComponentName printServiceName = printerId.getServiceName();
+ RemotePrintService printService = null;
+ synchronized (mLock) {
+ printService = mActiveServices.get(printServiceName);
+ }
+ if (printService == null) {
+ return;
+ }
+ printService.onRequestCancelPrintJob(printJobInfo);
}
- if (printService == null) {
- return;
- }
- printService.onRequestCancelPrintJob(printJobInfo);
} else {
// If the print job is failed we do not need cooperation
// from the print service.
@@ -329,7 +334,7 @@
}
}
- public void restartPrintJob(PrintJobId printJobId, int appId) {
+ public void restartPrintJob(@NonNull PrintJobId printJobId, int appId) {
PrintJobInfo printJobInfo = getPrintJobInfo(printJobId, appId);
if (printJobInfo == null || printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
return;
@@ -363,7 +368,7 @@
}
}
- public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer) {
+ public void createPrinterDiscoverySession(@NonNull IPrinterDiscoveryObserver observer) {
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -386,7 +391,7 @@
}
}
- public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer) {
+ public void destroyPrinterDiscoverySession(@NonNull IPrinterDiscoveryObserver observer) {
synchronized (mLock) {
// Already destroyed - nothing to do.
if (mPrinterDiscoverySession == null) {
@@ -397,8 +402,8 @@
}
}
- public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
- List<PrinterId> printerIds) {
+ public void startPrinterDiscovery(@NonNull IPrinterDiscoveryObserver observer,
+ @Nullable List<PrinterId> printerIds) {
synchronized (mLock) {
throwIfDestroyedLocked();
// No services - nothing to do.
@@ -415,7 +420,7 @@
}
}
- public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer) {
+ public void stopPrinterDiscovery(@NonNull IPrinterDiscoveryObserver observer) {
synchronized (mLock) {
throwIfDestroyedLocked();
// No services - nothing to do.
@@ -431,7 +436,7 @@
}
}
- public void validatePrinters(List<PrinterId> printerIds) {
+ public void validatePrinters(@NonNull List<PrinterId> printerIds) {
synchronized (mLock) {
throwIfDestroyedLocked();
// No services - nothing to do.
@@ -447,7 +452,7 @@
}
}
- public void startPrinterStateTracking(PrinterId printerId) {
+ public void startPrinterStateTracking(@NonNull PrinterId printerId) {
synchronized (mLock) {
throwIfDestroyedLocked();
// No services - nothing to do.
@@ -479,7 +484,7 @@
}
}
- public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
+ public void addPrintJobStateChangeListener(@NonNull IPrintJobStateChangeListener listener,
int appId) throws RemoteException {
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -497,7 +502,7 @@
}
}
- public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener) {
+ public void removePrintJobStateChangeListener(@NonNull IPrintJobStateChangeListener listener) {
synchronized (mLock) {
throwIfDestroyedLocked();
if (mPrintJobStateChangeListenerRecords == null) {
@@ -613,7 +618,7 @@
mDestroyed = true;
}
- public void dump(FileDescriptor fd, PrintWriter pw, String prefix) {
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String prefix) {
pw.append(prefix).append("user state ").append(String.valueOf(mUserId)).append(":");
pw.println();
@@ -991,10 +996,10 @@
}
private abstract class PrintJobStateChangeListenerRecord implements DeathRecipient {
- final IPrintJobStateChangeListener listener;
+ @NonNull final IPrintJobStateChangeListener listener;
final int appId;
- public PrintJobStateChangeListenerRecord(IPrintJobStateChangeListener listener,
+ public PrintJobStateChangeListenerRecord(@NonNull IPrintJobStateChangeListener listener,
int appId) throws RemoteException {
this.listener = listener;
this.appId = appId;
@@ -1043,7 +1048,7 @@
.sendToTarget();
}
- public void addObserverLocked(IPrinterDiscoveryObserver observer) {
+ public void addObserverLocked(@NonNull IPrinterDiscoveryObserver observer) {
// Add the observer.
mDiscoveryObservers.register(observer);
@@ -1058,7 +1063,7 @@
}
}
- public void removeObserverLocked(IPrinterDiscoveryObserver observer) {
+ public void removeObserverLocked(@NonNull IPrinterDiscoveryObserver observer) {
// Remove the observer.
mDiscoveryObservers.unregister(observer);
// No one else observing - then kill it.
@@ -1067,8 +1072,8 @@
}
}
- public final void startPrinterDiscoveryLocked(IPrinterDiscoveryObserver observer,
- List<PrinterId> priorityList) {
+ public final void startPrinterDiscoveryLocked(@NonNull IPrinterDiscoveryObserver observer,
+ @Nullable List<PrinterId> priorityList) {
if (mIsDestroyed) {
Log.w(LOG_TAG, "Not starting dicovery - session destroyed");
return;
@@ -1101,7 +1106,7 @@
.sendToTarget();
}
- public final void stopPrinterDiscoveryLocked(IPrinterDiscoveryObserver observer) {
+ public final void stopPrinterDiscoveryLocked(@NonNull IPrinterDiscoveryObserver observer) {
if (mIsDestroyed) {
Log.w(LOG_TAG, "Not stopping dicovery - session destroyed");
return;
@@ -1121,7 +1126,7 @@
.sendToTarget();
}
- public void validatePrintersLocked(List<PrinterId> printerIds) {
+ public void validatePrintersLocked(@NonNull List<PrinterId> printerIds) {
if (mIsDestroyed) {
Log.w(LOG_TAG, "Not validating pritners - session destroyed");
return;
@@ -1135,13 +1140,15 @@
ComponentName serviceName = null;
while (iterator.hasNext()) {
PrinterId printerId = iterator.next();
- if (updateList.isEmpty()) {
- updateList.add(printerId);
- serviceName = printerId.getServiceName();
- iterator.remove();
- } else if (printerId.getServiceName().equals(serviceName)) {
- updateList.add(printerId);
- iterator.remove();
+ if (printerId != null) {
+ if (updateList.isEmpty()) {
+ updateList.add(printerId);
+ serviceName = printerId.getServiceName();
+ iterator.remove();
+ } else if (printerId.getServiceName().equals(serviceName)) {
+ updateList.add(printerId);
+ iterator.remove();
+ }
}
}
// Schedule a notification of the service.
@@ -1157,7 +1164,7 @@
}
}
- public final void startPrinterStateTrackingLocked(PrinterId printerId) {
+ public final void startPrinterStateTrackingLocked(@NonNull PrinterId printerId) {
if (mIsDestroyed) {
Log.w(LOG_TAG, "Not starting printer state tracking - session destroyed");
return;
@@ -1500,8 +1507,8 @@
service.validatePrinters(printerIds);
}
- private void handleStartPrinterStateTracking(RemotePrintService service,
- PrinterId printerId) {
+ private void handleStartPrinterStateTracking(@NonNull RemotePrintService service,
+ @NonNull PrinterId printerId) {
service.startPrinterStateTracking(printerId);
}
diff --git a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
index 2640889..31182fc 100644
--- a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -155,16 +155,12 @@
@SmallTest
public void testTopicImportanceExtractor() throws Exception {
- mHelper.setTopicImportance("package", 0, new Notification.Topic("A", "a"),
- IMPORTANCE_MAX);
+ mHelper.setImportance("package", 0, new Notification.Topic("A", "a"), IMPORTANCE_MAX);
// There is no B. There never was a b. Moving on...
- mHelper.setTopicImportance("package", 0, new Notification.Topic("C", "c"),
- IMPORTANCE_HIGH);
- mHelper.setTopicImportance("package", 0, new Notification.Topic("D", "d"),
- IMPORTANCE_LOW);
+ mHelper.setImportance("package", 0, new Notification.Topic("C", "c"), IMPORTANCE_HIGH);
+ mHelper.setImportance("package", 0, new Notification.Topic("D", "d"), IMPORTANCE_LOW);
// watch out: different package.
- mHelper.setTopicImportance("package2", 0, new Notification.Topic("E", "e"),
- IMPORTANCE_NONE);
+ mHelper.setImportance("package2", 0, new Notification.Topic("E", "e"), IMPORTANCE_NONE);
TopicImportanceExtractor validator = mHelper.findExtractor(TopicImportanceExtractor.class);
validator.process(mRecordGroupGSortA);
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index aa95e1d..3859294 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -24,7 +24,6 @@
import java.lang.String;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -210,7 +209,22 @@
* Call sends responses through connection.
* @hide
*/
- public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000;
+ public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00200000;
+
+ /**
+ * When set, prevents a video {@code Call} from being downgraded to an audio-only call.
+ * <p>
+ * Should be set when the VideoState has the {@link VideoProfile#STATE_TX_ENABLED} or
+ * {@link VideoProfile#STATE_RX_ENABLED} bits set to indicate that the connection cannot be
+ * downgraded from a video call back to a VideoState of
+ * {@link VideoProfile#STATE_AUDIO_ONLY}.
+ * <p>
+ * Intuitively, a call which can be downgraded to audio should also have local and remote
+ * video
+ * capabilities (see {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and
+ * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL}).
+ */
+ public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00400000;
//******************************************************************************************
// Next CAPABILITY value: 0x00800000
@@ -332,6 +346,9 @@
if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX");
}
+ if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) {
+ builder.append(" CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO");
+ }
if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
}
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index deb98f4..fa7a59d 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -255,8 +255,23 @@
*/
public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000;
+ /**
+ * When set, prevents a video call from being downgraded to an audio-only call.
+ * <p>
+ * Should be set when the VideoState has the {@link VideoProfile#STATE_TX_ENABLED} or
+ * {@link VideoProfile#STATE_RX_ENABLED} bits set to indicate that the connection cannot be
+ * downgraded from a video call back to a VideoState of
+ * {@link VideoProfile#STATE_AUDIO_ONLY}.
+ * <p>
+ * Intuitively, a call which can be downgraded to audio should also have local and remote
+ * video
+ * capabilities (see {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and
+ * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL}).
+ */
+ public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00800000;
+
//**********************************************************************************************
- // Next CAPABILITY value: 0x00800000
+ // Next CAPABILITY value: 0x01000000
//**********************************************************************************************
/**
@@ -371,6 +386,9 @@
if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
}
+ if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) {
+ builder.append(" CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO");
+ }
if (can(capabilities, CAPABILITY_HIGH_DEF_AUDIO)) {
builder.append(" CAPABILITY_HIGH_DEF_AUDIO");
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 320d274..630dacc 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -746,7 +746,7 @@
*/
@Nullable
public PersistableBundle getConfig() {
- return getConfigForSubId(SubscriptionManager.getDefaultSubId());
+ return getConfigForSubId(SubscriptionManager.getDefaultSubscriptionId());
}
/**
diff --git a/telephony/java/android/telephony/DataConnectionRealTimeInfo.java b/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
index 96069213..f71f58d 100644
--- a/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
+++ b/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
@@ -28,10 +28,10 @@
public class DataConnectionRealTimeInfo implements Parcelable {
private long mTime; // Time the info was collected since boot in nanos;
- public static int DC_POWER_STATE_LOW = 1;
- public static int DC_POWER_STATE_MEDIUM = 2;
- public static int DC_POWER_STATE_HIGH = 3;
- public static int DC_POWER_STATE_UNKNOWN = Integer.MAX_VALUE;
+ public static final int DC_POWER_STATE_LOW = 1;
+ public static final int DC_POWER_STATE_MEDIUM = 2;
+ public static final int DC_POWER_STATE_HIGH = 3;
+ public static final int DC_POWER_STATE_UNKNOWN = Integer.MAX_VALUE;
private int mDcPowerState; // DC_POWER_STATE_[LOW | MEDIUM | HIGH | UNKNOWN]
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 553221d..b089387 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -2082,7 +2082,7 @@
* to read the VM number.
*/
public static boolean isVoiceMailNumber(String number) {
- return isVoiceMailNumber(SubscriptionManager.getDefaultSubId(), number);
+ return isVoiceMailNumber(SubscriptionManager.getDefaultSubscriptionId(), number);
}
/**
@@ -2977,7 +2977,7 @@
* Returns Default voice subscription Id.
*/
private static int getDefaultVoiceSubId() {
- return SubscriptionManager.getDefaultVoiceSubId();
+ return SubscriptionManager.getDefaultVoiceSubscriptionId();
}
//==== End of utility methods used only in compareStrictly() =====
}
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 16472c8..ae130d4 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -194,10 +194,12 @@
* {@more}
* Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
* READ_PRECISE_PHONE_STATE}
- *
* @see #onDataConnectionRealTimeInfoChanged(DataConnectionRealTimeInfo)
+ *
+ * @deprecated Use {@link TelephonyManager#getModemActivityInfo()}
* @hide
*/
+ @Deprecated
public static final int LISTEN_DATA_CONNECTION_REAL_TIME_INFO = 0x00002000;
/**
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 9998937..ff8c71c 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -53,7 +53,6 @@
private static final boolean VDBG = false;
/** An invalid subscription identifier */
- /** @hide */
public static final int INVALID_SUBSCRIPTION_ID = -1;
/** Base value for Dummy SUBSCRIPTION_ID's. */
@@ -455,8 +454,9 @@
}
/**
- * Get the active SubscriptionInfo with the subId key
- * @param subId The unique SubscriptionInfo key in database
+ * Get the active SubscriptionInfo with the input subId.
+ *
+ * @param subId The unique SubscriptionInfo key in database.
* @return SubscriptionInfo, maybe null if its not active.
*/
public SubscriptionInfo getActiveSubscriptionInfo(int subId) {
@@ -898,12 +898,15 @@
}
/**
- * @return the "system" defaultSubId on a voice capable device this
- * will be getDefaultVoiceSubId() and on a data only device it will be
- * getDefaultDataSubId().
- * @hide
+ * Returns the system's default subscription id.
+ *
+ * For a voice capable device, it will return getDefaultVoiceSubscriptionId.
+ * For a data only device, it will return the getDefaultDataSubscriptionId.
+ * May return an INVALID_SUBSCRIPTION_ID on error.
+ *
+ * @return the "system" default subscription id.
*/
- public static int getDefaultSubId() {
+ public static int getDefaultSubscriptionId() {
int subId = INVALID_SUBSCRIPTION_ID;
try {
@@ -919,8 +922,14 @@
return subId;
}
- /** @hide */
- public static int getDefaultVoiceSubId() {
+ /**
+ * Returns the system's default voice subscription id.
+ *
+ * On a data only device or on error, will return INVALID_SUBSCRIPTION_ID.
+ *
+ * @return the default voice subscription Id.
+ */
+ public static int getDefaultVoiceSubscriptionId() {
int subId = INVALID_SUBSCRIPTION_ID;
try {
@@ -932,7 +941,7 @@
// ignore it
}
- if (VDBG) logd("getDefaultVoiceSubId, sub id = " + subId);
+ if (VDBG) logd("getDefaultVoiceSubscriptionId, sub id = " + subId);
return subId;
}
@@ -949,23 +958,31 @@
}
}
- /** @hide */
+ /**
+ * Return the SubscriptionInfo for default voice subscription.
+ *
+ * Will return null on data only devices, or on error.
+ *
+ * @return the SubscriptionInfo for the default voice subscription.
+ * @hide
+ */
public SubscriptionInfo getDefaultVoiceSubscriptionInfo() {
- return getActiveSubscriptionInfo(getDefaultVoiceSubId());
+ return getActiveSubscriptionInfo(getDefaultVoiceSubscriptionId());
}
/** @hide */
public static int getDefaultVoicePhoneId() {
- return getPhoneId(getDefaultVoiceSubId());
+ return getPhoneId(getDefaultVoiceSubscriptionId());
}
/**
- * @return subId of the DefaultSms subscription or
- * a value < 0 if an error.
+ * Returns the system's default SMS subscription id.
*
- * @hide
+ * On a data only device or on error, will return INVALID_SUBSCRIPTION_ID.
+ *
+ * @return the default SMS subscription Id.
*/
- public static int getDefaultSmsSubId() {
+ public static int getDefaultSmsSubscriptionId() {
int subId = INVALID_SUBSCRIPTION_ID;
try {
@@ -977,7 +994,7 @@
// ignore it
}
- if (VDBG) logd("getDefaultSmsSubId, sub id = " + subId);
+ if (VDBG) logd("getDefaultSmsSubscriptionId, sub id = " + subId);
return subId;
}
@@ -994,18 +1011,31 @@
}
}
- /** @hide */
+ /**
+ * Return the SubscriptionInfo for default voice subscription.
+ *
+ * Will return null on data only devices, or on error.
+ *
+ * @return the SubscriptionInfo for the default SMS subscription.
+ * @hide
+ */
public SubscriptionInfo getDefaultSmsSubscriptionInfo() {
- return getActiveSubscriptionInfo(getDefaultSmsSubId());
+ return getActiveSubscriptionInfo(getDefaultSmsSubscriptionId());
}
/** @hide */
public int getDefaultSmsPhoneId() {
- return getPhoneId(getDefaultSmsSubId());
+ return getPhoneId(getDefaultSmsSubscriptionId());
}
- /** @hide */
- public static int getDefaultDataSubId() {
+ /**
+ * Returns the system's default data subscription id.
+ *
+ * On a voice only device or on error, will return INVALID_SUBSCRIPTION_ID.
+ *
+ * @return the default data subscription Id.
+ */
+ public static int getDefaultDataSubscriptionId() {
int subId = INVALID_SUBSCRIPTION_ID;
try {
@@ -1017,7 +1047,7 @@
// ignore it
}
- if (VDBG) logd("getDefaultDataSubId, sub id = " + subId);
+ if (VDBG) logd("getDefaultDataSubscriptionId, sub id = " + subId);
return subId;
}
@@ -1034,14 +1064,21 @@
}
}
- /** @hide */
+ /**
+ * Return the SubscriptionInfo for default data subscription.
+ *
+ * Will return null on voice only devices, or on error.
+ *
+ * @return the SubscriptionInfo for the default data subscription.
+ * @hide
+ */
public SubscriptionInfo getDefaultDataSubscriptionInfo() {
- return getActiveSubscriptionInfo(getDefaultDataSubId());
+ return getActiveSubscriptionInfo(getDefaultDataSubscriptionId());
}
/** @hide */
public int getDefaultDataPhoneId() {
- return getPhoneId(getDefaultDataSubId());
+ return getPhoneId(getDefaultDataSubscriptionId());
}
/** @hide */
@@ -1061,13 +1098,13 @@
//FIXME this is vulnerable to race conditions
/** @hide */
public boolean allDefaultsSelected() {
- if (!isValidSubscriptionId(getDefaultDataSubId())) {
+ if (!isValidSubscriptionId(getDefaultDataSubscriptionId())) {
return false;
}
- if (!isValidSubscriptionId(getDefaultSmsSubId())) {
+ if (!isValidSubscriptionId(getDefaultSmsSubscriptionId())) {
return false;
}
- if (!isValidSubscriptionId(getDefaultVoiceSubId())) {
+ if (!isValidSubscriptionId(getDefaultVoiceSubscriptionId())) {
return false;
}
return true;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 7eaa6a6..fcb42a4 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1232,7 +1232,6 @@
* on a CDMA network).
* @param subId
*/
- /** {@hide} */
public String getNetworkOperatorName(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId);
return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_ALPHA, "");
@@ -1259,8 +1258,7 @@
*
* @param subId
*/
- /** {@hide} */
- public String getNetworkOperatorForSubscription(int subId) {
+ public String getNetworkOperator(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId);
return getNetworkOperatorForPhone(phoneId);
}
@@ -1276,7 +1274,7 @@
* @param phoneId
* @hide
**/
- public String getNetworkOperatorForPhone(int phoneId) {
+ public String getNetworkOperatorForPhone(int phoneId) {
return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, "");
}
@@ -1298,7 +1296,6 @@
*
* @param subId
*/
- /** {@hide} */
public boolean isNetworkRoaming(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId);
return Boolean.parseBoolean(getTelephonyProperty(phoneId,
@@ -1327,8 +1324,7 @@
*
* @param subId for which Network CountryIso is returned
*/
- /** {@hide} */
- public String getNetworkCountryIsoForSubscription(int subId) {
+ public String getNetworkCountryIso(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId);
return getNetworkCountryIsoForPhone(phoneId);
}
@@ -1436,7 +1432,6 @@
* Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
- /** {@hide} */
public int getNetworkType(int subId) {
try {
ITelephony telephony = getITelephony();
@@ -1497,7 +1492,6 @@
* Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
- /** {@hide} */
public int getDataNetworkType(int subId) {
try{
ITelephony telephony = getITelephony();
@@ -1535,7 +1529,6 @@
* Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
- /** {@hide} */
public int getVoiceNetworkType(int subId) {
try{
ITelephony telephony = getITelephony();
@@ -1804,10 +1797,9 @@
* @see #getSimState
*
* @param subId for which SimOperator is returned
- * @hide
*/
public String getSimOperator(int subId) {
- return getSimOperatorNumericForSubscription(subId);
+ return getSimOperatorNumeric(subId);
}
/**
@@ -1820,17 +1812,17 @@
* @hide
*/
public String getSimOperatorNumeric() {
- int subId = SubscriptionManager.getDefaultDataSubId();
+ int subId = SubscriptionManager.getDefaultDataSubscriptionId();
if (!SubscriptionManager.isUsableSubIdValue(subId)) {
- subId = SubscriptionManager.getDefaultSmsSubId();
+ subId = SubscriptionManager.getDefaultSmsSubscriptionId();
if (!SubscriptionManager.isUsableSubIdValue(subId)) {
- subId = SubscriptionManager.getDefaultVoiceSubId();
+ subId = SubscriptionManager.getDefaultVoiceSubscriptionId();
if (!SubscriptionManager.isUsableSubIdValue(subId)) {
- subId = SubscriptionManager.getDefaultSubId();
+ subId = SubscriptionManager.getDefaultSubscriptionId();
}
}
}
- return getSimOperatorNumericForSubscription(subId);
+ return getSimOperatorNumeric(subId);
}
/**
@@ -1844,7 +1836,7 @@
* @param subId for which SimOperator is returned
* @hide
*/
- public String getSimOperatorNumericForSubscription(int subId) {
+ public String getSimOperatorNumeric(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId);
return getSimOperatorNumericForPhone(phoneId);
}
@@ -1881,9 +1873,8 @@
* @see #getSimState
*
* @param subId for which SimOperatorName is returned
- * @hide
*/
- public String getSimOperatorNameForSubscription(int subId) {
+ public String getSimOperatorName(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId);
return getSimOperatorNameForPhone(phoneId);
}
@@ -1909,21 +1900,8 @@
* Returns the ISO country code equivalent for the SIM provider's country code.
*
* @param subId for which SimCountryIso is returned
- *
- * @hide
*/
public String getSimCountryIso(int subId) {
- return getSimCountryIsoForSubscription(subId);
- }
-
- /**
- * Returns the ISO country code equivalent for the SIM provider's country code.
- *
- * @param subId for which SimCountryIso is returned
- *
- * @hide
- */
- public String getSimCountryIsoForSubscription(int subId) {
int phoneId = SubscriptionManager.getPhoneId(subId);
return getSimCountryIsoForPhone(phoneId);
}
@@ -1957,7 +1935,6 @@
* Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
- /** {@hide} */
public String getSimSerialNumber(int subId) {
try {
IPhoneSubInfo info = getSubscriberInfo();
@@ -2046,7 +2023,6 @@
*
* @param subId whose subscriber id is returned
*/
- /** {@hide} */
public String getSubscriberId(int subId) {
try {
IPhoneSubInfo info = getSubscriberInfo();
@@ -2089,9 +2065,8 @@
* Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*
- * @param subscription whose subscriber id is returned
+ * @param subId whose subscriber id is returned
*/
- /** {@hide} */
public String getGroupIdLevel1(int subId) {
try {
IPhoneSubInfo info = getSubscriberInfo();
@@ -2118,7 +2093,7 @@
* The default SMS app can also use this.
*/
public String getLine1Number() {
- return getLine1NumberForSubscriber(getDefaultSubscription());
+ return getLine1Number(getDefaultSubscription());
}
/**
@@ -2134,8 +2109,7 @@
*
* @param subId whose phone number for line 1 is returned
*/
- /** {@hide} */
- public String getLine1NumberForSubscriber(int subId) {
+ public String getLine1Number(int subId) {
String number = null;
try {
ITelephony telephony = getITelephony();
@@ -2174,7 +2148,7 @@
* @return true if the operation was executed correctly.
*/
public boolean setLine1NumberForDisplay(String alphaTag, String number) {
- return setLine1NumberForDisplayForSubscriber(getDefaultSubscription(), alphaTag, number);
+ return setLine1NumberForDisplay(getDefaultSubscription(), alphaTag, number);
}
/**
@@ -2190,9 +2164,8 @@
* @param alphaTag alpha-tagging of the dailing nubmer
* @param number The dialing number
* @return true if the operation was executed correctly.
- * @hide
*/
- public boolean setLine1NumberForDisplayForSubscriber(int subId, String alphaTag, String number) {
+ public boolean setLine1NumberForDisplay(int subId, String alphaTag, String number) {
try {
ITelephony telephony = getITelephony();
if (telephony != null)
@@ -2213,7 +2186,7 @@
* nobody seems to call this.
*/
public String getLine1AlphaTag() {
- return getLine1AlphaTagForSubscriber(getDefaultSubscription());
+ return getLine1AlphaTag(getDefaultSubscription());
}
/**
@@ -2226,8 +2199,7 @@
* @param subId whose alphabetic identifier associated with line 1 is returned
* nobody seems to call this.
*/
- /** {@hide} */
- public String getLine1AlphaTagForSubscriber(int subId) {
+ public String getLine1AlphaTag(int subId) {
String alphaTag = null;
try {
ITelephony telephony = getITelephony();
@@ -2327,7 +2299,6 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* @param subId whose voice mail number is returned
*/
- /** {@hide} */
public String getVoiceMailNumber(int subId) {
try {
IPhoneSubInfo info = getSubscriberInfo();
@@ -2400,7 +2371,6 @@
* @param alphaTag The alpha tag to display.
* @param number The voicemail number.
*/
- /** {@hide} */
public boolean setVoiceMailNumber(int subId, String alphaTag, String number) {
try {
ITelephony telephony = getITelephony();
@@ -2466,7 +2436,6 @@
* @param subId whose alphabetic identifier associated with the
* voice mail number is returned
*/
- /** {@hide} */
public String getVoiceMailAlphaTag(int subId) {
try {
IPhoneSubInfo info = getSubscriberInfo();
@@ -2584,7 +2553,6 @@
*
* @param subId whose call state is returned
*/
- /** {@hide} */
public int getCallState(int subId) {
try {
ITelephony telephony = getITelephony();
@@ -3225,19 +3193,19 @@
* Returns Default subscription.
*/
private static int getDefaultSubscription() {
- return SubscriptionManager.getDefaultSubId();
+ return SubscriptionManager.getDefaultSubscriptionId();
}
/**
* Returns Default phone.
*/
private static int getDefaultPhone() {
- return SubscriptionManager.getPhoneId(SubscriptionManager.getDefaultSubId());
+ return SubscriptionManager.getPhoneId(SubscriptionManager.getDefaultSubscriptionId());
}
/** {@hide} */
public int getDefaultSim() {
- return SubscriptionManager.getSlotId(SubscriptionManager.getDefaultSubId());
+ return SubscriptionManager.getSlotId(SubscriptionManager.getDefaultSubscriptionId());
}
/**
@@ -4182,7 +4150,7 @@
/** @hide */
@SystemApi
public void setDataEnabled(boolean enable) {
- setDataEnabled(SubscriptionManager.getDefaultDataSubId(), enable);
+ setDataEnabled(SubscriptionManager.getDefaultDataSubscriptionId(), enable);
}
/** @hide */
@@ -4201,7 +4169,7 @@
/** @hide */
@SystemApi
public boolean getDataEnabled() {
- return getDataEnabled(SubscriptionManager.getDefaultDataSubId());
+ return getDataEnabled(SubscriptionManager.getDefaultDataSubscriptionId());
}
/** @hide */
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index b9d7297..5f3f773 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -327,7 +327,7 @@
public static CallerInfo getCallerInfo(Context context, String number) {
if (VDBG) Rlog.v(TAG, "getCallerInfo() based on number...");
- int subId = SubscriptionManager.getDefaultSubId();
+ int subId = SubscriptionManager.getDefaultSubscriptionId();
return getCallerInfo(context, number, subId);
}
@@ -444,7 +444,7 @@
// string in the phone number field.
/* package */ CallerInfo markAsVoiceMail() {
- int subId = SubscriptionManager.getDefaultSubId();
+ int subId = SubscriptionManager.getDefaultSubscriptionId();
return markAsVoiceMail(subId);
}
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index c754068..05cb31e 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -387,7 +387,7 @@
public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
OnQueryCompleteListener listener, Object cookie) {
- int subId = SubscriptionManager.getDefaultSubId();
+ int subId = SubscriptionManager.getDefaultSubscriptionId();
return startQuery(token, context, number, listener, cookie, subId);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 76b69ce..907d76e 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -21,7 +21,6 @@
import android.net.NetworkCapabilities;
import android.os.Bundle;
import android.telephony.CellInfo;
-import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.CellInfo;
@@ -65,7 +64,6 @@
void notifyPreciseDataConnectionFailed(String reason, String apnType, String apn,
String failCause);
void notifyCellInfoForSubscriber(in int subId, in List<CellInfo> cellInfo);
- void notifyDataConnectionRealTimeInfo(in DataConnectionRealTimeInfo dcRtInfo);
void notifyVoLteServiceStateChanged(in VoLteServiceState lteState);
void notifyOemHookRawEventForSubscriber(in int subId, in byte[] rawData);
void notifySubscriptionInfoChanged();
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestCertificateSource.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestCertificateSource.java
index 0c36063..4c12c2d 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestCertificateSource.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/TestCertificateSource.java
@@ -16,8 +16,9 @@
package android.security.net.config;
-import java.util.Set;
+import android.util.ArraySet;
import java.security.cert.X509Certificate;
+import java.util.Set;
import com.android.org.conscrypt.TrustedCertificateIndex;
@@ -33,10 +34,12 @@
}
}
+ @Override
public Set<X509Certificate> getCertificates() {
return mCertificates;
}
+ @Override
public X509Certificate findBySubjectAndPublicKey(X509Certificate cert) {
java.security.cert.TrustAnchor anchor = mIndex.findBySubjectAndPublicKey(cert);
if (anchor == null) {
@@ -45,6 +48,7 @@
return anchor.getTrustedCert();
}
+ @Override
public X509Certificate findByIssuerAndSignature(X509Certificate cert) {
java.security.cert.TrustAnchor anchor = mIndex.findByIssuerAndSignature(cert);
if (anchor == null) {
@@ -52,4 +56,13 @@
}
return anchor.getTrustedCert();
}
+
+ @Override
+ public Set<X509Certificate> findAllByIssuerAndSignature(X509Certificate cert) {
+ Set<X509Certificate> certs = new ArraySet<X509Certificate>();
+ for (java.security.cert.TrustAnchor anchor : mIndex.findAllByIssuerAndSignature(cert)) {
+ certs.add(anchor.getTrustedCert());
+ }
+ return certs;
+ }
}
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 6e42391..605e8c0 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -15,12 +15,14 @@
*/
package android.net.wifi;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
import android.security.Credentials;
import android.text.TextUtils;
import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
@@ -72,6 +74,13 @@
public static final String KEYSTORE_URI = "keystore://";
/**
+ * String representing the keystore URI used for wpa_supplicant,
+ * Unlike #KEYSTORE_URI, this supports a list of space-delimited aliases
+ * @hide
+ */
+ public static final String KEYSTORES_URI = "keystores://";
+
+ /**
* String to set the engine value to when it should be enabled.
* @hide
*/
@@ -101,10 +110,12 @@
public static final String REALM_KEY = "realm";
/** @hide */
public static final String PLMN_KEY = "plmn";
+ /** @hide */
+ public static final String CA_CERT_ALIAS_DELIMITER = " ";
private HashMap<String, String> mFields = new HashMap<String, String>();
- private X509Certificate mCaCert;
+ private X509Certificate[] mCaCerts;
private PrivateKey mClientPrivateKey;
private X509Certificate mClientCertificate;
@@ -136,7 +147,7 @@
dest.writeString(entry.getValue());
}
- writeCertificate(dest, mCaCert);
+ writeCertificates(dest, mCaCerts);
if (mClientPrivateKey != null) {
String algorithm = mClientPrivateKey.getAlgorithm();
@@ -151,6 +162,17 @@
writeCertificate(dest, mClientCertificate);
}
+ private void writeCertificates(Parcel dest, X509Certificate[] cert) {
+ if (cert != null && cert.length != 0) {
+ dest.writeInt(cert.length);
+ for (int i = 0; i < cert.length; i++) {
+ writeCertificate(dest, cert[i]);
+ }
+ } else {
+ dest.writeInt(0);
+ }
+ }
+
private void writeCertificate(Parcel dest, X509Certificate cert) {
if (cert != null) {
try {
@@ -176,7 +198,7 @@
enterpriseConfig.mFields.put(key, value);
}
- enterpriseConfig.mCaCert = readCertificate(in);
+ enterpriseConfig.mCaCerts = readCertificates(in);
PrivateKey userKey = null;
int len = in.readInt();
@@ -199,6 +221,18 @@
return enterpriseConfig;
}
+ private X509Certificate[] readCertificates(Parcel in) {
+ X509Certificate[] certs = null;
+ int len = in.readInt();
+ if (len > 0) {
+ certs = new X509Certificate[len];
+ for (int i = 0; i < len; i++) {
+ certs[i] = readCertificate(in);
+ }
+ }
+ return certs;
+ }
+
private X509Certificate readCertificate(Parcel in) {
X509Certificate cert = null;
int len = in.readInt();
@@ -399,6 +433,36 @@
}
/**
+ * Encode a CA certificate alias so it does not contain illegal character.
+ * @hide
+ */
+ public static String encodeCaCertificateAlias(String alias) {
+ byte[] bytes = alias.getBytes(StandardCharsets.UTF_8);
+ StringBuilder sb = new StringBuilder(bytes.length * 2);
+ for (byte o : bytes) {
+ sb.append(String.format("%02x", o & 0xFF));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Decode a previously-encoded CA certificate alias.
+ * @hide
+ */
+ public static String decodeCaCertificateAlias(String alias) {
+ byte[] data = new byte[alias.length() >> 1];
+ for (int n = 0, position = 0; n < alias.length(); n += 2, position++) {
+ data[position] = (byte) Integer.parseInt(alias.substring(n, n + 2), 16);
+ }
+ try {
+ return new String(data, StandardCharsets.UTF_8);
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ return alias;
+ }
+ }
+
+ /**
* Set CA certificate alias.
*
* <p> See the {@link android.security.KeyChain} for details on installing or choosing
@@ -412,6 +476,35 @@
}
/**
+ * Set CA certificate aliases. When creating installing the corresponding certificate to
+ * the keystore, please use alias encoded by {@link #encodeCaCertificateAlias(String)}.
+ *
+ * <p> See the {@link android.security.KeyChain} for details on installing or choosing
+ * a certificate.
+ * </p>
+ * @param aliases identifies the certificate
+ * @hide
+ */
+ public void setCaCertificateAliases(@Nullable String[] aliases) {
+ if (aliases == null) {
+ setFieldValue(CA_CERT_KEY, null, CA_CERT_PREFIX);
+ } else if (aliases.length == 1) {
+ // Backwards compatibility: use the original cert prefix if setting only one alias.
+ setCaCertificateAlias(aliases[0]);
+ } else {
+ // Use KEYSTORES_URI which supports multiple aliases.
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < aliases.length; i++) {
+ if (i > 0) {
+ sb.append(CA_CERT_ALIAS_DELIMITER);
+ }
+ sb.append(encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + aliases[i]));
+ }
+ setFieldValue(CA_CERT_KEY, sb.toString(), KEYSTORES_URI);
+ }
+ }
+
+ /**
* Get CA certificate alias
* @return alias to the CA certificate
* @hide
@@ -421,6 +514,32 @@
}
/**
+ * Get CA certificate aliases
+ * @return alias to the CA certificate
+ * @hide
+ */
+ @Nullable public String[] getCaCertificateAliases() {
+ String value = getFieldValue(CA_CERT_KEY, "");
+ if (value.startsWith(CA_CERT_PREFIX)) {
+ // Backwards compatibility: parse the original alias prefix.
+ return new String[] {getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX)};
+ } else if (value.startsWith(KEYSTORES_URI)) {
+ String values = value.substring(KEYSTORES_URI.length());
+
+ String[] aliases = TextUtils.split(values, CA_CERT_ALIAS_DELIMITER);
+ for (int i = 0; i < aliases.length; i++) {
+ aliases[i] = decodeCaCertificateAlias(aliases[i]);
+ if (aliases[i].startsWith(Credentials.CA_CERTIFICATE)) {
+ aliases[i] = aliases[i].substring(Credentials.CA_CERTIFICATE.length());
+ }
+ }
+ return aliases.length != 0 ? aliases : null;
+ } else {
+ return TextUtils.isEmpty(value) ? null : new String[] {value};
+ }
+ }
+
+ /**
* Specify a X.509 certificate that identifies the server.
*
* <p>A default name is automatically assigned to the certificate and used
@@ -431,31 +550,76 @@
* @param cert X.509 CA certificate
* @throws IllegalArgumentException if not a CA certificate
*/
- public void setCaCertificate(X509Certificate cert) {
+ public void setCaCertificate(@Nullable X509Certificate cert) {
if (cert != null) {
if (cert.getBasicConstraints() >= 0) {
- mCaCert = cert;
+ mCaCerts = new X509Certificate[] {cert};
} else {
throw new IllegalArgumentException("Not a CA certificate");
}
} else {
- mCaCert = null;
+ mCaCerts = null;
}
}
/**
- * Get CA certificate
+ * Get CA certificate. If multiple CA certificates are configured previously,
+ * return the first one.
* @return X.509 CA certificate
*/
- public X509Certificate getCaCertificate() {
- return mCaCert;
+ @Nullable public X509Certificate getCaCertificate() {
+ if (mCaCerts != null && mCaCerts.length > 0) {
+ return mCaCerts[0];
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Specify a list of X.509 certificates that identifies the server. The validation
+ * passes if the CA of server certificate matches one of the given certificates.
+
+ * <p>Default names are automatically assigned to the certificates and used
+ * with this configuration. The framework takes care of installing the
+ * certificates when the config is saved and removing the certificates when
+ * the config is removed.
+ *
+ * @param certs X.509 CA certificates
+ * @throws IllegalArgumentException if any of the provided certificates is
+ * not a CA certificate
+ */
+ public void setCaCertificates(@Nullable X509Certificate[] certs) {
+ if (certs != null) {
+ X509Certificate[] newCerts = new X509Certificate[certs.length];
+ for (int i = 0; i < certs.length; i++) {
+ if (certs[i].getBasicConstraints() >= 0) {
+ newCerts[i] = certs[i];
+ } else {
+ throw new IllegalArgumentException("Not a CA certificate");
+ }
+ }
+ mCaCerts = newCerts;
+ } else {
+ mCaCerts = null;
+ }
+ }
+
+ /**
+ * Get CA certificates.
+ */
+ @Nullable public X509Certificate[] getCaCertificates() {
+ if (mCaCerts != null || mCaCerts.length > 0) {
+ return mCaCerts;
+ } else {
+ return null;
+ }
}
/**
* @hide
*/
public void resetCaCertificate() {
- mCaCert = null;
+ mCaCerts = null;
}
/** Set Client certificate alias.
diff --git a/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl b/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
deleted file mode 100644
index 50bec33..0000000
--- a/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.net.wifi.ScanResult;
-import android.net.wifi.passpoint.WifiPasspointPolicy;
-import android.net.wifi.passpoint.WifiPasspointCredential;
-import android.os.Messenger;
-
-/**
- * Interface that allows controlling and querying Wifi Passpoint connectivity.
- *
- * {@hide}
- */
-interface IWifiPasspointManager
-{
- Messenger getMessenger();
-
- int getPasspointState();
-
- List<WifiPasspointPolicy> requestCredentialMatch(in List<ScanResult> requested);
-
- List<WifiPasspointCredential> getCredentials();
-
- boolean addCredential(in WifiPasspointCredential cred);
-
- boolean updateCredential(in WifiPasspointCredential cred);
-
- boolean removeCredential(in WifiPasspointCredential cred);
-}
-
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.aidl
deleted file mode 100644
index cfd3605..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-parcelable WifiPasspointCredential;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
deleted file mode 100644
index a100aed..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
+++ /dev/null
@@ -1,665 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.net.wifi.WifiEnterpriseConfig;
-import android.os.Parcelable;
-import android.os.Parcel;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-
-/**
- * A class representing a Wi-Fi Passpoint credential.
- * @hide
- */
-public class WifiPasspointCredential implements Parcelable {
-
- private final static String TAG = "PasspointCredential";
- private final static boolean DBG = true;
-
- /** Wi-Fi nodes**/
- private String mWifiSpFqdn;
-
- /** PerProviderSubscription nodes **/
- private String mCredentialName;
-
- /** SubscriptionUpdate nodes **/
- private String mSubscriptionUpdateInterval;
- private String mSubscriptionUpdateMethod;
- private String mSubscriptionUpdateRestriction;
- private String mSubscriptionUpdateURI;
- private String mSubscriptionUpdateUsername;
- private String mSubscriptionUpdatePassword;
-
- /** HomeSP nodes **/
- private String mHomeSpFqdn;
- private String mFriendlyName;
- private Collection<WifiPasspointDmTree.HomeOIList> mHomeOIList;
- private Collection<WifiPasspointDmTree.OtherHomePartners> mOtherHomePartnerList;
-
- /** SubscriptionParameters nodes**/
- private String mCreationDate;
- private String mExpirationDate;
-
- /** Credential nodes **/
- private String mType;
- private String mInnerMethod;
- private String mCertType;
- private String mCertSha256Fingerprint;
- private String mUpdateIdentifier;
- private String mUsername;
- private String mPasswd;
- private String mRealm;
- private String mImsi;
- private String mMcc;
- private String mMnc;
- private String mCaRootCert;
- private String mClientCert;
- private boolean mCheckAaaServerCertStatus;
-
- /** Policy nodes **/
- private String mPolicyUpdateUri;
- private String mPolicyUpdateInterval;
- private String mPolicyUpdateUsername;
- private String mPolicyUpdatePassword;
- private String mPolicyUpdateRestriction;
- private String mPolicyUpdateMethod;
- private Collection<WifiPasspointDmTree.PreferredRoamingPartnerList> mPreferredRoamingPartnerList;
- private Collection<WifiPasspointDmTree.MinBackhaulThresholdNetwork> mMinBackhaulThresholdNetwork;
- private Collection<WifiPasspointDmTree.SPExclusionList> mSpExclusionList;
- private Collection<WifiPasspointDmTree.RequiredProtoPortTuple> mRequiredProtoPortTuple;
- private String mMaxBssLoad;
-
- /** CrednetialPriority node **/
- private int mCrednetialPriority;
-
- /** AAAServerTrustRoot nodes **/
- private String mAaaCertUrl;
- private String mAaaSha256Fingerprint;
-
- /** Others **/
- private boolean mIsMachineRemediation;
- private boolean mUserPreferred = false;
- private String mWifiTreePath;
- private WifiEnterpriseConfig mEnterpriseConfig;
-
- /** @hide */
- public WifiPasspointCredential() {}
-
- /**
- * Constructor
- * @param realm Realm of the passpoint credential
- * @param fqdn Fully qualified domain name (FQDN) of the credential
- * @param config Enterprise config, must be either EAP-TLS or EAP-TTLS
- * @see WifiEnterpriseConfig
- */
- public WifiPasspointCredential(String realm, String fqdn, WifiEnterpriseConfig config) {
- mRealm = realm;
- switch (config.getEapMethod()) {
- case WifiEnterpriseConfig.Eap.TLS:
- case WifiEnterpriseConfig.Eap.TTLS:
- mEnterpriseConfig = new WifiEnterpriseConfig(config);
- break;
- default:
- // ignore
- }
- }
-
- /** @hide */
- public WifiPasspointCredential(String type,
- String caroot,
- String clientcert,
- String mcc,
- String mnc,
- WifiPasspointDmTree.SpFqdn sp,
- WifiPasspointDmTree.CredentialInfo credinfo) {
-
- if (credinfo == null) {
- return;
- }
-
- mType = type;
- mCaRootCert = caroot;
- mClientCert = clientcert;
-
- mWifiSpFqdn = sp.nodeName;
- mUpdateIdentifier = sp.perProviderSubscription.UpdateIdentifier;
-
- mCredentialName = credinfo.nodeName;
- mOtherHomePartnerList = credinfo.homeSP.otherHomePartners.values();
-
- Set set = credinfo.aAAServerTrustRoot.entrySet();
- Iterator i = set.iterator();
- if (i.hasNext()) {
- Map.Entry entry3 = (Map.Entry) i.next();
- WifiPasspointDmTree.AAAServerTrustRoot aaa = (WifiPasspointDmTree.AAAServerTrustRoot) entry3.getValue();
- mAaaCertUrl = aaa.CertURL;
- mAaaSha256Fingerprint = aaa.CertSHA256Fingerprint;
- }
-
- mCertType = credinfo.credential.digitalCertificate.CertificateType;
- mCertSha256Fingerprint = credinfo.credential.digitalCertificate.CertSHA256Fingerprint;
- mUsername = credinfo.credential.usernamePassword.Username;
- mPasswd = credinfo.credential.usernamePassword.Password;
- mIsMachineRemediation = credinfo.credential.usernamePassword.MachineManaged;
- mInnerMethod = credinfo.credential.usernamePassword.eAPMethod.InnerMethod;
- mImsi = credinfo.credential.sim.IMSI;
- mMcc = mcc;
- mMnc = mnc;
- mCreationDate = credinfo.credential.CreationDate;
- mExpirationDate = credinfo.credential.ExpirationDate;
- mRealm = credinfo.credential.Realm;
-
- if (credinfo.credentialPriority == null) {
- mCrednetialPriority = 128;
- } else {
- mCrednetialPriority = Integer.parseInt(credinfo.credentialPriority);
- }
-
- mHomeSpFqdn = credinfo.homeSP.FQDN;
-
- mSubscriptionUpdateInterval = credinfo.subscriptionUpdate.UpdateInterval;
- mSubscriptionUpdateMethod = credinfo.subscriptionUpdate.UpdateMethod;
- mSubscriptionUpdateRestriction = credinfo.subscriptionUpdate.Restriction;
- mSubscriptionUpdateURI = credinfo.subscriptionUpdate.URI;
- mSubscriptionUpdateUsername = credinfo.subscriptionUpdate.usernamePassword.Username;
- mSubscriptionUpdatePassword = credinfo.subscriptionUpdate.usernamePassword.Password;
-
- mPolicyUpdateUri = credinfo.policy.policyUpdate.URI;
- mPolicyUpdateInterval = credinfo.policy.policyUpdate.UpdateInterval;
- mPolicyUpdateUsername = credinfo.policy.policyUpdate.usernamePassword.Username;
- mPolicyUpdatePassword = credinfo.policy.policyUpdate.usernamePassword.Password;
- mPolicyUpdateRestriction = credinfo.policy.policyUpdate.Restriction;
- mPolicyUpdateMethod = credinfo.policy.policyUpdate.UpdateMethod;
- mPreferredRoamingPartnerList = credinfo.policy.preferredRoamingPartnerList.values();
- mMinBackhaulThresholdNetwork = credinfo.policy.minBackhaulThreshold.values();
- mRequiredProtoPortTuple = credinfo.policy.requiredProtoPortTuple.values();
- mMaxBssLoad = credinfo.policy.maximumBSSLoadValue;
- mSpExclusionList = credinfo.policy.sPExclusionList.values();
-
- mHomeOIList = credinfo.homeSP.homeOIList.values();
- mFriendlyName = credinfo.homeSP.FriendlyName;
- mCheckAaaServerCertStatus = credinfo.credential.CheckAAAServerCertStatus;
- }
-
- /** @hide */
- public String getUpdateIdentifier() {
- return mUpdateIdentifier;
- }
-
- /** @hide */
- public String getUpdateMethod() {
- return mSubscriptionUpdateMethod;
- }
-
- /** @hide */
- public void setUpdateMethod(String method) {
- mSubscriptionUpdateMethod = method;
- }
-
- /** @hide */
- public String getWifiSpFqdn() {
- return mWifiSpFqdn;
- }
-
- /** @hide */
- public String getCredName() {
- return mCredentialName;
- }
-
- /** @hide */
- public String getType() {
- return mType;
- }
-
- /**
- * Get enterprise config of this Passpoint credential.
- * @return Enterprise config
- * @see WifiEnterpriseConfig
- */
- public WifiEnterpriseConfig getEnterpriseConfig() {
- return new WifiEnterpriseConfig(mEnterpriseConfig);
- }
-
- /**
- * Set enterprise config of this Passpoint credential.
- * @param config Enterprise config, must be either EAP-TLS or EAP-TTLS
- * @see WifiEnterpriseConfig
- */
- public void setEnterpriseConfig(WifiEnterpriseConfig config) {
- // TODO
- }
-
- /** @hide */
- public String getCertType() {
- return mCertType;
- }
-
- /** @hide */
- public String getCertSha256Fingerprint() {
- return mCertSha256Fingerprint;
- }
-
- /** @hide */
- public String getUserName() {
- return mUsername;
- }
-
- /** @hide */
- public String getPassword() {
- // TODO: guarded by connectivity internal
- return mPasswd;
- }
-
- /** @hide */
- public String getImsi() {
- return mImsi;
- }
-
- /** @hide */
- public String getMcc() {
- return mMcc;
- }
-
- /** @hide */
- public String getMnc() {
- return mMnc;
- }
-
- /** @hide */
- public String getCaRootCertPath() {
- return mCaRootCert;
- }
-
- /** @hide */
- public String getClientCertPath() {
- return mClientCert;
- }
-
- /**
- * Get the realm of this Passpoint credential.
- * @return Realm
- */
- public String getRealm() {
- return mRealm;
- }
-
- /**
- * Set the ream of this Passpoint credential.
- * @param realm Realm
- */
- public void setRealm(String realm) {
- mRealm = realm;
- }
-
- /** @hide */
- public int getPriority() {
- if (mUserPreferred) {
- return 0;
- }
-
- return mCrednetialPriority;
- }
-
- /**
- * Get the fully qualified domain name (FQDN) of this Passpoint credential.
- * @return FQDN
- */
- public String getHomeSpFqdn() {
- return mHomeSpFqdn;
- }
-
- /**
- * Set the fully qualified domain name (FQDN) of this Passpoint credential.
- * @param fqdn FQDN
- */
- public void setHomeFqdn(String fqdn) {
- mHomeSpFqdn = fqdn;
- }
-
-
- /** @hide */
- public Collection<WifiPasspointDmTree.OtherHomePartners> getOtherHomePartnerList() {
- return mOtherHomePartnerList;
- }
-
- /** @hide */
- public String getSubscriptionUpdateUsername() {
- return mSubscriptionUpdateUsername;
- }
-
- /** @hide */
- public String getSubscriptionUpdatePassword() {
- return mSubscriptionUpdatePassword;
- }
-
- /** @hide */
- public String getPolicyUpdateUri() {
- return mPolicyUpdateUri;
- }
-
- /** @hide */
- public String getPolicyUpdateInterval() {
- return mPolicyUpdateInterval;
- }
-
- /** @hide */
- public String getPolicyUpdateUsername() {
- return mPolicyUpdateUsername;
- }
-
- /** @hide */
- public String getPolicyUpdatePassword() {
- return mPolicyUpdatePassword;
- }
-
- /** @hide */
- public String getPolicyUpdateRestriction() {
- return mPolicyUpdateRestriction;
- }
-
- /** @hide */
- public String getPolicyUpdateMethod() {
- return mPolicyUpdateMethod;
- }
-
- /** @hide */
- public String getCreationDate() {
- return mCreationDate;
- }
-
- /** @hide */
- public String getExpirationDate() {
- return mExpirationDate;
- }
-
- /** @hide */
- public void setExpirationDate(String expirationdate) {
- mExpirationDate = expirationdate;
- }
-
- /** @hide */
- public Collection<WifiPasspointDmTree.PreferredRoamingPartnerList> getPreferredRoamingPartnerList() {
- return mPreferredRoamingPartnerList;
- }
-
- /** @hide */
- public Collection<WifiPasspointDmTree.HomeOIList> getHomeOiList() {
- return mHomeOIList;
- }
-
- /** @hide */
- public Collection<WifiPasspointDmTree.MinBackhaulThresholdNetwork> getBackhaulThresholdList() {
- return mMinBackhaulThresholdNetwork;
- }
-
- /** @hide */
- public Collection<WifiPasspointDmTree.RequiredProtoPortTuple> getRequiredProtoPortList() {
- return mRequiredProtoPortTuple;
- }
-
- /** @hide */
- public Collection<WifiPasspointDmTree.SPExclusionList> getSPExclusionList() {
- return mSpExclusionList;
- }
-
- /** @hide */
- public boolean getIsMachineRemediation() {
- return mIsMachineRemediation;
- }
-
- /** @hide */
- public String getAaaCertUrl() {
- return mAaaCertUrl;
- }
-
- /** @hide */
- public String getAaaSha256Fingerprint() {
- return mAaaSha256Fingerprint;
- }
-
- /** @hide */
- public String getSubscriptionUpdateRestriction() {
- return mSubscriptionUpdateRestriction;
- }
-
- /** @hide */
- public String getSubscriptionUpdateURI() {
- return mSubscriptionUpdateURI;
- }
-
- /** @hide */
- public String getSubscriptionUpdateInterval() {
- return mSubscriptionUpdateInterval;
- }
-
- /** @hide */
- public String getFriendlyName() {
- return mFriendlyName;
- }
-
- /** @hide */
- public String getMaxBssLoad() {
- return mMaxBssLoad;
- }
-
- /** @hide */
- public boolean getUserPreference() {
- return mUserPreferred;
- }
-
- /** @hide */
- public boolean getCheckAaaServerCertStatus() {
- return mCheckAaaServerCertStatus;
- }
-
- /** @hide */
- public void setUserPreference(boolean value) {
- mUserPreferred = value;
- }
-
- @Override
- /** @hide */
- public boolean equals(Object obj) {
- boolean result = false;
- if (obj instanceof WifiPasspointCredential) {
- final WifiPasspointCredential other = (WifiPasspointCredential) obj;
- if (this.mType.equals(other.mType)) {
- if (this.mType.equals("TTLS")) {
- result = this.mUsername.equals(other.mUsername) &&
- this.mPasswd.equals(other.mPasswd) &&
- this.mRealm.equals(other.mRealm) &&
- this.mHomeSpFqdn.equals(other.mHomeSpFqdn);
- }
- if (this.mType.equals("TLS")) {
- result = this.mRealm.equals(other.mRealm) &&
- this.mHomeSpFqdn.equals(other.mHomeSpFqdn) &&
- this.mClientCert.equals(other.mClientCert);
- }
- if (this.mType.equals("SIM")) {
- result = this.mMcc.equals(other.mMcc) &&
- this.mMnc.equals(other.mMnc) &&
- this.mImsi.equals(other.mImsi) &&
- this.mHomeSpFqdn.equals(other.mHomeSpFqdn);
- }
- }
- }
- return result;
- }
-
- @Override
- /** @hide */
- public String toString() {
- StringBuffer sb = new StringBuffer();
- String none = "<none>";
-
- if (!DBG) {
- sb.append(none);
- } else {
- sb.append(", UpdateIdentifier: ")
- .append(mUpdateIdentifier == null ? none : mUpdateIdentifier)
- .append(", SubscriptionUpdateMethod: ")
- .append(mSubscriptionUpdateMethod == null ? none : mSubscriptionUpdateMethod)
- .append(", Type: ").append(mType == null ? none : mType)
- .append(", Username: ").append(mUsername == null ? none : mUsername)
- .append(", Passwd: ").append(mPasswd == null ? none : mPasswd)
- .append(", SubDMAccUsername: ")
- .append(mSubscriptionUpdateUsername == null ? none : mSubscriptionUpdateUsername)
- .append(", SubDMAccPassword: ")
- .append(mSubscriptionUpdatePassword == null ? none : mSubscriptionUpdatePassword)
- .append(", PolDMAccUsername: ")
- .append(mPolicyUpdateUsername == null ? none : mPolicyUpdateUsername)
- .append(", PolDMAccPassword: ")
- .append(mPolicyUpdatePassword == null ? none : mPolicyUpdatePassword)
- .append(", Imsi: ").append(mImsi == null ? none : mImsi)
- .append(", Mcc: ").append(mMcc == null ? none : mMcc)
- .append(", Mnc: ").append(mMnc == null ? none : mMnc)
- .append(", CaRootCert: ").append(mCaRootCert == null ? none : mCaRootCert)
- .append(", Realm: ").append(mRealm == null ? none : mRealm)
- .append(", Priority: ").append(mCrednetialPriority)
- .append(", Fqdn: ").append(mHomeSpFqdn == null ? none : mHomeSpFqdn)
- .append(", Otherhomepartners: ")
- .append(mOtherHomePartnerList == null ? none : mOtherHomePartnerList)
- .append(", ExpirationDate: ")
- .append(mExpirationDate == null ? none : mExpirationDate)
- .append(", MaxBssLoad: ").append(mMaxBssLoad == null ? none : mMaxBssLoad)
- .append(", SPExclusionList: ").append(mSpExclusionList);
-
- if (mPreferredRoamingPartnerList != null) {
- sb.append("PreferredRoamingPartnerList:");
- for (WifiPasspointDmTree.PreferredRoamingPartnerList prpListItem : mPreferredRoamingPartnerList) {
- sb.append("[fqdnmatch:").append(prpListItem.FQDN_Match).
- append(", priority:").append(prpListItem.Priority).
- append(", country:").append(prpListItem.Country).append("]");
- }
- }
-
- if (mHomeOIList != null) {
- sb.append("HomeOIList:");
- for (WifiPasspointDmTree.HomeOIList HomeOIListItem : mHomeOIList) {
- sb.append("[HomeOI:").append(HomeOIListItem.HomeOI).
- append(", HomeOIRequired:").append(HomeOIListItem.HomeOIRequired).
- append("]");
- }
- }
-
- if (mMinBackhaulThresholdNetwork != null) {
- sb.append("BackHaulThreshold:");
- for (WifiPasspointDmTree.MinBackhaulThresholdNetwork BhtListItem : mMinBackhaulThresholdNetwork) {
- sb.append("[networkType:").append(BhtListItem.NetworkType).
- append(", dlBandwidth:").append(BhtListItem.DLBandwidth).
- append(", ulBandwidth:").append(BhtListItem.ULBandwidth).
- append("]");
- }
- }
-
- if (mRequiredProtoPortTuple != null) {
- sb.append("WifiMORequiredProtoPortTupleList:");
- for (WifiPasspointDmTree.RequiredProtoPortTuple RpptListItem : mRequiredProtoPortTuple) {
- sb.append("[IPProtocol:").append(RpptListItem.IPProtocol).
- append(", PortNumber:").append(RpptListItem.PortNumber).
- append("]");
- }
- }
- }
- return sb.toString();
- }
-
- /** Implement the Parcelable interface {@hide} */
- public int describeContents() {
- return 0;
- }
-
- /** Implement the Parcelable interface {@hide} */
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mWifiSpFqdn);
- dest.writeString(mCredentialName);
- dest.writeString(mType);
- dest.writeInt(mCrednetialPriority);
- dest.writeString(mHomeSpFqdn);
- dest.writeString(mRealm);
- }
-
- /** Implement the Parcelable interface {@hide} */
- public void readFromParcel(Parcel in) {
- mWifiSpFqdn = in.readString();
- mCredentialName = in.readString();
- mType = in.readString();
- mCrednetialPriority = in.readInt();
- mHomeSpFqdn = in.readString();
- mRealm = in.readString();
- }
-
- /** Implement the Parcelable interface {@hide} */
- public static final Creator<WifiPasspointCredential> CREATOR =
- new Creator<WifiPasspointCredential>() {
- public WifiPasspointCredential createFromParcel(Parcel in) {
- WifiPasspointCredential pc = new WifiPasspointCredential();
- pc.mWifiSpFqdn = in.readString();
- pc.mCredentialName = in.readString();
- pc.mType = in.readString();
- pc.mCrednetialPriority = in.readInt();
- pc.mHomeSpFqdn = in.readString();
- pc.mRealm = in.readString();
- return pc;
- }
-
- public WifiPasspointCredential[] newArray(int size) {
- return new WifiPasspointCredential[size];
- }
- };
-
- /** @hide */
- public int compareTo(WifiPasspointCredential another) {
-
- //The smaller the higher
- if (mCrednetialPriority < another.mCrednetialPriority) {
- return -1;
- } else if (mCrednetialPriority == another.mCrednetialPriority) {
- return this.mType.compareTo(another.mType);
- } else {
- return 1;
- }
- }
-
- @Override
- /** @hide */
- public int hashCode() {
- int hash = 208;
- if (mType != null) {
- hash += mType.hashCode();
- }
- if (mRealm != null) {
- hash += mRealm.hashCode();
- }
- if (mHomeSpFqdn != null) {
- hash += mHomeSpFqdn.hashCode();
- }
- if (mUsername != null) {
- hash += mUsername.hashCode();
- }
- if (mPasswd != null) {
- hash += mPasswd.hashCode();
- }
-
- return hash;
- }
-}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.aidl
deleted file mode 100644
index 6a88b2e..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-parcelable WifiPasspointDmTree;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.java
deleted file mode 100644
index 427c84c..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.java
+++ /dev/null
@@ -1,1375 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.os.Parcelable;
-import android.os.Parcel;
-import java.util.HashMap;
-
-/**
- * Required Mobile Device Management Tree Structure
- *
- * +----------+
- * | ./(Root) |
- * +----+-----+
- * |
- * +---------+ | +---------+ +---------+
- * | DevInfo |-----------+---------| Wi-Fi |--|SP FQDN* |
- * +---------+ | +---------+ +---------+
- * +---------+ | |
- * |DevDetail|-----------+ +-----------------------+
- * +---------+ |PerproviderSubscription|--<X>+
- * +-----------------------+
- *
- * This class contains all nodes start from Wi-Fi
- * @hide
- **/
-public class WifiPasspointDmTree implements Parcelable {
- private final static String TAG = "WifiTree";
- public int PpsMoId;//plugfest used only
- public HashMap<String, SpFqdn> spFqdn = new HashMap<String, SpFqdn>();//Maps.newHashMap();
-
- public SpFqdn createSpFqdn(String name) {
- SpFqdn obj = new SpFqdn(name);
- spFqdn.put(name, obj);
- return obj;
- }
-
- public static class SpFqdn implements Parcelable {
- public String nodeName;
- public PerProviderSubscription perProviderSubscription = new PerProviderSubscription();
-
- public SpFqdn(String name) {
- nodeName = name;
- }
-
- public SpFqdn() {
- }
-
- public SpFqdn(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(nodeName);
- out.writeParcelable(perProviderSubscription, flags);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- nodeName = in.readString();
- perProviderSubscription = in.readParcelable(PerProviderSubscription.class
- .getClassLoader());
- }
- }
-
- public static final Parcelable.Creator<SpFqdn> CREATOR = new Parcelable.Creator<SpFqdn>() {
- public SpFqdn createFromParcel(Parcel in) {
- return new SpFqdn(in);
- }
-
- public SpFqdn[] newArray(int size) {
- return new SpFqdn[size];
- }
- };
- }
-
- /**
- * PerProviderSubscription
- **/
- public static class PerProviderSubscription implements Parcelable {
- /**
- * PerProviderSubscription/UpdateIdentifier
- **/
- public String UpdateIdentifier;
- public HashMap<String, CredentialInfo> credentialInfo = new HashMap<String, CredentialInfo>();
-
- public CredentialInfo createCredentialInfo(String name) {
- CredentialInfo obj = new CredentialInfo(name);
- credentialInfo.put(name, obj);
- return obj;
- }
-
- public PerProviderSubscription() {
- }
-
- public PerProviderSubscription(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(UpdateIdentifier);
- out.writeMap(credentialInfo);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- UpdateIdentifier = in.readString();
- in.readMap(credentialInfo, CredentialInfo.class.getClassLoader());
- }
- }
-
- public static final Parcelable.Creator<PerProviderSubscription> CREATOR = new Parcelable.Creator<PerProviderSubscription>() {
- public PerProviderSubscription createFromParcel(Parcel in) {
- return new PerProviderSubscription(in);
- }
-
- public PerProviderSubscription[] newArray(int size) {
- return new PerProviderSubscription[size];
- }
- };
-
- }
-
- /**
- * PerProviderSubscription/<X+>
- * This interior node contains the Home SP information, subscription policy, management and credential information.
- **/
- public static class CredentialInfo implements Parcelable {
- public String nodeName;
- public Policy policy = new Policy();
- public String credentialPriority;
- public HashMap<String, AAAServerTrustRoot> aAAServerTrustRoot = new HashMap<String, AAAServerTrustRoot>();
- public SubscriptionUpdate subscriptionUpdate = new SubscriptionUpdate();
- public HomeSP homeSP = new HomeSP();
- public SubscriptionParameters subscriptionParameters = new SubscriptionParameters();
- public Credential credential = new Credential();
- public Extension extension = new Extension();
-
- public CredentialInfo(String nn) {
- nodeName = nn;
- }
-
- public AAAServerTrustRoot createAAAServerTrustRoot(String name, String url, String fp) {
- AAAServerTrustRoot obj = new AAAServerTrustRoot(name, url, fp);
- aAAServerTrustRoot.put(name, obj);
- return obj;
- }
-
- public CredentialInfo() {
- }
-
- public CredentialInfo(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(nodeName);
- out.writeParcelable(policy, flags);
- out.writeString(credentialPriority);
- out.writeMap(aAAServerTrustRoot);
- out.writeParcelable(subscriptionUpdate, flags);
- out.writeParcelable(homeSP, flags);
- out.writeParcelable(subscriptionParameters, flags);
- out.writeParcelable(credential, flags);
- //out.writeParcelable(extension, flags);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- nodeName = in.readString();
- policy = in.readParcelable(Policy.class.getClassLoader());
- credentialPriority = in.readString();
- in.readMap(aAAServerTrustRoot, AAAServerTrustRoot.class.getClassLoader());
- subscriptionUpdate = in.readParcelable(SubscriptionUpdate.class.getClassLoader());
- homeSP = in.readParcelable(HomeSP.class.getClassLoader());
- subscriptionParameters = in.readParcelable(SubscriptionParameters.class
- .getClassLoader());
- credential = in.readParcelable(Credential.class.getClassLoader());
- //extension = in.readParcelable(Extension.class.getClassLoader());
- }
- }
-
- public static final Parcelable.Creator<CredentialInfo> CREATOR = new Parcelable.Creator<CredentialInfo>() {
- public CredentialInfo createFromParcel(Parcel in) {
- return new CredentialInfo(in);
- }
-
- public CredentialInfo[] newArray(int size) {
- return new CredentialInfo[size];
- }
- };
-
- }
-
- /**
- * PerProviderSubscription/<X+>/Policy
- **/
- public static class Policy implements Parcelable {
- public HashMap<String, PreferredRoamingPartnerList> preferredRoamingPartnerList = new HashMap<String, PreferredRoamingPartnerList>();
- public HashMap<String, MinBackhaulThresholdNetwork> minBackhaulThreshold = new HashMap<String, MinBackhaulThresholdNetwork>();
- public PolicyUpdate policyUpdate = new PolicyUpdate();
- public HashMap<String, SPExclusionList> sPExclusionList = new HashMap<String, SPExclusionList>();
- public HashMap<String, RequiredProtoPortTuple> requiredProtoPortTuple = new HashMap<String, RequiredProtoPortTuple>();
- public String maximumBSSLoadValue;
-
- public PreferredRoamingPartnerList createPreferredRoamingPartnerList(String name,
- String fqdn, String priority, String country) {
- PreferredRoamingPartnerList obj = new PreferredRoamingPartnerList(name, fqdn, priority,
- country);
- preferredRoamingPartnerList.put(name, obj);
- return obj;
- }
-
- public MinBackhaulThresholdNetwork createMinBackhaulThreshold(String name, String type,
- String dl, String ul) {
- MinBackhaulThresholdNetwork obj = new MinBackhaulThresholdNetwork(name, type, dl, ul);
- minBackhaulThreshold.put(name, obj);
- return obj;
- }
-
- public SPExclusionList createSPExclusionList(String name, String ssid) {
- SPExclusionList obj = new SPExclusionList(name, ssid);
- sPExclusionList.put(name, obj);
- return obj;
- }
-
- public RequiredProtoPortTuple createRequiredProtoPortTuple(String name, String proto,
- String port) {
- RequiredProtoPortTuple obj = new RequiredProtoPortTuple(name, proto, port);
- requiredProtoPortTuple.put(name, obj);
- return obj;
- }
-
- public Policy() {
- }
-
- public Policy(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeMap(preferredRoamingPartnerList);
- out.writeMap(minBackhaulThreshold);
- out.writeParcelable(policyUpdate, flags);
- out.writeMap(sPExclusionList);
- out.writeMap(requiredProtoPortTuple);
- out.writeString(maximumBSSLoadValue);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- in.readMap(preferredRoamingPartnerList,
- PreferredRoamingPartnerList.class.getClassLoader());
- in.readMap(minBackhaulThreshold, MinBackhaulThresholdNetwork.class.getClassLoader());
- policyUpdate = in.readParcelable(PolicyUpdate.class.getClassLoader());
- in.readMap(sPExclusionList, SPExclusionList.class.getClassLoader());
- in.readMap(requiredProtoPortTuple, RequiredProtoPortTuple.class.getClassLoader());
- maximumBSSLoadValue = in.readString();
-
- }
- }
-
- public static final Parcelable.Creator<Policy> CREATOR = new Parcelable.Creator<Policy>() {
- public Policy createFromParcel(Parcel in) {
- return new Policy(in);
- }
-
- public Policy[] newArray(int size) {
- return new Policy[size];
- }
- };
-
- }
-
- /**
- * PerProviderSubscription/<X+>/Policy/PreferredRoamingPartnerList/<X+>
- **/
- public static class PreferredRoamingPartnerList implements Parcelable {
- public String nodeName;
- public String FQDN_Match; //maximum 255 + ",includeSubdomains", equals 273
- public String Priority;
- public String Country; // maximum 600 octets
-
- public PreferredRoamingPartnerList(String nn, String f, String p, String c) {
- nodeName = nn;
- FQDN_Match = f;
- Priority = p;
- Country = c;
- }
-
- public PreferredRoamingPartnerList() {
- }
-
- public PreferredRoamingPartnerList(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(nodeName);
- out.writeString(FQDN_Match);
- out.writeString(Priority);
- out.writeString(Country);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- nodeName = in.readString();
- FQDN_Match = in.readString();
- Priority = in.readString();
- Country = in.readString();
- }
- }
-
- public static final Parcelable.Creator<PreferredRoamingPartnerList> CREATOR = new Parcelable.Creator<PreferredRoamingPartnerList>() {
- public PreferredRoamingPartnerList createFromParcel(Parcel in) {
- return new PreferredRoamingPartnerList(in);
- }
-
- public PreferredRoamingPartnerList[] newArray(int size) {
- return new PreferredRoamingPartnerList[size];
- }
- };
- }
-
- /**
- * PerProviderSubscription/<X+>/Policy/MinBackhaulThreshold
- **/
- public static class MinBackhaulThresholdNetwork implements Parcelable {
- public String nodeName;
- public String NetworkType;
- public String DLBandwidth;
- public String ULBandwidth;
-
- public MinBackhaulThresholdNetwork(String nn, String nt, String d, String u) {
- nodeName = nn;
- NetworkType = nt;
- DLBandwidth = d;
- ULBandwidth = u;
- }
-
- public MinBackhaulThresholdNetwork() {
- }
-
- public MinBackhaulThresholdNetwork(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(nodeName);
- out.writeString(NetworkType);
- out.writeString(DLBandwidth);
- out.writeString(ULBandwidth);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- nodeName = in.readString();
- NetworkType = in.readString();
- DLBandwidth = in.readString();
- ULBandwidth = in.readString();
- }
- }
-
- public static final Parcelable.Creator<MinBackhaulThresholdNetwork> CREATOR = new Parcelable.Creator<MinBackhaulThresholdNetwork>() {
- public MinBackhaulThresholdNetwork createFromParcel(Parcel in) {
- return new MinBackhaulThresholdNetwork(in);
- }
-
- public MinBackhaulThresholdNetwork[] newArray(int size) {
- return new MinBackhaulThresholdNetwork[size];
- }
- };
-
- }
-
- /**
- * PerProviderSubscription/<X+>/Policy/PolicyUpdate
- **/
- public static class PolicyUpdate implements Parcelable {
- public String UpdateInterval;
- public String UpdateMethod;
- public String Restriction;
- public String URI;
- public UsernamePassword usernamePassword = new UsernamePassword();
- public String Other;
- public TrustRoot trustRoot = new TrustRoot();
-
- public PolicyUpdate() {
- }
-
- public PolicyUpdate(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(UpdateInterval);
- out.writeString(UpdateMethod);
- out.writeString(Restriction);
- out.writeString(URI);
- out.writeParcelable(usernamePassword, flags);
- out.writeString(Other);
- out.writeParcelable(trustRoot, flags);
-
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- UpdateInterval = in.readString();
- UpdateMethod = in.readString();
- Restriction = in.readString();
- URI = in.readString();
- usernamePassword = in.readParcelable(UsernamePassword.class.getClassLoader());
- Other = in.readString();
- trustRoot = in.readParcelable(TrustRoot.class.getClassLoader());
- }
- }
-
- public static final Parcelable.Creator<PolicyUpdate> CREATOR = new Parcelable.Creator<PolicyUpdate>() {
- public PolicyUpdate createFromParcel(Parcel in) {
- return new PolicyUpdate(in);
- }
-
- public PolicyUpdate[] newArray(int size) {
- return new PolicyUpdate[size];
- }
- };
- }
-
- /**
- * PerProviderSubscription/<X+>/Policy/SPExclusionList
- **/
- public static class SPExclusionList implements Parcelable {
- public String nodeName;
- public String SSID;
-
- public SPExclusionList(String nn, String s) {
- nodeName = nn;
- SSID = s;
- }
-
- public SPExclusionList() {
- }
-
- public SPExclusionList(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(nodeName);
- out.writeString(SSID);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- nodeName = in.readString();
- SSID = in.readString();
- }
- }
-
- public static final Parcelable.Creator<SPExclusionList> CREATOR = new Parcelable.Creator<SPExclusionList>() {
- public SPExclusionList createFromParcel(Parcel in) {
- return new SPExclusionList(in);
- }
-
- public SPExclusionList[] newArray(int size) {
- return new SPExclusionList[size];
- }
- };
- }
-
- /**
- * PerProviderSubscription/<X+>/Policy/RequiredProtoPortTuple
- **/
- public static class RequiredProtoPortTuple implements Parcelable {
- public String nodeName;
- public String IPProtocol;
- public String PortNumber;
-
- public RequiredProtoPortTuple() {
- }
-
- public RequiredProtoPortTuple(String nn, String protocol, String port) {
- nodeName = nn;
- IPProtocol = protocol;
- PortNumber = port;
- }
-
- public RequiredProtoPortTuple(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(nodeName);
- out.writeString(IPProtocol);
- out.writeString(PortNumber);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- nodeName = in.readString();
- IPProtocol = in.readString();
- PortNumber = in.readString();
- }
- }
-
- public static final Parcelable.Creator<RequiredProtoPortTuple> CREATOR = new Parcelable.Creator<RequiredProtoPortTuple>() {
- public RequiredProtoPortTuple createFromParcel(Parcel in) {
- return new RequiredProtoPortTuple(in);
- }
-
- public RequiredProtoPortTuple[] newArray(int size) {
- return new RequiredProtoPortTuple[size];
- }
- };
- }
-
- /**
- * PerProviderSubscription/<X+>/AAAServerTrustRoot
- **/
- public static class AAAServerTrustRoot implements Parcelable {
- public String nodeName;
- public String CertURL;
- public String CertSHA256Fingerprint;
-
- public AAAServerTrustRoot(String nn, String url, String fp) {
- nodeName = nn;
- CertURL = url;
- CertSHA256Fingerprint = fp;
- }
-
- public AAAServerTrustRoot() {
- }
-
- public AAAServerTrustRoot(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(nodeName);
- out.writeString(CertURL);
- out.writeString(CertSHA256Fingerprint);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- nodeName = in.readString();
- CertURL = in.readString();
- CertSHA256Fingerprint = in.readString();
- }
- }
-
- public static final Parcelable.Creator<AAAServerTrustRoot> CREATOR = new Parcelable.Creator<AAAServerTrustRoot>() {
- public AAAServerTrustRoot createFromParcel(Parcel in) {
- return new AAAServerTrustRoot(in);
- }
-
- public AAAServerTrustRoot[] newArray(int size) {
- return new AAAServerTrustRoot[size];
- }
- };
- }
-
- /**
- * PerProviderSubscription/<X+>/SubscriptionUpdate
- **/
- public static class SubscriptionUpdate implements Parcelable {
- public String UpdateInterval;
- public String UpdateMethod;
- public String Restriction;
- public String URI;
- public UsernamePassword usernamePassword = new UsernamePassword();
- public String Other;
- public TrustRoot trustRoot = new TrustRoot();
-
- public SubscriptionUpdate() {
- }
-
- public SubscriptionUpdate(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(UpdateInterval);
- out.writeString(UpdateMethod);
- out.writeString(Restriction);
- out.writeString(URI);
- out.writeParcelable(usernamePassword, flags);
- out.writeString(Other);
- out.writeParcelable(trustRoot, flags);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- UpdateInterval = in.readString();
- UpdateMethod = in.readString();
- Restriction = in.readString();
- URI = in.readString();
- usernamePassword = in.readParcelable(UsernamePassword.class.getClassLoader());
- Other = in.readString();
- trustRoot = in.readParcelable(TrustRoot.class.getClassLoader());
- }
- }
-
- public static final Parcelable.Creator<SubscriptionUpdate> CREATOR = new Parcelable.Creator<SubscriptionUpdate>() {
- public SubscriptionUpdate createFromParcel(Parcel in) {
- return new SubscriptionUpdate(in);
- }
-
- public SubscriptionUpdate[] newArray(int size) {
- return new SubscriptionUpdate[size];
- }
- };
-
- }
-
- /**
- * PerProviderSubscription/<X+>/Policy/PolicyUpdate/TrustRoot
- * PerProviderSubscription/<X+>/SubscriptionUpdate/TrustRoot
- * PerProviderSubscription/<X+>/AAAServerTrustRoot/<X+>
- **/
- public static class TrustRoot implements Parcelable {
- public String CertURL;
- public String CertSHA256Fingerprint;
-
- public TrustRoot() {
- }
-
- public TrustRoot(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(CertURL);
- out.writeString(CertSHA256Fingerprint);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- CertURL = in.readString();
- CertSHA256Fingerprint = in.readString();
- }
- }
-
- public static final Parcelable.Creator<TrustRoot> CREATOR = new Parcelable.Creator<TrustRoot>() {
- public TrustRoot createFromParcel(Parcel in) {
- return new TrustRoot(in);
- }
-
- public TrustRoot[] newArray(int size) {
- return new TrustRoot[size];
- }
- };
- }
-
- /**
- * PerProviderSubscription/<X+>/Policy/PolicyUpdate/UsernamePassword
- * PerProviderSubscription/<X+>/SubscriptionUpdate/UsernamePassword
- * PerProviderSubscription/<X+>/Credential/UsernamePassword
- **/
- public static class UsernamePassword implements Parcelable {
- public String Username;
- public String Password;
- //following are Credential node used only
- public boolean MachineManaged;
- public String SoftTokenApp;
- public String AbleToShare;
- public EAPMethod eAPMethod = new EAPMethod();
-
- public UsernamePassword() {
- }
-
- public UsernamePassword(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(Username);
- out.writeString(Password);
- out.writeInt(MachineManaged ? 1 : 0);
- out.writeString(SoftTokenApp);
- out.writeString(AbleToShare);
- out.writeParcelable(eAPMethod, flags);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- Username = in.readString();
- Password = in.readString();
- MachineManaged = (in.readInt() == 1) ? true : false;
- SoftTokenApp = in.readString();
- AbleToShare = in.readString();
- eAPMethod = in.readParcelable(EAPMethod.class.getClassLoader());
- }
- }
-
- public static final Parcelable.Creator<UsernamePassword> CREATOR = new Parcelable.Creator<UsernamePassword>() {
- public UsernamePassword createFromParcel(Parcel in) {
- return new UsernamePassword(in);
- }
-
- public UsernamePassword[] newArray(int size) {
- return new UsernamePassword[size];
- }
- };
-
- }
-
- /**
- * PerProviderSubscription/<X+>/Credential/UsernamePassword/EAPMethod
- **/
- public static class EAPMethod implements Parcelable {
- public String EAPType;
- public String VendorId;
- public String VendorType;
- public String InnerEAPType;
- public String InnerVendorId;
- public String InnerVendorType;
- public String InnerMethod;
-
- public EAPMethod() {
- }
-
- public EAPMethod(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(EAPType);
- out.writeString(VendorId);
- out.writeString(VendorType);
- out.writeString(InnerEAPType);
- out.writeString(InnerVendorId);
- out.writeString(InnerVendorType);
- out.writeString(InnerMethod);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- EAPType = in.readString();
- VendorId = in.readString();
- VendorType = in.readString();
- InnerEAPType = in.readString();
- InnerVendorId = in.readString();
- InnerVendorType = in.readString();
- InnerMethod = in.readString();
- }
- }
-
- public static final Parcelable.Creator<EAPMethod> CREATOR = new Parcelable.Creator<EAPMethod>() {
- public EAPMethod createFromParcel(Parcel in) {
- return new EAPMethod(in);
- }
-
- public EAPMethod[] newArray(int size) {
- return new EAPMethod[size];
- }
- };
- }
-
- /**
- * PerProviderSubscription/<X+>/HomeSP
- **/
- public static class HomeSP implements Parcelable {
- public HashMap<String, NetworkID> networkID = new HashMap<String, NetworkID>();
- public String FriendlyName;
- public String IconURL;
- public String FQDN;
- public HashMap<String, HomeOIList> homeOIList = new HashMap<String, HomeOIList>();
- public HashMap<String, OtherHomePartners> otherHomePartners = new HashMap<String, OtherHomePartners>();
- public String RoamingConsortiumOI;
-
- public NetworkID createNetworkID(String name, String ssid, String hessid) {
- NetworkID obj = new NetworkID(name, ssid, hessid);
- networkID.put(name, obj);
- return obj;
- }
-
- public HomeOIList createHomeOIList(String name, String homeoi, boolean required) {
- HomeOIList obj = new HomeOIList(name, homeoi, required);
- homeOIList.put(name, obj);
- return obj;
- }
-
- public OtherHomePartners createOtherHomePartners(String name, String fqdn) {
- OtherHomePartners obj = new OtherHomePartners(name, fqdn);
- otherHomePartners.put(name, obj);
- return obj;
- }
-
- public HomeSP() {
- }
-
- public HomeSP(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeMap(networkID);
- out.writeString(FriendlyName);
- out.writeString(IconURL);
- out.writeString(FQDN);
- out.writeMap(homeOIList);
- out.writeMap(otherHomePartners);
- out.writeString(RoamingConsortiumOI);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- in.readMap(networkID, NetworkID.class.getClassLoader());
- FriendlyName = in.readString();
- IconURL = in.readString();
- FQDN = in.readString();
- in.readMap(homeOIList, HomeOIList.class.getClassLoader());
- in.readMap(otherHomePartners, OtherHomePartners.class.getClassLoader());
- RoamingConsortiumOI = in.readString();
- }
- }
-
- public static final Parcelable.Creator<HomeSP> CREATOR = new Parcelable.Creator<HomeSP>() {
- public HomeSP createFromParcel(Parcel in) {
- return new HomeSP(in);
- }
-
- public HomeSP[] newArray(int size) {
- return new HomeSP[size];
- }
- };
-
- }
-
- /**
- * PerProviderSubscription/<X+>/HomeSP/NetworkID
- **/
- public static class NetworkID implements Parcelable {
- public String nodeName;
- public String SSID;
- public String HESSID;
-
- public NetworkID(String nn, String s, String h) {
- nodeName = nn;
- SSID = s;
- HESSID = h;
- }
-
- public NetworkID() {
- }
-
- public NetworkID(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(nodeName);
- out.writeString(SSID);
- out.writeString(HESSID);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- nodeName = in.readString();
- SSID = in.readString();
- HESSID = in.readString();
- }
- }
-
- public static final Parcelable.Creator<NetworkID> CREATOR = new Parcelable.Creator<NetworkID>() {
- public NetworkID createFromParcel(Parcel in) {
- return new NetworkID(in);
- }
-
- public NetworkID[] newArray(int size) {
- return new NetworkID[size];
- }
- };
-
- }
-
- /**
- * PerProviderSubscription/<X+>/HomeSP/HomeOIList
- **/
- public static class HomeOIList implements Parcelable {
- public String nodeName;
- public String HomeOI;
- public boolean HomeOIRequired;
-
- public HomeOIList(String nn, String h, boolean r) {
- nodeName = nn;
- HomeOI = h;
- HomeOIRequired = r;
- }
-
- public HomeOIList() {
- }
-
- public HomeOIList(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(nodeName);
- out.writeString(HomeOI);
- out.writeInt(HomeOIRequired ? 1 : 0);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- nodeName = in.readString();
- HomeOI = in.readString();
- HomeOIRequired = (in.readInt() == 1) ? true : false;
- }
- }
-
- public static final Parcelable.Creator<HomeOIList> CREATOR = new Parcelable.Creator<HomeOIList>() {
- public HomeOIList createFromParcel(Parcel in) {
- return new HomeOIList(in);
- }
-
- public HomeOIList[] newArray(int size) {
- return new HomeOIList[size];
- }
- };
-
- }
-
- /**
- * PerProviderSubscription/<X+>/HomeSP/OtherHomePartners
- **/
- public static class OtherHomePartners implements Parcelable {
- public String nodeName;
- public String FQDN;
-
- public OtherHomePartners(String nn, String f) {
- nodeName = nn;
- FQDN = f;
- }
-
- public OtherHomePartners() {
- }
-
- public OtherHomePartners(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(nodeName);
- out.writeString(FQDN);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- nodeName = in.readString();
- FQDN = in.readString();
- }
- }
-
- public static final Parcelable.Creator<OtherHomePartners> CREATOR = new Parcelable.Creator<OtherHomePartners>() {
- public OtherHomePartners createFromParcel(Parcel in) {
- return new OtherHomePartners(in);
- }
-
- public OtherHomePartners[] newArray(int size) {
- return new OtherHomePartners[size];
- }
- };
-
- }
-
- /**
- * PerProviderSubscription/<X+>/SubscriptionParameters
- **/
- public static class SubscriptionParameters implements Parcelable {
- public String CreationDate;
- public String ExpirationDate;
- public String TypeOfSubscription;
- public UsageLimits usageLimits = new UsageLimits();
-
- public SubscriptionParameters() {
- }
-
- public SubscriptionParameters(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(CreationDate);
- out.writeString(ExpirationDate);
- out.writeString(TypeOfSubscription);
- out.writeParcelable(usageLimits, flags);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- CreationDate = in.readString();
- ExpirationDate = in.readString();
- TypeOfSubscription = in.readString();
- usageLimits = in.readParcelable(UsageLimits.class.getClassLoader());
- }
- }
-
- public static final Parcelable.Creator<SubscriptionParameters> CREATOR = new Parcelable.Creator<SubscriptionParameters>() {
- public SubscriptionParameters createFromParcel(Parcel in) {
- return new SubscriptionParameters(in);
- }
-
- public SubscriptionParameters[] newArray(int size) {
- return new SubscriptionParameters[size];
- }
- };
-
- }
-
- /**
- * PerProviderSubscription/<X+>/SubscriptionParameters/UsageLimits
- **/
- public static class UsageLimits implements Parcelable {
- public String DataLimit;
- public String StartDate;
- public String TimeLimit;
- public String UsageTimePeriod;
-
- public UsageLimits() {
- }
-
- public UsageLimits(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(DataLimit);
- out.writeString(StartDate);
- out.writeString(TimeLimit);
- out.writeString(UsageTimePeriod);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- DataLimit = in.readString();
- StartDate = in.readString();
- TimeLimit = in.readString();
- UsageTimePeriod = in.readString();
- }
- }
-
- public static final Parcelable.Creator<UsageLimits> CREATOR = new Parcelable.Creator<UsageLimits>() {
- public UsageLimits createFromParcel(Parcel in) {
- return new UsageLimits(in);
- }
-
- public UsageLimits[] newArray(int size) {
- return new UsageLimits[size];
- }
- };
- }
-
- /**
- * PerProviderSubscription/<X+>/Credential
- **/
- public static class Credential implements Parcelable {
- public String CreationDate;
- public String ExpirationDate;
- public UsernamePassword usernamePassword = new UsernamePassword();
- public DigitalCertificate digitalCertificate = new DigitalCertificate();
- public String Realm;
- public boolean CheckAAAServerCertStatus;
- public SIM sim = new SIM();
-
- public Credential() {
- }
-
- public Credential(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(CreationDate);
- out.writeString(ExpirationDate);
- out.writeParcelable(usernamePassword, flags);
- out.writeParcelable(digitalCertificate, flags);
- out.writeString(Realm);
- out.writeInt(CheckAAAServerCertStatus ? 1 : 0);
- out.writeParcelable(sim, flags);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- CreationDate = in.readString();
- ExpirationDate = in.readString();
- usernamePassword = in.readParcelable(UsernamePassword.class.getClassLoader());
- digitalCertificate = in.readParcelable(DigitalCertificate.class.getClassLoader());
- Realm = in.readString();
- CheckAAAServerCertStatus = (in.readInt() == 1) ? true : false;
- sim = in.readParcelable(SIM.class.getClassLoader());
- }
- }
-
- public static final Parcelable.Creator<Credential> CREATOR = new Parcelable.Creator<Credential>() {
- public Credential createFromParcel(Parcel in) {
- return new Credential(in);
- }
-
- public Credential[] newArray(int size) {
- return new Credential[size];
- }
- };
- }
-
- /**
- * PerProviderSubscription/<X+>/Credential/DigitalCertificate
- **/
- public static class DigitalCertificate implements Parcelable {
- public String CertificateType;
- public String CertSHA256Fingerprint;
-
- public DigitalCertificate() {
- }
-
- public DigitalCertificate(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(CertificateType);
- out.writeString(CertSHA256Fingerprint);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- CertificateType = in.readString();
- CertSHA256Fingerprint = in.readString();
- }
- }
-
- public static final Parcelable.Creator<DigitalCertificate> CREATOR = new Parcelable.Creator<DigitalCertificate>() {
- public DigitalCertificate createFromParcel(Parcel in) {
- return new DigitalCertificate(in);
- }
-
- public DigitalCertificate[] newArray(int size) {
- return new DigitalCertificate[size];
- }
- };
-
- }
-
- /**
- * PerProviderSubscription/<X+>/Credential/SIM
- **/
- public static class SIM implements Parcelable {
- public String IMSI;
- public String EAPType;
-
- public SIM() {
- }
-
- public SIM(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(IMSI);
- out.writeString(EAPType);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- IMSI = in.readString();
- EAPType = in.readString();
- }
- }
-
- public static final Parcelable.Creator<SIM> CREATOR = new Parcelable.Creator<SIM>() {
- public SIM createFromParcel(Parcel in) {
- return new SIM(in);
- }
-
- public SIM[] newArray(int size) {
- return new SIM[size];
- }
- };
-
- }
-
- /**
- * PerProviderSubscription/<X+>/Extension
- **/
- public static class Extension {
- public String empty;
- }
-
- public WifiPasspointDmTree() {
- }
-
- public WifiPasspointDmTree(Parcel in) {
- readFromParcel(in);
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel out, int flags) {
- out.writeMap(spFqdn);
- }
-
- public void readFromParcel(Parcel in) {
- if (in == null) {
- //log here
- } else {
- in.readMap(spFqdn, SpFqdn.class.getClassLoader());
- }
- }
-
- public static final Parcelable.Creator<WifiPasspointDmTree> CREATOR = new Parcelable.Creator<WifiPasspointDmTree>() {
- public WifiPasspointDmTree createFromParcel(Parcel in) {
- return new WifiPasspointDmTree(in);
- }
-
- public WifiPasspointDmTree[] newArray(int size) {
- return new WifiPasspointDmTree[size];
- }
- };
-
-}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.aidl
deleted file mode 100644
index 27f23bc..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-parcelable WifiPasspointInfo;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
deleted file mode 100644
index 33db3f5..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
+++ /dev/null
@@ -1,559 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/** @hide */
-public class WifiPasspointInfo implements Parcelable {
-
- /** TODO doc */
- public static final int ANQP_CAPABILITY = 1 << 0;
-
- /** TODO doc */
- public static final int VENUE_NAME = 1 << 1;
-
- /** TODO doc */
- public static final int NETWORK_AUTH_TYPE = 1 << 2;
-
- /** TODO doc */
- public static final int ROAMING_CONSORTIUM = 1 << 3;
-
- /** TODO doc */
- public static final int IP_ADDR_TYPE_AVAILABILITY = 1 << 4;
-
- /** TODO doc */
- public static final int NAI_REALM = 1 << 5;
-
- /** TODO doc */
- public static final int CELLULAR_NETWORK = 1 << 6;
-
- /** TODO doc */
- public static final int DOMAIN_NAME = 1 << 7;
-
- /** TODO doc */
- public static final int HOTSPOT_CAPABILITY = 1 << 8;
-
- /** TODO doc */
- public static final int OPERATOR_FRIENDLY_NAME = 1 << 9;
-
- /** TODO doc */
- public static final int WAN_METRICS = 1 << 10;
-
- /** TODO doc */
- public static final int CONNECTION_CAPABILITY = 1 << 11;
-
- /** TODO doc */
- public static final int OSU_PROVIDER = 1 << 12;
-
- /** TODO doc */
- public static final int PRESET_CRED_MATCH =
- ANQP_CAPABILITY |
- HOTSPOT_CAPABILITY |
- NAI_REALM |
- CELLULAR_NETWORK |
- DOMAIN_NAME;
-
- /** TODO doc */
- public static final int PRESET_ALL =
- ANQP_CAPABILITY |
- VENUE_NAME |
- NETWORK_AUTH_TYPE |
- ROAMING_CONSORTIUM |
- IP_ADDR_TYPE_AVAILABILITY |
- NAI_REALM |
- CELLULAR_NETWORK |
- DOMAIN_NAME |
- HOTSPOT_CAPABILITY |
- OPERATOR_FRIENDLY_NAME |
- WAN_METRICS |
- CONNECTION_CAPABILITY |
- OSU_PROVIDER;
-
-
- public static class WanMetrics {
- public static final int STATUS_RESERVED = 0;
- public static final int STATUS_UP = 1;
- public static final int STATUS_DOWN = 2;
- public static final int STATUS_TEST = 3;
-
- public int wanInfo;
- public long downlinkSpeed;
- public long uplinkSpeed;
- public int downlinkLoad;
- public int uplinkLoad;
- public int lmd;
-
- public int getLinkStatus() {
- return wanInfo & 0x3;
- }
-
- public boolean getSymmetricLink() {
- return (wanInfo & (1 << 2)) != 0;
- }
-
- public boolean getAtCapacity() {
- return (wanInfo & (1 << 3)) != 0;
- }
-
- @Override
- public String toString() {
- return wanInfo + "," + downlinkSpeed + "," + uplinkSpeed + "," +
- downlinkLoad + "," + uplinkLoad + "," + lmd;
- }
- }
-
- public static class IpProtoPort {
- public static final int STATUS_CLOSED = 0;
- public static final int STATUS_OPEN = 1;
- public static final int STATUS_UNKNOWN = 2;
-
- public int proto;
- public int port;
- public int status;
-
- @Override
- public String toString() {
- return proto + "," + port + "," + status;
- }
- }
-
- public static class NetworkAuthType {
- public static final int TYPE_TERMS_AND_CONDITION = 0;
- public static final int TYPE_ONLINE_ENROLLMENT = 1;
- public static final int TYPE_HTTP_REDIRECTION = 2;
- public static final int TYPE_DNS_REDIRECTION = 3;
-
- public int type;
- public String redirectUrl;
-
- @Override
- public String toString() {
- return type + "," + redirectUrl;
- }
- }
-
- public static class IpAddressType {
- public static final int IPV6_NOT_AVAILABLE = 0;
- public static final int IPV6_AVAILABLE = 1;
- public static final int IPV6_UNKNOWN = 2;
-
- public static final int IPV4_NOT_AVAILABLE = 0;
- public static final int IPV4_PUBLIC = 1;
- public static final int IPV4_PORT_RESTRICTED = 2;
- public static final int IPV4_SINGLE_NAT = 3;
- public static final int IPV4_DOUBLE_NAT = 4;
- public static final int IPV4_PORT_RESTRICTED_SINGLE_NAT = 5;
- public static final int IPV4_PORT_RESTRICTED_DOUBLE_NAT = 6;
- public static final int IPV4_PORT_UNKNOWN = 7;
-
- private static final int NULL_VALUE = -1;
-
- public int availability;
-
- public int getIpv6Availability() {
- return availability & 0x3;
- }
-
- public int getIpv4Availability() {
- return (availability & 0xFF) >> 2;
- }
-
- @Override
- public String toString() {
- return getIpv6Availability() + "," + getIpv4Availability();
- }
- }
-
- public static class NaiRealm {
- public static final int ENCODING_RFC4282 = 0;
- public static final int ENCODING_UTF8 = 1;
-
- public int encoding;
- public String realm;
-
- @Override
- public String toString() {
- return encoding + "," + realm;
- }
- }
-
- public static class CellularNetwork {
- public String mcc;
- public String mnc;
-
- @Override
- public String toString() {
- return mcc + "," + mnc;
- }
- }
-
- /** BSSID */
- public String bssid;
-
- /** venue name */
- public String venueName;
-
- /** list of network authentication types */
- public List<NetworkAuthType> networkAuthTypeList;
-
- /** list of roaming consortium OIs */
- public List<String> roamingConsortiumList;
-
- /** IP address availability */
- public IpAddressType ipAddrTypeAvailability;
-
- /** list of NAI realm */
- public List<NaiRealm> naiRealmList;
-
- /** list of 3GPP cellular network */
- public List<CellularNetwork> cellularNetworkList;
-
- /** list of fully qualified domain name (FQDN) */
- public List<String> domainNameList;
-
- /** HS 2.0 operator friendly name */
- public String operatorFriendlyName;
-
- /** HS 2.0 wan metrics */
- public WanMetrics wanMetrics;
-
- /** list of HS 2.0 IP proto port */
- public List<IpProtoPort> connectionCapabilityList;
-
- /** list of HS 2.0 OSU providers */
- public List<WifiPasspointOsuProvider> osuProviderList;
-
- /**
- * Convert mask to ANQP subtypes, for supplicant command use.
- *
- * @param mask The ANQP subtypes mask.
- * @return String of ANQP subtypes, good for supplicant command use
- * @hide
- */
- public static String toAnqpSubtypes(int mask) {
- StringBuilder sb = new StringBuilder();
- if ((mask & ANQP_CAPABILITY) != 0)
- sb.append("257,");
- if ((mask & VENUE_NAME) != 0)
- sb.append("258,");
- if ((mask & NETWORK_AUTH_TYPE) != 0)
- sb.append("260,");
- if ((mask & ROAMING_CONSORTIUM) != 0)
- sb.append("261,");
- if ((mask & IP_ADDR_TYPE_AVAILABILITY) != 0)
- sb.append("262,");
- if ((mask & NAI_REALM) != 0)
- sb.append("263,");
- if ((mask & CELLULAR_NETWORK) != 0)
- sb.append("264,");
- if ((mask & DOMAIN_NAME) != 0)
- sb.append("268,");
- if ((mask & HOTSPOT_CAPABILITY) != 0)
- sb.append("hs20:2,");
- if ((mask & OPERATOR_FRIENDLY_NAME) != 0)
- sb.append("hs20:3,");
- if ((mask & WAN_METRICS) != 0)
- sb.append("hs20:4,");
- if ((mask & CONNECTION_CAPABILITY) != 0)
- sb.append("hs20:5,");
- if ((mask & OSU_PROVIDER) != 0)
- sb.append("hs20:8,");
- if (sb.length() > 0)
- sb.deleteCharAt(sb.length() - 1);
- return sb.toString();
- }
-
- @Override
- public String toString() {
- StringBuffer sb = new StringBuffer();
-
- sb.append("BSSID: ").append("(").append(bssid).append(")");
-
- if (venueName != null)
- sb.append(" venueName: ").append("(")
- .append(venueName.replace("\n", "\\n")).append(")");
-
- if (networkAuthTypeList != null) {
- sb.append(" networkAuthType: ");
- for (NetworkAuthType auth : networkAuthTypeList)
- sb.append("(").append(auth.toString()).append(")");
- }
-
- if (roamingConsortiumList != null) {
- sb.append(" roamingConsortium: ");
- for (String oi : roamingConsortiumList)
- sb.append("(").append(oi).append(")");
- }
-
- if (ipAddrTypeAvailability != null) {
- sb.append(" ipAddrTypeAvaibility: ").append("(")
- .append(ipAddrTypeAvailability.toString()).append(")");
- }
-
- if (naiRealmList != null) {
- sb.append(" naiRealm: ");
- for (NaiRealm realm : naiRealmList)
- sb.append("(").append(realm.toString()).append(")");
- }
-
- if (cellularNetworkList != null) {
- sb.append(" cellularNetwork: ");
- for (CellularNetwork plmn : cellularNetworkList)
- sb.append("(").append(plmn.toString()).append(")");
- }
-
- if (domainNameList != null) {
- sb.append(" domainName: ");
- for (String fqdn : domainNameList)
- sb.append("(").append(fqdn).append(")");
- }
-
- if (operatorFriendlyName != null)
- sb.append(" operatorFriendlyName: ").append("(")
- .append(operatorFriendlyName).append(")");
-
- if (wanMetrics != null)
- sb.append(" wanMetrics: ").append("(")
- .append(wanMetrics.toString()).append(")");
-
- if (connectionCapabilityList != null) {
- sb.append(" connectionCapability: ");
- for (IpProtoPort ip : connectionCapabilityList)
- sb.append("(").append(ip.toString()).append(")");
- }
-
- if (osuProviderList != null) {
- sb.append(" osuProviderList: ");
- for (WifiPasspointOsuProvider osu : osuProviderList)
- sb.append("(").append(osu.toString()).append(")");
- }
-
- return sb.toString();
- }
-
- /** Implement the Parcelable interface {@hide} */
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(bssid);
- out.writeString(venueName);
-
- if (networkAuthTypeList == null) {
- out.writeInt(0);
- } else {
- out.writeInt(networkAuthTypeList.size());
- for (NetworkAuthType auth : networkAuthTypeList) {
- out.writeInt(auth.type);
- out.writeString(auth.redirectUrl);
- }
- }
-
- if (roamingConsortiumList == null) {
- out.writeInt(0);
- } else {
- out.writeInt(roamingConsortiumList.size());
- for (String oi : roamingConsortiumList)
- out.writeString(oi);
- }
-
- if (ipAddrTypeAvailability == null) {
- out.writeInt(IpAddressType.NULL_VALUE);
- } else {
- out.writeInt(ipAddrTypeAvailability.availability);
- }
-
- if (naiRealmList == null) {
- out.writeInt(0);
- } else {
- out.writeInt(naiRealmList.size());
- for (NaiRealm realm : naiRealmList) {
- out.writeInt(realm.encoding);
- out.writeString(realm.realm);
- }
- }
-
- if (cellularNetworkList == null) {
- out.writeInt(0);
- } else {
- out.writeInt(cellularNetworkList.size());
- for (CellularNetwork plmn : cellularNetworkList) {
- out.writeString(plmn.mcc);
- out.writeString(plmn.mnc);
- }
- }
-
-
- if (domainNameList == null) {
- out.writeInt(0);
- } else {
- out.writeInt(domainNameList.size());
- for (String fqdn : domainNameList)
- out.writeString(fqdn);
- }
-
- out.writeString(operatorFriendlyName);
-
- if (wanMetrics == null) {
- out.writeInt(0);
- } else {
- out.writeInt(1);
- out.writeInt(wanMetrics.wanInfo);
- out.writeLong(wanMetrics.downlinkSpeed);
- out.writeLong(wanMetrics.uplinkSpeed);
- out.writeInt(wanMetrics.downlinkLoad);
- out.writeInt(wanMetrics.uplinkLoad);
- out.writeInt(wanMetrics.lmd);
- }
-
- if (connectionCapabilityList == null) {
- out.writeInt(0);
- } else {
- out.writeInt(connectionCapabilityList.size());
- for (IpProtoPort ip : connectionCapabilityList) {
- out.writeInt(ip.proto);
- out.writeInt(ip.port);
- out.writeInt(ip.status);
- }
- }
-
- if (osuProviderList == null) {
- out.writeInt(0);
- } else {
- out.writeInt(osuProviderList.size());
- for (WifiPasspointOsuProvider osu : osuProviderList)
- osu.writeToParcel(out, flags);
- }
- }
-
- /** Implement the Parcelable interface {@hide} */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /** Implement the Parcelable interface {@hide} */
- public static final Parcelable.Creator<WifiPasspointInfo> CREATOR =
- new Parcelable.Creator<WifiPasspointInfo>() {
- @Override
- public WifiPasspointInfo createFromParcel(Parcel in) {
- WifiPasspointInfo p = new WifiPasspointInfo();
- int n;
-
- p.bssid = in.readString();
- p.venueName = in.readString();
-
- n = in.readInt();
- if (n > 0) {
- p.networkAuthTypeList = new ArrayList<NetworkAuthType>();
- for (int i = 0; i < n; i++) {
- NetworkAuthType auth = new NetworkAuthType();
- auth.type = in.readInt();
- auth.redirectUrl = in.readString();
- p.networkAuthTypeList.add(auth);
- }
- }
-
- n = in.readInt();
- if (n > 0) {
- p.roamingConsortiumList = new ArrayList<String>();
- for (int i = 0; i < n; i++)
- p.roamingConsortiumList.add(in.readString());
- }
-
- n = in.readInt();
- if (n != IpAddressType.NULL_VALUE) {
- p.ipAddrTypeAvailability = new IpAddressType();
- p.ipAddrTypeAvailability.availability = n;
- }
-
- n = in.readInt();
- if (n > 0) {
- p.naiRealmList = new ArrayList<NaiRealm>();
- for (int i = 0; i < n; i++) {
- NaiRealm realm = new NaiRealm();
- realm.encoding = in.readInt();
- realm.realm = in.readString();
- p.naiRealmList.add(realm);
- }
- }
-
- n = in.readInt();
- if (n > 0) {
- p.cellularNetworkList = new ArrayList<CellularNetwork>();
- for (int i = 0; i < n; i++) {
- CellularNetwork plmn = new CellularNetwork();
- plmn.mcc = in.readString();
- plmn.mnc = in.readString();
- p.cellularNetworkList.add(plmn);
- }
- }
-
- n = in.readInt();
- if (n > 0) {
- p.domainNameList = new ArrayList<String>();
- for (int i = 0; i < n; i++)
- p.domainNameList.add(in.readString());
- }
-
- p.operatorFriendlyName = in.readString();
-
- n = in.readInt();
- if (n > 0) {
- p.wanMetrics = new WanMetrics();
- p.wanMetrics.wanInfo = in.readInt();
- p.wanMetrics.downlinkSpeed = in.readLong();
- p.wanMetrics.uplinkSpeed = in.readLong();
- p.wanMetrics.downlinkLoad = in.readInt();
- p.wanMetrics.uplinkLoad = in.readInt();
- p.wanMetrics.lmd = in.readInt();
- }
-
- n = in.readInt();
- if (n > 0) {
- p.connectionCapabilityList = new ArrayList<IpProtoPort>();
- for (int i = 0; i < n; i++) {
- IpProtoPort ip = new IpProtoPort();
- ip.proto = in.readInt();
- ip.port = in.readInt();
- ip.status = in.readInt();
- p.connectionCapabilityList.add(ip);
- }
- }
-
- n = in.readInt();
- if (n > 0) {
- p.osuProviderList = new ArrayList<WifiPasspointOsuProvider>();
- for (int i = 0; i < n; i++) {
- WifiPasspointOsuProvider osu = WifiPasspointOsuProvider.CREATOR
- .createFromParcel(in);
- p.osuProviderList.add(osu);
- }
- }
-
- return p;
- }
-
- @Override
- public WifiPasspointInfo[] newArray(int size) {
- return new WifiPasspointInfo[size];
- }
- };
-}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
deleted file mode 100644
index 0245a3d..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
+++ /dev/null
@@ -1,567 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.content.Context;
-import android.net.wifi.ScanResult;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.internal.util.AsyncChannel;
-import com.android.internal.util.Protocol;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Provides APIs for managing Wifi Passpoint credentials.
- * @hide
- */
-public class WifiPasspointManager {
-
- private static final String TAG = "PasspointManager";
-
- private static final boolean DBG = true;
-
- /* Passpoint states values */
-
- /** Passpoint is in an unknown state. This should only occur in boot time */
- public static final int PASSPOINT_STATE_UNKNOWN = 0;
-
- /** Passpoint is disabled. This occurs when wifi is disabled */
- public static final int PASSPOINT_STATE_DISABLED = 1;
-
- /** Passpoint is enabled and in discovery state */
- public static final int PASSPOINT_STATE_DISCOVERY = 2;
-
- /** Passpoint is enabled and in access state */
- public static final int PASSPOINT_STATE_ACCESS = 3;
-
- /** Passpoint is enabled and in provisioning state */
- public static final int PASSPOINT_STATE_PROVISION = 4;
-
- /* Passpoint callback error codes */
-
- /** Indicates that the operation failed due to an internal error */
- public static final int REASON_ERROR = 0;
-
- /** Indicates that the operation failed because wifi is disabled */
- public static final int REASON_WIFI_DISABLED = 1;
-
- /** Indicates that the operation failed because the framework is busy */
- public static final int REASON_BUSY = 2;
-
- /** Indicates that the operation failed because parameter is invalid */
- public static final int REASON_INVALID_PARAMETER = 3;
-
- /** Indicates that the operation failed because the server is not trusted */
- public static final int REASON_NOT_TRUSTED = 4;
-
- /**
- * protocol supported for Passpoint
- */
- public static final String PROTOCOL_DM = "OMA-DM-ClientInitiated";
-
- /**
- * protocol supported for Passpoint
- */
- public static final String PROTOCOL_SOAP = "SPP-ClientInitiated";
-
- /* Passpoint broadcasts */
-
- /**
- * Broadcast intent action indicating that the state of Passpoint
- * connectivity has changed
- */
- public static final String PASSPOINT_STATE_CHANGED_ACTION =
- "android.net.wifi.passpoint.STATE_CHANGE";
-
- /**
- * Broadcast intent action indicating that the saved Passpoint credential
- * list has changed
- */
- public static final String PASSPOINT_CRED_CHANGED_ACTION =
- "android.net.wifi.passpoint.CRED_CHANGE";
-
- /**
- * Broadcast intent action indicating that Passpoint online sign up is
- * avaiable.
- */
- public static final String PASSPOINT_OSU_AVAILABLE_ACTION =
- "android.net.wifi.passpoint.OSU_AVAILABLE";
-
- /**
- * Broadcast intent action indicating that user remediation is required
- */
- public static final String PASSPOINT_USER_REM_REQ_ACTION =
- "android.net.wifi.passpoint.USER_REM_REQ";
-
- /**
- * Interface for callback invocation when framework channel is lost
- */
- public interface ChannelListener {
- /**
- * The channel to the framework has been disconnected. Application could
- * try re-initializing using {@link #initialize}
- */
- public void onChannelDisconnected();
- }
-
- /**
- * Interface for callback invocation on an application action
- */
- public interface ActionListener {
- /** The operation succeeded */
- public void onSuccess();
-
- /**
- * The operation failed
- *
- * @param reason The reason for failure could be one of
- * {@link #WIFI_DISABLED}, {@link #ERROR} or {@link #BUSY}
- */
- public void onFailure(int reason);
- }
-
- /**
- * Interface for callback invocation when doing OSU or user remediation
- */
- public interface OsuRemListener {
- /** The operation succeeded */
- public void onSuccess();
-
- /**
- * The operation failed
- *
- * @param reason The reason for failure could be one of
- * {@link #WIFI_DISABLED}, {@link #ERROR} or {@link #BUSY}
- */
- public void onFailure(int reason);
-
- /**
- * Browser launch is requried for user interaction. When this callback
- * is called, app should launch browser / webview to the given URI.
- *
- * @param uri URI for browser launch
- */
- public void onBrowserLaunch(String uri);
-
- /**
- * When this is called, app should dismiss the previously lanched browser.
- */
- public void onBrowserDismiss();
- }
-
- /**
- * A channel that connects the application to the wifi passpoint framework.
- * Most passpoint operations require a Channel as an argument.
- * An instance of Channel is obtained by doing a call on {@link #initialize}
- */
- public static class Channel {
- private final static int INVALID_LISTENER_KEY = 0;
-
- private ChannelListener mChannelListener;
-
- private HashMap<Integer, Object> mListenerMap = new HashMap<Integer, Object>();
- private HashMap<Integer, Integer> mListenerMapCount = new HashMap<Integer, Integer>();
- private Object mListenerMapLock = new Object();
- private int mListenerKey = 0;
-
- private List<ScanResult> mAnqpRequest = new LinkedList<ScanResult>();
- private Object mAnqpRequestLock = new Object();
-
- private AsyncChannel mAsyncChannel;
- private PasspointHandler mHandler;
- Context mContext;
-
- Channel(Context context, Looper looper, ChannelListener l) {
- mAsyncChannel = new AsyncChannel();
- mHandler = new PasspointHandler(looper);
- mChannelListener = l;
- mContext = context;
- }
-
- private int putListener(Object listener) {
- return putListener(listener, 1);
- }
-
- private int putListener(Object listener, int count) {
- if (listener == null || count <= 0)
- return INVALID_LISTENER_KEY;
- int key;
- synchronized (mListenerMapLock) {
- do {
- key = mListenerKey++;
- } while (key == INVALID_LISTENER_KEY);
- mListenerMap.put(key, listener);
- mListenerMapCount.put(key, count);
- }
- return key;
- }
-
- private Object peekListener(int key) {
- Log.d(TAG, "peekListener() key=" + key);
- if (key == INVALID_LISTENER_KEY)
- return null;
- synchronized (mListenerMapLock) {
- return mListenerMap.get(key);
- }
- }
-
-
- private Object getListener(int key, boolean forceRemove) {
- Log.d(TAG, "getListener() key=" + key + " force=" + forceRemove);
- if (key == INVALID_LISTENER_KEY)
- return null;
- synchronized (mListenerMapLock) {
- if (!forceRemove) {
- int count = mListenerMapCount.get(key);
- Log.d(TAG, "count=" + count);
- mListenerMapCount.put(key, --count);
- if (count > 0)
- return null;
- }
- Log.d(TAG, "remove key");
- mListenerMapCount.remove(key);
- return mListenerMap.remove(key);
- }
- }
-
- private void anqpRequestStart(ScanResult sr) {
- Log.d(TAG, "anqpRequestStart sr.bssid=" + sr.BSSID);
- synchronized (mAnqpRequestLock) {
- mAnqpRequest.add(sr);
- }
- }
-
- private void anqpRequestFinish(WifiPasspointInfo result) {
- Log.d(TAG, "anqpRequestFinish pi.bssid=" + result.bssid);
- synchronized (mAnqpRequestLock) {
- for (ScanResult sr : mAnqpRequest)
- if (sr.BSSID.equals(result.bssid)) {
- Log.d(TAG, "find hit " + result.bssid);
- /* sr.passpoint = result; */
- mAnqpRequest.remove(sr);
- Log.d(TAG, "mAnqpRequest.len=" + mAnqpRequest.size());
- break;
- }
- }
- }
-
- private void anqpRequestFinish(ScanResult sr) {
- Log.d(TAG, "anqpRequestFinish sr.bssid=" + sr.BSSID);
- synchronized (mAnqpRequestLock) {
- for (ScanResult sr1 : mAnqpRequest)
- if (sr1.BSSID.equals(sr.BSSID)) {
- mAnqpRequest.remove(sr1);
- break;
- }
- }
- }
-
- class PasspointHandler extends Handler {
- PasspointHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message message) {
- Object listener = null;
-
- switch (message.what) {
- case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
- if (mChannelListener != null) {
- mChannelListener.onChannelDisconnected();
- mChannelListener = null;
- }
- break;
-
- case REQUEST_ANQP_INFO_SUCCEEDED:
- WifiPasspointInfo result = (WifiPasspointInfo) message.obj;
- anqpRequestFinish(result);
- listener = getListener(message.arg2, false);
- if (listener != null) {
- ((ActionListener) listener).onSuccess();
- }
- break;
-
- case REQUEST_ANQP_INFO_FAILED:
- anqpRequestFinish((ScanResult) message.obj);
- listener = getListener(message.arg2, false);
- if (listener == null)
- getListener(message.arg2, true);
- if (listener != null) {
- ((ActionListener) listener).onFailure(message.arg1);
- }
- break;
-
- case START_OSU_SUCCEEDED:
- listener = getListener(message.arg2, true);
- if (listener != null) {
- ((OsuRemListener) listener).onSuccess();
- }
- break;
-
- case START_OSU_FAILED:
- listener = getListener(message.arg2, true);
- if (listener != null) {
- ((OsuRemListener) listener).onFailure(message.arg1);
- }
- break;
-
- case START_OSU_BROWSER:
- listener = peekListener(message.arg2);
- if (listener != null) {
- ParcelableString str = (ParcelableString) message.obj;
- if (str == null || str.string == null)
- ((OsuRemListener) listener).onBrowserDismiss();
- else
- ((OsuRemListener) listener).onBrowserLaunch(str.string);
- }
- break;
-
- default:
- Log.d(TAG, "Ignored " + message);
- break;
- }
- }
- }
-
- }
-
- public static class ParcelableString implements Parcelable {
- public String string;
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(string);
- }
-
- public static final Parcelable.Creator<ParcelableString> CREATOR =
- new Parcelable.Creator<ParcelableString>() {
- @Override
- public ParcelableString createFromParcel(Parcel in) {
- ParcelableString ret = new ParcelableString();
- ret.string = in.readString();
- return ret;
- }
- @Override
- public ParcelableString[] newArray(int size) {
- return new ParcelableString[size];
- }
- };
- }
-
- private static final int BASE = Protocol.BASE_WIFI_PASSPOINT_MANAGER;
-
- public static final int REQUEST_ANQP_INFO = BASE + 1;
- public static final int REQUEST_ANQP_INFO_FAILED = BASE + 2;
- public static final int REQUEST_ANQP_INFO_SUCCEEDED = BASE + 3;
- public static final int REQUEST_OSU_ICON = BASE + 4;
- public static final int REQUEST_OSU_ICON_FAILED = BASE + 5;
- public static final int REQUEST_OSU_ICON_SUCCEEDED = BASE + 6;
- public static final int START_OSU = BASE + 7;
- public static final int START_OSU_BROWSER = BASE + 8;
- public static final int START_OSU_FAILED = BASE + 9;
- public static final int START_OSU_SUCCEEDED = BASE + 10;
-
- private Context mContext;
- IWifiPasspointManager mService;
-
- /**
- * TODO: doc
- * @param context
- * @param service
- */
- public WifiPasspointManager(Context context, IWifiPasspointManager service) {
- mContext = context;
- mService = service;
- }
-
- /**
- * Registers the application with the framework. This function must be the
- * first to be called before any async passpoint operations are performed.
- *
- * @param srcContext is the context of the source
- * @param srcLooper is the Looper on which the callbacks are receivied
- * @param listener for callback at loss of framework communication. Can be
- * null.
- * @return Channel instance that is necessary for performing any further
- * passpoint operations
- *
- */
- public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
- Messenger messenger = getMessenger();
- if (messenger == null)
- return null;
-
- Channel c = new Channel(srcContext, srcLooper, listener);
- if (c.mAsyncChannel.connectSync(srcContext, c.mHandler, messenger)
- == AsyncChannel.STATUS_SUCCESSFUL) {
- return c;
- } else {
- return null;
- }
- }
-
- /**
- * STOPSHIP: temp solution, should use supplicant manager instead, check
- * with b/13931972
- */
- public Messenger getMessenger() {
- try {
- return mService.getMessenger();
- } catch (RemoteException e) {
- return null;
- }
- }
-
- public int getPasspointState() {
- try {
- return mService.getPasspointState();
- } catch (RemoteException e) {
- return PASSPOINT_STATE_UNKNOWN;
- }
- }
-
- public void requestAnqpInfo(Channel c, List<ScanResult> requested, int mask,
- ActionListener listener) {
- Log.d(TAG, "requestAnqpInfo start");
- Log.d(TAG, "requested.size=" + requested.size());
- checkChannel(c);
- List<ScanResult> list = new ArrayList<ScanResult>();
- for (ScanResult sr : requested)
- if (sr.capabilities.contains("[HS20]")) {
- list.add(sr);
- c.anqpRequestStart(sr);
- Log.d(TAG, "adding " + sr.BSSID);
- }
- int count = list.size();
- Log.d(TAG, "after filter, count=" + count);
- if (count == 0) {
- if (DBG)
- Log.d(TAG, "ANQP info request contains no HS20 APs, skipped");
- listener.onSuccess();
- return;
- }
- int key = c.putListener(listener, count);
- for (ScanResult sr : list)
- c.mAsyncChannel.sendMessage(REQUEST_ANQP_INFO, mask, key, sr);
- Log.d(TAG, "requestAnqpInfo end");
- }
-
- public void requestOsuIcons(Channel c, List<WifiPasspointOsuProvider> requested,
- int resolution, ActionListener listener) {
- }
-
- public List<WifiPasspointPolicy> requestCredentialMatch(List<ScanResult> requested) {
- try {
- return mService.requestCredentialMatch(requested);
- } catch (RemoteException e) {
- return null;
- }
- }
-
- /**
- * Get a list of saved Passpoint credentials. Only those credentials owned
- * by the caller will be returned.
- *
- * @return The list of credentials
- */
- public List<WifiPasspointCredential> getCredentials() {
- try {
- return mService.getCredentials();
- } catch (RemoteException e) {
- return null;
- }
- }
-
- /**
- * Add a new Passpoint credential.
- *
- * @param cred The credential to be added
- * @return {@code true} if the operation succeeds, {@code false} otherwise
- */
- public boolean addCredential(WifiPasspointCredential cred) {
- try {
- return mService.addCredential(cred);
- } catch (RemoteException e) {
- return false;
- }
- }
-
- /**
- * Update an existing Passpoint credential. Only system or the owner of this
- * credential has the permission to do this.
- *
- * @param cred The credential to be updated
- * @return {@code true} if the operation succeeds, {@code false} otherwise
- */
- public boolean updateCredential(WifiPasspointCredential cred) {
- try {
- return mService.updateCredential(cred);
- } catch (RemoteException e) {
- return false;
- }
- }
-
- /**
- * Remove an existing Passpoint credential. Only system or the owner of this
- * credential has the permission to do this.
- *
- * @param cred The credential to be removed
- * @return {@code true} if the operation succeeds, {@code false} otherwise
- */
- public boolean removeCredential(WifiPasspointCredential cred) {
- try {
- return mService.removeCredential(cred);
- } catch (RemoteException e) {
- return false;
- }
- }
-
- public void startOsu(Channel c, WifiPasspointOsuProvider osu, OsuRemListener listener) {
- Log.d(TAG, "startOsu start");
- checkChannel(c);
- int key = c.putListener(listener);
- c.mAsyncChannel.sendMessage(START_OSU, 0, key, osu);
- Log.d(TAG, "startOsu end");
- }
-
- public void startRemediation(Channel c, OsuRemListener listener) {
- }
-
- public void connect(WifiPasspointPolicy policy) {
- }
-
- private static void checkChannel(Channel c) {
- if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
- }
-}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.aidl
deleted file mode 100644
index 088136f..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-parcelable WifiPasspointOsuProvider;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java
deleted file mode 100644
index b54b70c..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/** @hide */
-public class WifiPasspointOsuProvider implements Parcelable {
-
- /** TODO: doc
- * @hide
- */
- public static final int OSU_METHOD_UNKNOWN = -1;
-
- /** TODO: doc
- * @hide
- */
- public static final int OSU_METHOD_OMADM = 0;
-
- /** TODO: doc
- * @hide
- */
- public static final int OSU_METHOD_SOAP = 1;
-
- /** TODO: doc */
- public String ssid;
-
- /** TODO: doc */
- public String friendlyName;
-
- /** TODO: doc
- * @hide
- */
- public String serverUri;
-
- /** TODO: doc
- * @hide
- */
- public int osuMethod = OSU_METHOD_UNKNOWN;
-
- /** TODO: doc */
- public int iconWidth;
-
- /** TODO: doc */
- public int iconHeight;
-
- /** TODO: doc */
- public String iconType;
-
- /** TODO: doc */
- public String iconFileName;
-
- /** TODO: doc */
- public Object icon; // TODO: should change to image format
-
- /** TODO: doc */
- public String osuNai;
-
- /** TODO: doc */
- public String osuService;
-
- /** default constructor @hide */
- public WifiPasspointOsuProvider() {
- // TODO
- }
-
- /** copy constructor @hide */
- public WifiPasspointOsuProvider(WifiPasspointOsuProvider source) {
- // TODO
- }
-
- @Override
- public String toString() {
- StringBuffer sb = new StringBuffer();
- sb.append("SSID: ").append("<").append(ssid).append(">");
- if (friendlyName != null)
- sb.append(" friendlyName: ").append("<").append(friendlyName).append(">");
- if (serverUri != null)
- sb.append(" serverUri: ").append("<").append(serverUri).append(">");
- sb.append(" osuMethod: ").append("<").append(osuMethod).append(">");
- if (iconFileName != null) {
- sb.append(" icon: <").append(iconWidth).append("x")
- .append(iconHeight).append(" ")
- .append(iconType).append(" ")
- .append(iconFileName).append(">");
- }
- if (osuNai != null)
- sb.append(" osuNai: ").append("<").append(osuNai).append(">");
- if (osuService != null)
- sb.append(" osuService: ").append("<").append(osuService).append(">");
- return sb.toString();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(ssid);
- out.writeString(friendlyName);
- out.writeString(serverUri);
- out.writeInt(osuMethod);
- out.writeInt(iconWidth);
- out.writeInt(iconHeight);
- out.writeString(iconType);
- out.writeString(iconFileName);
- out.writeString(osuNai);
- out.writeString(osuService);
- // TODO: icon image?
- }
-
- public static final Parcelable.Creator<WifiPasspointOsuProvider> CREATOR =
- new Parcelable.Creator<WifiPasspointOsuProvider>() {
- @Override
- public WifiPasspointOsuProvider createFromParcel(Parcel in) {
- WifiPasspointOsuProvider osu = new WifiPasspointOsuProvider();
- osu.ssid = in.readString();
- osu.friendlyName = in.readString();
- osu.serverUri = in.readString();
- osu.osuMethod = in.readInt();
- osu.iconWidth = in.readInt();
- osu.iconHeight = in.readInt();
- osu.iconType = in.readString();
- osu.iconFileName = in.readString();
- osu.osuNai = in.readString();
- osu.osuService = in.readString();
- return osu;
- }
-
- @Override
- public WifiPasspointOsuProvider[] newArray(int size) {
- return new WifiPasspointOsuProvider[size];
- }
- };
-}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.aidl
deleted file mode 100644
index 1d61da0..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-parcelable WifiPasspointPolicy;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java
deleted file mode 100644
index c08877e..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.net.wifi.WifiConfiguration;
-import android.os.Parcelable;
-import android.os.Parcel;
-import android.security.Credentials;
-import android.util.Log;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-
-
-/** @hide */
-public class WifiPasspointPolicy implements Parcelable {
-
- private final static String TAG = "PasspointPolicy";
-
- /** @hide */
- public static final int HOME_SP = 0;
-
- /** @hide */
- public static final int ROAMING_PARTNER = 1;
-
- /** @hide */
- public static final int UNRESTRICTED = 2;
-
- private String mName;
- private int mCredentialPriority;
- private int mRoamingPriority;
- private String mBssid;
- private String mSsid;
- private WifiPasspointCredential mCredential;
- private int mRestriction;// Permitted values are "HomeSP", "RoamingPartner", or "Unrestricted"
- private boolean mIsHomeSp;
-
- private final String INT_PRIVATE_KEY = "private_key";
- private final String INT_PHASE2 = "phase2";
- private final String INT_PASSWORD = "password";
- private final String INT_IDENTITY = "identity";
- private final String INT_EAP = "eap";
- private final String INT_CLIENT_CERT = "client_cert";
- private final String INT_CA_CERT = "ca_cert";
- private final String INT_ANONYMOUS_IDENTITY = "anonymous_identity";
- private final String INT_SIM_SLOT = "sim_slot";
- private final String INT_ENTERPRISEFIELD_NAME ="android.net.wifi.WifiConfiguration$EnterpriseField";
- private final String ISO8601DATEFORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
- private final String ENTERPRISE_PHASE2_MSCHAPV2 = "auth=MSCHAPV2";
- private final String ENTERPRISE_PHASE2_MSCHAP = "auth=MSCHAP";
-
- /** @hide */
- public WifiPasspointPolicy(String name, String ssid,
- String bssid, WifiPasspointCredential pc,
- int restriction, boolean ishomesp) {
- mName = name;
- if (pc != null) {
- mCredentialPriority = pc.getPriority();
- }
- //PerProviderSubscription/<X+>/Policy/PreferredRoamingPartnerList/<X+>/Priority
- mRoamingPriority = 128; //default priority value of 128
- mSsid = ssid;
- mCredential = pc;
- mBssid = bssid;
- mRestriction = restriction;
- mIsHomeSp = ishomesp;
- }
-
- public String getSsid() {
- return mSsid;
- }
-
- /** @hide */
- public void setBssid(String bssid) {
- mBssid = bssid;
- }
-
- public String getBssid() {
- return mBssid;
- }
-
- /** @hide */
- public void setRestriction(int r) {
- mRestriction = r;
- }
-
- /** @hide */
- public int getRestriction() {
- return mRestriction;
- }
-
- /** @hide */
- public void setHomeSp(boolean b) {
- mIsHomeSp = b;
- }
-
- /** @hide */
- public boolean isHomeSp() {
- return mIsHomeSp;
- }
-
- /** @hide */
- public void setCredential(WifiPasspointCredential newCredential) {
- mCredential = newCredential;
- }
-
- public WifiPasspointCredential getCredential() {
- // TODO: return a copy
- return mCredential;
- }
-
- /** @hide */
- public void setCredentialPriority(int priority) {
- mCredentialPriority = priority;
- }
-
- /** @hide */
- public void setRoamingPriority(int priority) {
- mRoamingPriority = priority;
- }
-
- public int getCredentialPriority() {
- return mCredentialPriority;
- }
-
- public int getRoamingPriority() {
- return mRoamingPriority;
- }
-
- public WifiConfiguration createWifiConfiguration() {
- WifiConfiguration wfg = new WifiConfiguration();
- if (mBssid != null) {
- Log.d(TAG, "create bssid:" + mBssid);
- wfg.BSSID = mBssid;
- }
-
- if (mSsid != null) {
- Log.d(TAG, "create ssid:" + mSsid);
- wfg.SSID = mSsid;
- }
- //TODO: 1. add pmf configuration
- // 2. add ocsp configuration
- // 3. add eap-sim configuration
- /*Key management*/
- wfg.status = WifiConfiguration.Status.ENABLED;
- wfg.allowedKeyManagement.clear();
- wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
- wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
-
- /*Group Ciphers*/
- wfg.allowedGroupCiphers.clear();
- wfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
- wfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
-
- /*Protocols*/
- wfg.allowedProtocols.clear();
- wfg.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
- wfg.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
-
- Class[] enterpriseFieldArray = WifiConfiguration.class.getClasses();
- Class<?> enterpriseFieldClass = null;
-
-
- for(Class<?> myClass : enterpriseFieldArray) {
- if(myClass.getName().equals(INT_ENTERPRISEFIELD_NAME)) {
- enterpriseFieldClass = myClass;
- break;
- }
- }
- Log.d(TAG, "class chosen " + enterpriseFieldClass.getName() );
-
-
- Field anonymousId = null, caCert = null, clientCert = null,
- eap = null, identity = null, password = null,
- phase2 = null, privateKey = null;
-
- Field[] fields = WifiConfiguration.class.getFields();
-
-
- for (Field tempField : fields) {
- if (tempField.getName().trim().equals(INT_ANONYMOUS_IDENTITY)) {
- anonymousId = tempField;
- Log.d(TAG, "field " + anonymousId.getName() );
- } else if (tempField.getName().trim().equals(INT_CA_CERT)) {
- caCert = tempField;
- } else if (tempField.getName().trim().equals(INT_CLIENT_CERT)) {
- clientCert = tempField;
- Log.d(TAG, "field " + clientCert.getName() );
- } else if (tempField.getName().trim().equals(INT_EAP)) {
- eap = tempField;
- Log.d(TAG, "field " + eap.getName() );
- } else if (tempField.getName().trim().equals(INT_IDENTITY)) {
- identity = tempField;
- Log.d(TAG, "field " + identity.getName() );
- } else if (tempField.getName().trim().equals(INT_PASSWORD)) {
- password = tempField;
- Log.d(TAG, "field " + password.getName() );
- } else if (tempField.getName().trim().equals(INT_PHASE2)) {
- phase2 = tempField;
- Log.d(TAG, "field " + phase2.getName() );
-
- } else if (tempField.getName().trim().equals(INT_PRIVATE_KEY)) {
- privateKey = tempField;
- }
- }
-
-
- Method setValue = null;
-
- for(Method m: enterpriseFieldClass.getMethods()) {
- if(m.getName().trim().equals("setValue")) {
- Log.d(TAG, "method " + m.getName() );
- setValue = m;
- break;
- }
- }
-
- try {
- // EAP
- String eapmethod = mCredential.getType();
- Log.d(TAG, "eapmethod:" + eapmethod);
- setValue.invoke(eap.get(wfg), eapmethod);
-
- // Username, password, EAP Phase 2
- if ("TTLS".equals(eapmethod)) {
- setValue.invoke(phase2.get(wfg), ENTERPRISE_PHASE2_MSCHAPV2);
- setValue.invoke(identity.get(wfg), mCredential.getUserName());
- setValue.invoke(password.get(wfg), mCredential.getPassword());
- setValue.invoke(anonymousId.get(wfg), "anonymous@" + mCredential.getRealm());
- }
-
- // EAP CA Certificate
- String cacertificate = null;
- String rootCA = mCredential.getCaRootCertPath();
- if (rootCA == null){
- cacertificate = null;
- } else {
- cacertificate = "keystore://" + Credentials.WIFI + "HS20" + Credentials.CA_CERTIFICATE + rootCA;
- }
- Log.d(TAG, "cacertificate:" + cacertificate);
- setValue.invoke(caCert.get(wfg), cacertificate);
-
- //User certificate
- if ("TLS".equals(eapmethod)) {
- String usercertificate = null;
- String privatekey = null;
- String clientCertPath = mCredential.getClientCertPath();
- if (clientCertPath != null){
- privatekey = "keystore://" + Credentials.WIFI + "HS20" + Credentials.USER_PRIVATE_KEY + clientCertPath;
- usercertificate = "keystore://" + Credentials.WIFI + "HS20" + Credentials.USER_CERTIFICATE + clientCertPath;
- }
- Log.d(TAG, "privatekey:" + privatekey);
- Log.d(TAG, "usercertificate:" + usercertificate);
- if (privatekey != null && usercertificate != null) {
- setValue.invoke(privateKey.get(wfg), privatekey);
- setValue.invoke(clientCert.get(wfg), usercertificate);
- }
- }
- } catch (Exception e) {
- Log.d(TAG, "createWifiConfiguration err:" + e);
- }
-
- return wfg;
- }
-
- /** {@inheritDoc} @hide */
- public int compareTo(WifiPasspointPolicy another) {
- Log.d(TAG, "this:" + this);
- Log.d(TAG, "another:" + another);
-
- if (another == null) {
- return -1;
- } else if (this.mIsHomeSp == true && another.isHomeSp() == false) {
- //home sp priority is higher then roaming
- Log.d(TAG, "compare HomeSP first, this is HomeSP, another isn't");
- return -1;
- } else if ((this.mIsHomeSp == true && another.isHomeSp() == true)) {
- Log.d(TAG, "both HomeSP");
- //if both home sp, compare credential priority
- if (this.mCredentialPriority < another.getCredentialPriority()) {
- Log.d(TAG, "this priority is higher");
- return -1;
- } else if (this.mCredentialPriority == another.getCredentialPriority()) {
- Log.d(TAG, "both priorities equal");
- //if priority still the same, compare name(ssid)
- if (this.mName.compareTo(another.mName) != 0) {
- Log.d(TAG, "compare mName return:" + this.mName.compareTo(another.mName));
- return this.mName.compareTo(another.mName);
- }
- /**
- *if name still the same, compare credential
- *the device may has two more credentials(TLS,SIM..etc)
- *it can associate to one AP(same ssid). so we should compare by credential
- */
- if (this.mCredential != null && another.mCredential != null) {
- if (this.mCredential.compareTo(another.mCredential) != 0) {
- Log.d(TAG,
- "compare mCredential return:" + this.mName.compareTo(another.mName));
- return this.mCredential.compareTo(another.mCredential);
- }
- }
- } else {
- return 1;
- }
- } else if ((this.mIsHomeSp == false && another.isHomeSp() == false)) {
- Log.d(TAG, "both RoamingSp");
- //if both roaming sp, compare roaming priority(preferredRoamingPartnerList/<X+>/priority)
- if (this.mRoamingPriority < another.getRoamingPriority()) {
- Log.d(TAG, "this priority is higher");
- return -1;
- } else if (this.mRoamingPriority == another.getRoamingPriority()) {//priority equals, compare name
- Log.d(TAG, "both priorities equal");
- //if priority still the same, compare name(ssid)
- if (this.mName.compareTo(another.mName) != 0) {
- Log.d(TAG, "compare mName return:" + this.mName.compareTo(another.mName));
- return this.mName.compareTo(another.mName);
- }
- //if name still the same, compare credential
- if (this.mCredential != null && another.mCredential != null) {
- if (this.mCredential.compareTo(another.mCredential) != 0) {
- Log.d(TAG,
- "compare mCredential return:"
- + this.mCredential.compareTo(another.mCredential));
- return this.mCredential.compareTo(another.mCredential);
- }
- }
- } else {
- return 1;
- }
- }
-
- Log.d(TAG, "both policies equal");
- return 0;
- }
-
- @Override
- /** @hide */
- public String toString() {
- return "PasspointPolicy: name=" + mName + " CredentialPriority=" + mCredentialPriority +
- " mRoamingPriority" + mRoamingPriority +
- " ssid=" + mSsid + " restriction=" + mRestriction +
- " ishomesp=" + mIsHomeSp + " Credential=" + mCredential;
- }
-
- /** Implement the Parcelable interface {@hide} */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /** Implement the Parcelable interface {@hide} */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- // TODO
- }
-
- /** Implement the Parcelable interface {@hide} */
- public static final Creator<WifiPasspointPolicy> CREATOR =
- new Creator<WifiPasspointPolicy>() {
- @Override
- public WifiPasspointPolicy createFromParcel(Parcel in) {
- return null;
- }
-
- @Override
- public WifiPasspointPolicy[] newArray(int size) {
- return new WifiPasspointPolicy[size];
- }
- };
-}