diff options
36 files changed, 641 insertions, 136 deletions
diff --git a/api/current.txt b/api/current.txt index 7584ba8363a5..24ab58642433 100644 --- a/api/current.txt +++ b/api/current.txt @@ -47199,6 +47199,7 @@ package android.view.accessibility { method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int); method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList(); method public void interrupt(); + method public static boolean isAccessibilityButtonSupported(); method public boolean isEnabled(); method public boolean isTouchExplorationEnabled(); method public void removeAccessibilityRequestPreparer(android.view.accessibility.AccessibilityRequestPreparer); diff --git a/api/test-current.txt b/api/test-current.txt index 1258554e7fdd..343228a87848 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -47651,6 +47651,7 @@ package android.view.accessibility { method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int); method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList(); method public void interrupt(); + method public static boolean isAccessibilityButtonSupported(); method public boolean isEnabled(); method public boolean isTouchExplorationEnabled(); method public void removeAccessibilityRequestPreparer(android.view.accessibility.AccessibilityRequestPreparer); diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java index dfd5996c6a00..44c2667f2d85 100644 --- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java +++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java @@ -415,7 +415,8 @@ public final class BluetoothLeAdvertiser { gatt = mBluetoothManager.getBluetoothGatt(); } catch (RemoteException e) { Log.e(TAG, "Failed to get Bluetooth gatt - ", e); - throw new IllegalStateException("Failed to get Bluetooth"); + postStartSetFailure(handler, callback, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR); + return; } IAdvertisingSetCallback wrapped = wrap(callback, handler); @@ -429,7 +430,8 @@ public final class BluetoothLeAdvertiser { periodicData, duration, maxExtendedAdvertisingEvents, wrapped); } catch (RemoteException e) { Log.e(TAG, "Failed to start advertising set - ", e); - throw new IllegalStateException("Failed to start advertising set"); + postStartSetFailure(handler, callback, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR); + return; } } @@ -453,8 +455,7 @@ public final class BluetoothLeAdvertiser { gatt.stopAdvertisingSet(wrapped); } catch (RemoteException e) { Log.e(TAG, "Failed to stop advertising - ", e); - throw new IllegalStateException("Failed to stop advertising"); - } + } } /** @@ -648,6 +649,16 @@ public final class BluetoothLeAdvertiser { }; } + private void postStartSetFailure(Handler handler, final AdvertisingSetCallback callback, + final int error) { + handler.post(new Runnable() { + @Override + public void run() { + callback.onAdvertisingSetStarted(null, 0, error); + } + }); + } + private void postStartFailure(final AdvertiseCallback callback, final int error) { mHandler.post(new Runnable() { @Override diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java index 6b4f2d5acd00..6e2654e3ce7c 100644 --- a/core/java/android/net/IpPrefix.java +++ b/core/java/android/net/IpPrefix.java @@ -20,6 +20,8 @@ import android.os.Parcel; import android.os.Parcelable; import android.util.Pair; +import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; @@ -185,6 +187,20 @@ public final class IpPrefix implements Parcelable { } /** + * @hide + */ + public boolean isIPv6() { + return getAddress() instanceof Inet6Address; + } + + /** + * @hide + */ + public boolean isIPv4() { + return getAddress() instanceof Inet4Address; + } + + /** * Returns a string representation of this {@code IpPrefix}. * * @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::/64"}. diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index 62de9911bc48..bcfe93882375 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -76,7 +76,7 @@ public class LinkAddress implements Parcelable { * RFC 6724 section 3.2. * @hide */ - static int scopeForUnicastAddress(InetAddress addr) { + private static int scopeForUnicastAddress(InetAddress addr) { if (addr.isAnyLocalAddress()) { return RT_SCOPE_HOST; } @@ -101,7 +101,7 @@ public class LinkAddress implements Parcelable { * Per RFC 4193 section 8, fc00::/7 identifies these addresses. */ private boolean isIPv6ULA() { - if (address instanceof Inet6Address) { + if (isIPv6()) { byte[] bytes = address.getAddress(); return ((bytes[0] & (byte)0xfe) == (byte)0xfc); } @@ -109,13 +109,29 @@ public class LinkAddress implements Parcelable { } /** + * @return true if the address is IPv6. + * @hide + */ + public boolean isIPv6() { + return address instanceof Inet6Address; + } + + /** + * @return true if the address is IPv4 or is a mapped IPv4 address. + * @hide + */ + public boolean isIPv4() { + return address instanceof Inet4Address; + } + + /** * Utility function for the constructors. */ private void init(InetAddress address, int prefixLength, int flags, int scope) { if (address == null || address.isMulticastAddress() || prefixLength < 0 || - ((address instanceof Inet4Address) && prefixLength > 32) || + (address instanceof Inet4Address && prefixLength > 32) || (prefixLength > 128)) { throw new IllegalArgumentException("Bad LinkAddress params " + address + "/" + prefixLength); @@ -184,6 +200,7 @@ public class LinkAddress implements Parcelable { */ public LinkAddress(String address, int flags, int scope) { // This may throw an IllegalArgumentException; catching it is the caller's responsibility. + // TODO: consider rejecting mapped IPv4 addresses such as "::ffff:192.0.2.5/24". Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(address); init(ipAndMask.first, ipAndMask.second, flags, scope); } diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java index ca3985449d92..50cd7b18e254 100644 --- a/core/java/android/util/Patterns.java +++ b/core/java/android/util/Patterns.java @@ -406,7 +406,7 @@ public class Patterns { * the local part to be at most 64 octets. */ private static final String EMAIL_ADDRESS_LOCAL_PART = - "[" + EMAIL_CHAR + "]" + "(?:[" + EMAIL_CHAR + "\\.]{1,62}[" + EMAIL_CHAR + "])?"; + "[" + EMAIL_CHAR + "]" + "(?:[" + EMAIL_CHAR + "\\.]{0,62}[" + EMAIL_CHAR + "])?"; /** * Regular expression for the domain part of an email address. RFC5321 section 4.5.3.1.2 limits diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index d9128d8014bb..0b9bc5760fa8 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -23,7 +23,6 @@ import android.accessibilityservice.AccessibilityServiceInfo; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; -import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.ComponentName; import android.content.Context; @@ -1113,9 +1112,7 @@ public final class AccessibilityManager { * * @return {@code true} if the accessibility button is supported on this device, * {@code false} otherwise - * @hide */ - @SystemApi public static boolean isAccessibilityButtonSupported() { final Resources res = Resources.getSystem(); return res.getBoolean(com.android.internal.R.bool.config_showNavigationBar); diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java index d327180c6e9d..d64c9a1d813b 100644 --- a/core/java/com/android/internal/notification/SystemNotificationChannels.java +++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java @@ -132,10 +132,12 @@ public class SystemNotificationChannels { context.getString(R.string.notification_channel_usb), NotificationManager.IMPORTANCE_MIN)); - channelsList.add(new NotificationChannel( + NotificationChannel foregroundChannel = new NotificationChannel( FOREGROUND_SERVICE, context.getString(R.string.notification_channel_foreground_service), - NotificationManager.IMPORTANCE_LOW)); + NotificationManager.IMPORTANCE_LOW); + foregroundChannel.setBlockableSystem(true); + channelsList.add(foregroundChannel); nm.createNotificationChannels(channelsList); } diff --git a/core/res/res/values-mcc310-mnc030/strings.xml b/core/res/res/values-mcc310-mnc030/strings.xml new file mode 100644 index 000000000000..a3fea29070f5 --- /dev/null +++ b/core/res/res/values-mcc310-mnc030/strings.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* //device/apps/common/assets/res/any/strings.xml +** +** Copyright 2006, 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. +*/ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string> + <string name="mmcc_illegal_ms">SIM not allowed MM#3</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc170 b/core/res/res/values-mcc310-mnc170 deleted file mode 120000 index cfced1756742..000000000000 --- a/core/res/res/values-mcc310-mnc170 +++ /dev/null @@ -1 +0,0 @@ -./values-mcc310-mnc150
\ No newline at end of file diff --git a/core/res/res/values-mcc310-mnc170/strings.xml b/core/res/res/values-mcc310-mnc170/strings.xml new file mode 100644 index 000000000000..a3fea29070f5 --- /dev/null +++ b/core/res/res/values-mcc310-mnc170/strings.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* //device/apps/common/assets/res/any/strings.xml +** +** Copyright 2006, 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. +*/ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string> + <string name="mmcc_illegal_ms">SIM not allowed MM#3</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc280/strings.xml b/core/res/res/values-mcc310-mnc280/strings.xml new file mode 100644 index 000000000000..a3fea29070f5 --- /dev/null +++ b/core/res/res/values-mcc310-mnc280/strings.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* //device/apps/common/assets/res/any/strings.xml +** +** Copyright 2006, 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. +*/ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string> + <string name="mmcc_illegal_ms">SIM not allowed MM#3</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc380 b/core/res/res/values-mcc310-mnc380 deleted file mode 120000 index cfced1756742..000000000000 --- a/core/res/res/values-mcc310-mnc380 +++ /dev/null @@ -1 +0,0 @@ -./values-mcc310-mnc150
\ No newline at end of file diff --git a/core/res/res/values-mcc310-mnc380/strings.xml b/core/res/res/values-mcc310-mnc380/strings.xml new file mode 100644 index 000000000000..a3fea29070f5 --- /dev/null +++ b/core/res/res/values-mcc310-mnc380/strings.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* //device/apps/common/assets/res/any/strings.xml +** +** Copyright 2006, 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. +*/ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string> + <string name="mmcc_illegal_ms">SIM not allowed MM#3</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc410/strings.xml b/core/res/res/values-mcc310-mnc410/strings.xml new file mode 100644 index 000000000000..a3fea29070f5 --- /dev/null +++ b/core/res/res/values-mcc310-mnc410/strings.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* //device/apps/common/assets/res/any/strings.xml +** +** Copyright 2006, 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. +*/ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string> + <string name="mmcc_illegal_ms">SIM not allowed MM#3</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc560/strings.xml b/core/res/res/values-mcc310-mnc560/strings.xml new file mode 100644 index 000000000000..a3fea29070f5 --- /dev/null +++ b/core/res/res/values-mcc310-mnc560/strings.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* //device/apps/common/assets/res/any/strings.xml +** +** Copyright 2006, 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. +*/ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string> + <string name="mmcc_illegal_ms">SIM not allowed MM#3</string> +</resources> diff --git a/core/res/res/values-mcc310-mnc950/strings.xml b/core/res/res/values-mcc310-mnc950/strings.xml new file mode 100644 index 000000000000..a3fea29070f5 --- /dev/null +++ b/core/res/res/values-mcc310-mnc950/strings.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* //device/apps/common/assets/res/any/strings.xml +** +** Copyright 2006, 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. +*/ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string> + <string name="mmcc_illegal_ms">SIM not allowed MM#3</string> +</resources> diff --git a/core/res/res/values-mcc311-mnc180/strings.xml b/core/res/res/values-mcc311-mnc180/strings.xml new file mode 100644 index 000000000000..a3fea29070f5 --- /dev/null +++ b/core/res/res/values-mcc311-mnc180/strings.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* //device/apps/common/assets/res/any/strings.xml +** +** Copyright 2006, 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. +*/ +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="mmcc_imsi_unknown_in_hlr">SIM not provisioned MM#2</string> + <string name="mmcc_illegal_ms">SIM not allowed MM#3</string> +</resources> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 98147e72448e..ca4b355664d7 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -531,15 +531,18 @@ <!-- Integer parameters of the wifi to cellular handover feature wifi should not stick to bad networks --> <integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz">-82</integer> + <integer translatable="false" name="config_wifi_framework_wifi_score_entry_rssi_threshold_5GHz">-82</integer> <integer translatable="false" name="config_wifi_framework_wifi_score_low_rssi_threshold_5GHz">-70</integer> <integer translatable="false" name="config_wifi_framework_wifi_score_good_rssi_threshold_5GHz">-57</integer> <integer translatable="false" name="config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz">-85</integer> + <integer translatable="false" name="config_wifi_framework_wifi_score_entry_rssi_threshold_24GHz">-85</integer> <integer translatable="false" name="config_wifi_framework_wifi_score_low_rssi_threshold_24GHz">-73</integer> <integer translatable="false" name="config_wifi_framework_wifi_score_good_rssi_threshold_24GHz">-60</integer> <integer translatable="false" name="config_wifi_framework_wifi_score_bad_link_speed_24">6</integer> <integer translatable="false" name="config_wifi_framework_wifi_score_bad_link_speed_5">12</integer> <integer translatable="false" name="config_wifi_framework_wifi_score_good_link_speed_24">24</integer> <integer translatable="false" name="config_wifi_framework_wifi_score_good_link_speed_5">36</integer> + <string translatable="false" name="config_wifi_random_mac_oui">DA-A1-19</string> <string translatable="false" name="config_wifi_framework_sap_2G_channel_list">1,6,11</string> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 8a5625b9d3b3..ce6815f10b30 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -593,17 +593,18 @@ <!-- This is the label for the notification channel settings that controls the behavior of the notification about applications that are running in the background (that is, perhaps confusingly, running foreground services but not the foreground UI on the screen). - [CHAR LIMIT=NONE] --> - <string name="notification_channel_foreground_service">Apps running in background</string> + [CHAR LIMIT=NONE BACKUP_MESSAGE_ID=6665375982962336520] --> + <string name="notification_channel_foreground_service">Apps consuming battery</string> - <!-- Label for foreground service notification when one app is running. [CHAR LIMIT=NONE] --> + <!-- Label for foreground service notification when one app is running. + [CHAR LIMIT=NONE BACKUP_MESSAGE_ID=6826789589341671842] --> <string name="foreground_service_app_in_background"><xliff:g id="app_name">%1$s</xliff:g> is - running in the background</string> + using battery</string> <!-- Label for foreground service notification when multiple apps are running. - [CHAR LIMIT=NONE] --> + [CHAR LIMIT=NONE BACKUP_MESSAGE_ID=7150914856893450380] --> <string name="foreground_service_apps_in_background"><xliff:g id="number">%1$d</xliff:g> apps - are running in the background</string> + are using battery</string> <!-- Content for foreground service notification when one app is running. [CHAR LIMIT=NONE] --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index af08e241c002..04cfe485df4a 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -357,9 +357,11 @@ <java-symbol type="integer" name="config_wifi_framework_associated_full_scan_max_total_dwell_time" /> <java-symbol type="integer" name="config_wifi_framework_associated_partial_scan_max_num_active_channels" /> <java-symbol type="integer" name="config_wifi_framework_wifi_score_bad_rssi_threshold_24GHz" /> + <java-symbol type="integer" name="config_wifi_framework_wifi_score_entry_rssi_threshold_24GHz" /> <java-symbol type="integer" name="config_wifi_framework_wifi_score_low_rssi_threshold_24GHz" /> <java-symbol type="integer" name="config_wifi_framework_wifi_score_good_rssi_threshold_24GHz" /> <java-symbol type="integer" name="config_wifi_framework_wifi_score_bad_rssi_threshold_5GHz" /> + <java-symbol type="integer" name="config_wifi_framework_wifi_score_entry_rssi_threshold_5GHz" /> <java-symbol type="integer" name="config_wifi_framework_wifi_score_low_rssi_threshold_5GHz" /> <java-symbol type="integer" name="config_wifi_framework_wifi_score_good_rssi_threshold_5GHz" /> <java-symbol type="integer" name="config_wifi_framework_wifi_score_bad_link_speed_24" /> diff --git a/packages/SystemUI/res/layout/car_qs_panel.xml b/packages/SystemUI/res/layout/car_qs_panel.xml index d1f7ff83db93..0b46b0bdaa1c 100644 --- a/packages/SystemUI/res/layout/car_qs_panel.xml +++ b/packages/SystemUI/res/layout/car_qs_panel.xml @@ -24,4 +24,11 @@ <include layout="@layout/car_status_bar_header" /> <include layout="@layout/car_qs_footer" /> + + <com.android.systemui.statusbar.car.UserGridView + android:id="@+id/user_grid" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_marginLeft="@dimen/car_margin" + android:layout_marginRight="@dimen/car_margin" /> </LinearLayout> diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java index 9730f29da977..d42b87bcef28 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFooter.java @@ -18,6 +18,7 @@ import android.content.Intent; import android.graphics.drawable.Drawable; import android.support.annotation.Nullable; import android.util.AttributeSet; +import android.util.Log; import android.view.View; import android.widget.ImageView; import android.widget.RelativeLayout; @@ -27,6 +28,7 @@ import com.android.systemui.R; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.qs.QSFooter; import com.android.systemui.qs.QSPanel; +import com.android.systemui.statusbar.car.UserGridView; import com.android.systemui.statusbar.phone.MultiUserSwitch; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.UserInfoController; @@ -37,10 +39,13 @@ import com.android.systemui.statusbar.policy.UserInfoController; */ public class CarQSFooter extends RelativeLayout implements QSFooter, UserInfoController.OnUserInfoChangedListener { + private static final String TAG = "CarQSFooter"; + private UserInfoController mUserInfoController; private MultiUserSwitch mMultiUserSwitch; private ImageView mMultiUserAvatar; + private UserGridView mUserGridView; public CarQSFooter(Context context, AttributeSet attrs) { super(context, attrs); @@ -54,6 +59,19 @@ public class CarQSFooter extends RelativeLayout implements QSFooter, mUserInfoController = Dependency.get(UserInfoController.class); + mMultiUserSwitch.setOnClickListener(v -> { + if (mUserGridView == null) { + Log.e(TAG, "CarQSFooter not properly set up; cannot display user switcher."); + return; + } + + if (!mUserGridView.isShowing()) { + mUserGridView.show(); + } else { + mUserGridView.hide(); + } + }); + findViewById(R.id.settings_button).setOnClickListener(v -> { ActivityStarter activityStarter = Dependency.get(ActivityStarter.class); @@ -80,6 +98,10 @@ public class CarQSFooter extends RelativeLayout implements QSFooter, } } + public void setUserGridView(UserGridView view) { + mUserGridView = view; + } + @Override public void setListening(boolean listening) { if (listening) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java index 7c2a8129813a..13298d378845 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/car/CarQSFragment.java @@ -22,9 +22,12 @@ import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; +import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.plugins.qs.QS; import com.android.systemui.qs.QSFooter; +import com.android.systemui.statusbar.car.UserGridView; +import com.android.systemui.statusbar.policy.UserSwitcherController; /** * A quick settings fragment for the car. For auto, there is no row for quick settings or ability @@ -33,7 +36,8 @@ import com.android.systemui.qs.QSFooter; */ public class CarQSFragment extends Fragment implements QS { private View mHeader; - private QSFooter mFooter; + private CarQSFooter mFooter; + private UserGridView mUserGridView; @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @@ -46,6 +50,12 @@ public class CarQSFragment extends Fragment implements QS { super.onViewCreated(view, savedInstanceState); mHeader = view.findViewById(R.id.header); mFooter = view.findViewById(R.id.qs_footer); + + mUserGridView = view.findViewById(R.id.user_grid); + mUserGridView.init(null, Dependency.get(UserSwitcherController.class), + false /* showInitially */); + + mFooter.setUserGridView(mUserGridView); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java index 6060134de6da..172c62a99db2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java @@ -53,7 +53,7 @@ public class FullscreenUserSwitcher { mParent = containerStub.inflate(); mContainer = mParent.findViewById(R.id.container); mUserGridView = mContainer.findViewById(R.id.user_grid); - mUserGridView.init(statusBar, mUserSwitcherController); + mUserGridView.init(statusBar, mUserSwitcherController, true /* showInitially */); mUserGridView.setUserSelectionListener(record -> { if (!record.isCurrent) { toggleSwitchInProgress(true); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java index f178aa634247..e551801ca434 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java @@ -16,20 +16,21 @@ package com.android.systemui.statusbar.car; +import android.animation.Animator; +import android.animation.Animator.AnimatorListener; +import android.animation.ValueAnimator; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Align; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; -import android.os.UserHandle; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; +import android.support.v4.view.animation.FastOutSlowInInterpolator; import android.util.AttributeSet; -import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -37,9 +38,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; -import com.android.internal.util.UserIcons; import com.android.systemui.R; -import com.android.systemui.statusbar.UserUtil; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.policy.UserSwitcherController; @@ -48,21 +47,44 @@ import com.android.systemui.statusbar.policy.UserSwitcherController; * One of the uses of this is for the lock screen in auto. */ public class UserGridView extends ViewPager { + private static final int EXPAND_ANIMATION_TIME_MS = 200; + private static final int HIDE_ANIMATION_TIME_MS = 133; + private StatusBar mStatusBar; private UserSwitcherController mUserSwitcherController; private Adapter mAdapter; private UserSelectionListener mUserSelectionListener; + private ValueAnimator mHeightAnimator; + private int mTargetHeight; + private int mHeightChildren; + private boolean mShowing; public UserGridView(Context context, AttributeSet attrs) { super(context, attrs); } - public void init(StatusBar statusBar, UserSwitcherController userSwitcherController) { + public void init(StatusBar statusBar, UserSwitcherController userSwitcherController, + boolean showInitially) { mStatusBar = statusBar; mUserSwitcherController = userSwitcherController; mAdapter = new Adapter(mUserSwitcherController); addOnLayoutChangeListener(mAdapter); setAdapter(mAdapter); + mShowing = showInitially; + } + + public boolean isShowing() { + return mShowing; + } + + public void show() { + mShowing = true; + animateHeightChange(getMeasuredHeight(), mHeightChildren); + } + + public void hide() { + mShowing = false; + animateHeightChange(getMeasuredHeight(), 0); } public void onUserSwitched(int newUserId) { @@ -83,16 +105,85 @@ public class UserGridView extends ViewPager { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // Wrap content doesn't work in ViewPagers, so simulate the behavior in code. int height = 0; - for(int i = 0; i < getChildCount(); i++) { - View child = getChildAt(i); - child.measure(widthMeasureSpec, - MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); - height = Math.max(child.getMeasuredHeight(), height); + if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) { + height = MeasureSpec.getSize(heightMeasureSpec); + } else { + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + child.measure(widthMeasureSpec, + MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + height = Math.max(child.getMeasuredHeight(), height); + } + + mHeightChildren = height; + + // Override the height if it's not showing. + if (!mShowing) { + height = 0; + } + + // Respect the AT_MOST request from parent. + if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) { + height = Math.min(MeasureSpec.getSize(heightMeasureSpec), height); + } } heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); + super.onMeasure(widthMeasureSpec, heightMeasureSpec); } + private void animateHeightChange(int oldHeight, int newHeight) { + // If there is no change in height or an animation is already in progress towards the + // desired height, then there's no need to make any changes. + if (oldHeight == newHeight || newHeight == mTargetHeight) { + return; + } + + // Animation in progress is not going towards the new target, so cancel it. + if (mHeightAnimator != null){ + mHeightAnimator.cancel(); + } + + mTargetHeight = newHeight; + mHeightAnimator = ValueAnimator.ofInt(oldHeight, mTargetHeight); + mHeightAnimator.addUpdateListener(valueAnimator -> { + ViewGroup.LayoutParams layoutParams = getLayoutParams(); + layoutParams.height = (Integer) valueAnimator.getAnimatedValue(); + requestLayout(); + }); + mHeightAnimator.addListener(new AnimatorListener() { + @Override + public void onAnimationStart(Animator animator) {} + + @Override + public void onAnimationEnd(Animator animator) { + // ValueAnimator does not guarantee that the update listener will get an update + // to the final value, so here, the final value is set. Though the final calculated + // height (mTargetHeight) could be set, WRAP_CONTENT is more appropriate. + ViewGroup.LayoutParams layoutParams = getLayoutParams(); + layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; + requestLayout(); + mHeightAnimator = null; + } + + @Override + public void onAnimationCancel(Animator animator) {} + + @Override + public void onAnimationRepeat(Animator animator) {} + }); + + mHeightAnimator.setInterpolator(new FastOutSlowInInterpolator()); + if (oldHeight < newHeight) { + // Expanding + mHeightAnimator.setDuration(EXPAND_ANIMATION_TIME_MS); + } else { + // Hiding + mHeightAnimator.setDuration(HIDE_ANIMATION_TIME_MS); + } + mHeightAnimator.start(); + } + /** * This is a ViewPager.PagerAdapter which deletegates the work to a * UserSwitcherController.BaseUserAdapter. Java doesn't support multiple inheritance so we have diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java index 844a2c495501..3115361c6927 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java @@ -16,7 +16,10 @@ package com.android.systemui.statusbar.notification; +import android.content.Context; import android.graphics.Color; +import android.os.UserHandle; +import android.provider.Settings; import android.view.View; import android.widget.ImageView; @@ -57,4 +60,10 @@ public class NotificationUtils { offsetView.getLocationOnScreen(sLocationOffset); return sLocationOffset[1] - sLocationBase[1]; } + + public static boolean isHapticFeedbackDisabled(Context context) { + return Settings.System.getIntForUser(context.getContentResolver(), + Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 0; + } + } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java index e0d9748c48bf..88a562648a63 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java @@ -16,14 +16,19 @@ package com.android.systemui.statusbar.phone; +import static com.android.systemui.statusbar.notification.NotificationUtils.isHapticFeedbackDisabled; + import android.content.Context; import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.drawable.Icon; +import android.os.AsyncTask; +import android.os.UserHandle; import android.os.VibrationEffect; import android.os.Vibrator; +import android.provider.Settings; import android.support.v4.util.ArrayMap; import android.support.v4.util.ArraySet; import android.util.AttributeSet; @@ -34,6 +39,7 @@ import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.statusbar.AlphaOptimizedFrameLayout; import com.android.systemui.statusbar.StatusBarIconView; +import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.stack.AnimationFilter; import com.android.systemui.statusbar.stack.AnimationProperties; import com.android.systemui.statusbar.stack.StackStateAnimator; @@ -623,9 +629,10 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { boolean wasInShelf = icon.isInShelf(); boolean inShelf = iconAppearAmount == 1.0f; icon.setIsInShelf(inShelf); - if (mVibrateOnAnimation && !justAdded && mAnimationsEnabled - && wasInShelf != inShelf) { - mVibrator.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_TICK)); + if (shouldVibrateChange(wasInShelf != inShelf)) { + AsyncTask.execute( + () -> mVibrator.vibrate(VibrationEffect.get( + VibrationEffect.EFFECT_TICK))); } } justAdded = false; @@ -634,6 +641,25 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { justUndarkened = false; } + private boolean shouldVibrateChange(boolean inShelfChanged) { + if (!mVibrateOnAnimation) { + return false; + } + if (justAdded) { + return false; + } + if (!mAnimationsEnabled) { + return false; + } + if (!inShelfChanged) { + return false; + } + if (isHapticFeedbackDisabled(mContext)) { + return false; + } + return true; + } + public boolean hasCustomTransformHeight() { return isLastExpandIcon && customTransformHeight != NO_VALUE; } 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 d3ee55098474..46f9c04aa42e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.phone; +import static com.android.systemui.statusbar.notification.NotificationUtils.isHapticFeedbackDisabled; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; @@ -23,9 +25,12 @@ import android.animation.ValueAnimator; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; +import android.os.AsyncTask; import android.os.SystemClock; +import android.os.UserHandle; import android.os.VibrationEffect; import android.os.Vibrator; +import android.provider.Settings; import android.util.AttributeSet; import android.util.Log; import android.view.InputDevice; @@ -45,6 +50,7 @@ import com.android.systemui.classifier.FalsingManager; import com.android.systemui.doze.DozeLog; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.policy.HeadsUpManager; import java.io.FileDescriptor; @@ -59,6 +65,7 @@ public abstract class PanelView extends FrameLayout { private float mMinExpandHeight; private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger(); private boolean mPanelUpdateWhenAnimatorEnds; + private boolean mVibrateOnOpening; private final void logf(String fmt, Object... args) { Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args)); @@ -203,6 +210,8 @@ public abstract class PanelView extends FrameLayout { mNotificationsDragEnabled = getResources().getBoolean(R.bool.config_enableNotificationShadeDrag); mVibrator = mContext.getSystemService(Vibrator.class); + mVibrateOnOpening = mContext.getResources().getBoolean( + R.bool.config_vibrateOnIconAnimation); } protected void loadDimens() { @@ -394,7 +403,10 @@ public abstract class PanelView extends FrameLayout { runPeekAnimation(INITIAL_OPENING_PEEK_DURATION, getOpeningHeight(), false /* collapseWhenFinished */); notifyBarPanelExpansionChanged(); - mVibrator.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_CLICK)); + if (mVibrateOnOpening && !isHapticFeedbackDisabled(mContext)) { + AsyncTask.execute( + () -> mVibrator.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_TICK))); + } } protected abstract float getOpeningHeight(); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 325ffb4c3581..30e5a2cdba9d 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -28,6 +28,7 @@ import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID; import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; @@ -3230,6 +3231,18 @@ public class ActivityManagerService extends IActivityManager.Stub } final void applyUpdateVrModeLocked(ActivityRecord r) { + // VR apps are expected to run in a main display. If an app is turning on VR for + // itself, but lives in a dynamic stack, then make sure that it is moved to the main + // fullscreen stack before enabling VR Mode. + // TODO: The goal of this code is to keep the VR app on the main display. When the + // stack implementation changes in the future, keep in mind that the use of the fullscreen + // stack is a means to move the activity to the main display and a moveActivityToDisplay() + // option would be a better choice here. + if (r.requestedVrComponent != null && r.getStackId() >= FIRST_DYNAMIC_STACK_ID) { + Slog.i(TAG, "Moving " + r.shortComponentName + " from stack " + r.getStackId() + + " to main stack for VR"); + moveTaskToStack(r.getTask().taskId, FULLSCREEN_WORKSPACE_STACK_ID, true /* toTop */); + } mHandler.sendMessage( mHandler.obtainMessage(VR_MODE_CHANGE_MSG, 0, 0, r)); } diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 6b1f7585dde6..74bdf6f3dae4 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -947,8 +947,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo // the user leaves that mode. mLastReportedMultiWindowMode = !task.mFullscreen; mLastReportedPictureInPictureMode = (task.getStackId() == PINNED_STACK_ID); - - onOverrideConfigurationSent(); } void removeWindowContainer() { @@ -2212,15 +2210,12 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo * a new merged configuration is sent to the client for this activity. */ void setLastReportedConfiguration(@NonNull MergedConfiguration config) { - mLastReportedConfiguration.setTo(config); + setLastReportedConfiguration(config.getGlobalConfiguration(), + config.getOverrideConfiguration()); } - /** Call when override config was sent to the Window Manager to update internal records. */ - // TODO(b/36505427): Why do we set last reported based on sending the config to WM? Seems like - // we should only set this when we actually report to the activity which is what the method - // setLastReportedMergedOverrideConfiguration() does. Investigate if this is really needed. - void onOverrideConfigurationSent() { - mLastReportedConfiguration.setOverrideConfiguration(getMergedOverrideConfiguration()); + void setLastReportedConfiguration(Configuration global, Configuration override) { + mLastReportedConfiguration.setConfiguration(global, override); } @Override @@ -2234,9 +2229,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo return; } mWindowContainerController.onOverrideConfigurationChanged(newConfig, mBounds); - // TODO(b/36505427): Can we consolidate the call points of onOverrideConfigurationSent() - // to just use this method instead? - onOverrideConfigurationSent(); } // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer. @@ -2423,8 +2415,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo // Update last reported values. final Configuration newMergedOverrideConfig = getMergedOverrideConfiguration(); - mLastReportedConfiguration.setConfiguration(service.getGlobalConfiguration(), - newMergedOverrideConfig); + + setLastReportedConfiguration(service.getGlobalConfiguration(), newMergedOverrideConfig); if (changes == 0 && !forceNewConfig) { if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 617ba9603463..261797e3113c 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -1294,7 +1294,6 @@ final class TaskRecord extends ConfigurationContainer implements TaskWindowConta // created controller for the activity we are starting yet. mWindowContainerController.positionChildAt(appController, index); } - r.onOverrideConfigurationSent(); // Make sure the list of display UID whitelists is updated // now that this record is in a new task. diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 5fb83ab42866..e448fb2a532e 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -795,34 +795,57 @@ public class ServiceState implements Parcelable { return rtString; } + /** + * Convert RIL Service State to String + * + * @param serviceState + * @return String representation of the ServiceState + * + * @hide + */ + public static String rilServiceStateToString(int serviceState) { + switch(serviceState) { + case STATE_IN_SERVICE: + return "IN_SERVICE"; + case STATE_OUT_OF_SERVICE: + return "OUT_OF_SERVICE"; + case STATE_EMERGENCY_ONLY: + return "EMERGENCY_ONLY"; + case STATE_POWER_OFF: + return "POWER_OFF"; + default: + return "UNKNOWN"; + } + } + @Override public String toString() { - String radioTechnology = rilRadioTechnologyToString(mRilVoiceRadioTechnology); - String dataRadioTechnology = rilRadioTechnologyToString(mRilDataRadioTechnology); - - return (mVoiceRegState + " " + mDataRegState - + " " - + "voice " + getRoamingLogString(mVoiceRoamingType) - + " " - + "data " + getRoamingLogString(mDataRoamingType) - + " " + mVoiceOperatorAlphaLong - + " " + mVoiceOperatorAlphaShort - + " " + mVoiceOperatorNumeric - + " " + mDataOperatorAlphaLong - + " " + mDataOperatorAlphaShort - + " " + mDataOperatorNumeric - + " " + (mIsManualNetworkSelection ? "(manual)" : "") - + " " + radioTechnology - + " " + dataRadioTechnology - + " " + (mCssIndicator ? "CSS supported" : "CSS not supported") - + " " + mNetworkId - + " " + mSystemId - + " RoamInd=" + mCdmaRoamingIndicator - + " DefRoamInd=" + mCdmaDefaultRoamingIndicator - + " EmergOnly=" + mIsEmergencyOnly - + " IsDataRoamingFromRegistration=" + mIsDataRoamingFromRegistration - + " IsUsingCarrierAggregation=" + mIsUsingCarrierAggregation - + " mLteEarfcnRsrpBoost=" + mLteEarfcnRsrpBoost); + return new StringBuilder().append("{mVoiceRegState=").append(mVoiceRegState) + .append("(" + rilServiceStateToString(mVoiceRegState) + ")") + .append(", mDataRegState=").append(mDataRegState) + .append("(" + rilServiceStateToString(mDataRegState) + ")") + .append(", mVoiceRoamingType=").append(getRoamingLogString(mVoiceRoamingType)) + .append(", mDataRoamingType=").append(getRoamingLogString(mDataRoamingType)) + .append(", mVoiceOperatorAlphaLong=").append(mVoiceOperatorAlphaLong) + .append(", mVoiceOperatorAlphaShort=").append(mVoiceOperatorAlphaShort) + .append(", mDataOperatorAlphaLong=").append(mDataOperatorAlphaLong) + .append(", mDataOperatorAlphaShort=").append(mDataOperatorAlphaShort) + .append(", isManualNetworkSelection=").append(mIsManualNetworkSelection) + .append(mIsManualNetworkSelection ? "(manual)" : "(automatic)") + .append(", mRilVoiceRadioTechnology=").append(mRilVoiceRadioTechnology) + .append("(" + rilRadioTechnologyToString(mRilVoiceRadioTechnology) + ")") + .append(", mRilDataRadioTechnology=").append(mRilDataRadioTechnology) + .append("(" + rilRadioTechnologyToString(mRilDataRadioTechnology) + ")") + .append(", mCssIndicator=").append(mCssIndicator ? "supported" : "unsupported") + .append(", mNetworkId=").append(mNetworkId) + .append(", mSystemId=").append(mSystemId) + .append(", mCdmaRoamingIndicator=").append(mCdmaRoamingIndicator) + .append(", mCdmaDefaultRoamingIndicator=").append(mCdmaDefaultRoamingIndicator) + .append(", mIsEmergencyOnly=").append(mIsEmergencyOnly) + .append(", mIsDataRoamingFromRegistration=").append(mIsDataRoamingFromRegistration) + .append(", mIsUsingCarrierAggregation=").append(mIsUsingCarrierAggregation) + .append(", mLteEarfcnRsrpBoost=").append(mLteEarfcnRsrpBoost) + .append("}").toString(); } private void setNullState(int state) { diff --git a/core/tests/coretests/src/android/net/IpPrefixTest.java b/tests/net/java/android/net/IpPrefixTest.java index 4f2387dcf5c1..b5b2c07cbc4e 100644 --- a/core/tests/coretests/src/android/net/IpPrefixTest.java +++ b/tests/net/java/android/net/IpPrefixTest.java @@ -16,18 +16,27 @@ package android.net; -import android.net.IpPrefix; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import android.os.Parcel; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + import java.net.InetAddress; import java.util.Random; -import junit.framework.TestCase; -import static android.test.MoreAsserts.assertNotEqual; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; +import org.junit.runner.RunWith; +import org.junit.Test; -public class IpPrefixTest extends TestCase { +@RunWith(AndroidJUnit4.class) +@SmallTest +public class IpPrefixTest { private static InetAddress Address(String addr) { return InetAddress.parseNumericAddress(addr); @@ -42,7 +51,7 @@ public class IpPrefixTest extends TestCase { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xa0 }; - @SmallTest + @Test public void testConstructor() { IpPrefix p; try { @@ -103,6 +112,7 @@ public class IpPrefixTest extends TestCase { } catch(IllegalArgumentException expected) {} } + @Test public void testTruncation() { IpPrefix p; @@ -170,7 +180,7 @@ public class IpPrefixTest extends TestCase { assertFalse(o2.equals(o1)); } - @SmallTest + @Test public void testEquals() { IpPrefix p1, p2; @@ -212,7 +222,7 @@ public class IpPrefixTest extends TestCase { assertAreNotEqual(p1, p2); } - @SmallTest + @Test public void testContains() { IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127"); assertTrue(p.contains(Address("2001:db8:f00::ace:d00c"))); @@ -240,7 +250,7 @@ public class IpPrefixTest extends TestCase { assertFalse(ipv4Default.contains(Address("2001:db8::f00"))); } - @SmallTest + @Test public void testHashCode() { IpPrefix p = new IpPrefix(new byte[4], 0); Random random = new Random(); @@ -261,12 +271,12 @@ public class IpPrefixTest extends TestCase { assertEquals(p.hashCode(), oldP.hashCode()); } if (p.hashCode() != oldP.hashCode()) { - assertNotEqual(p, oldP); + assertNotEquals(p, oldP); } } } - @SmallTest + @Test public void testHashCodeIsNotConstant() { IpPrefix[] prefixes = { new IpPrefix("2001:db8:f00::ace:d00d/127"), @@ -276,12 +286,12 @@ public class IpPrefixTest extends TestCase { }; for (int i = 0; i < prefixes.length; i++) { for (int j = i + 1; j < prefixes.length; j++) { - assertNotEqual(prefixes[i].hashCode(), prefixes[j].hashCode()); + assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode()); } } } - @SmallTest + @Test public void testMappedAddressesAreBroken() { // 192.0.2.0/24 != ::ffff:c000:0204/120, but because we use InetAddress, // we are unable to comprehend that. @@ -318,13 +328,16 @@ public class IpPrefixTest extends TestCase { assertEquals(p, p2); } + @Test public void testParceling() { IpPrefix p; p = new IpPrefix("2001:4860:db8::/64"); assertParcelingIsLossless(p); + assertTrue(p.isIPv6()); p = new IpPrefix("192.0.2.0/25"); assertParcelingIsLossless(p); + assertTrue(p.isIPv4()); } } diff --git a/core/tests/coretests/src/android/net/LinkAddressTest.java b/tests/net/java/android/net/LinkAddressTest.java index adf8d95c0b66..c1ad94669508 100644 --- a/core/tests/coretests/src/android/net/LinkAddressTest.java +++ b/tests/net/java/android/net/LinkAddressTest.java @@ -16,6 +16,23 @@ package android.net; +import static android.system.OsConstants.IFA_F_DADFAILED; +import static android.system.OsConstants.IFA_F_DEPRECATED; +import static android.system.OsConstants.IFA_F_OPTIMISTIC; +import static android.system.OsConstants.IFA_F_PERMANENT; +import static android.system.OsConstants.IFA_F_TEMPORARY; +import static android.system.OsConstants.IFA_F_TENTATIVE; +import static android.system.OsConstants.RT_SCOPE_HOST; +import static android.system.OsConstants.RT_SCOPE_LINK; +import static android.system.OsConstants.RT_SCOPE_SITE; +import static android.system.OsConstants.RT_SCOPE_UNIVERSE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; @@ -27,44 +44,35 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; -import android.net.LinkAddress; import android.os.Parcel; -import android.test.AndroidTestCase; -import static android.test.MoreAsserts.assertNotEqual; -import android.test.suitebuilder.annotation.SmallTest; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; -import static android.system.OsConstants.IFA_F_DADFAILED; -import static android.system.OsConstants.IFA_F_DEPRECATED; -import static android.system.OsConstants.IFA_F_OPTIMISTIC; -import static android.system.OsConstants.IFA_F_PERMANENT; -import static android.system.OsConstants.IFA_F_TEMPORARY; -import static android.system.OsConstants.IFA_F_TENTATIVE; -import static android.system.OsConstants.RT_SCOPE_HOST; -import static android.system.OsConstants.RT_SCOPE_LINK; -import static android.system.OsConstants.RT_SCOPE_SITE; -import static android.system.OsConstants.RT_SCOPE_UNIVERSE; +import org.junit.runner.RunWith; +import org.junit.Test; -/** - * Tests for {@link LinkAddress}. - */ -public class LinkAddressTest extends AndroidTestCase { +@RunWith(AndroidJUnit4.class) +@SmallTest +public class LinkAddressTest { private static final String V4 = "192.0.2.1"; private static final String V6 = "2001:db8::1"; private static final InetAddress V4_ADDRESS = NetworkUtils.numericToInetAddress(V4); private static final InetAddress V6_ADDRESS = NetworkUtils.numericToInetAddress(V6); + @Test public void testConstants() { // RT_SCOPE_UNIVERSE = 0, but all the other constants should be nonzero. - assertNotEqual(0, RT_SCOPE_HOST); - assertNotEqual(0, RT_SCOPE_LINK); - assertNotEqual(0, RT_SCOPE_SITE); + assertNotEquals(0, RT_SCOPE_HOST); + assertNotEquals(0, RT_SCOPE_LINK); + assertNotEquals(0, RT_SCOPE_SITE); - assertNotEqual(0, IFA_F_DEPRECATED); - assertNotEqual(0, IFA_F_PERMANENT); - assertNotEqual(0, IFA_F_TENTATIVE); + assertNotEquals(0, IFA_F_DEPRECATED); + assertNotEquals(0, IFA_F_PERMANENT); + assertNotEquals(0, IFA_F_TENTATIVE); } + @Test public void testConstructors() throws SocketException { LinkAddress address; @@ -74,12 +82,14 @@ public class LinkAddressTest extends AndroidTestCase { assertEquals(25, address.getPrefixLength()); assertEquals(0, address.getFlags()); assertEquals(RT_SCOPE_UNIVERSE, address.getScope()); + assertTrue(address.isIPv4()); address = new LinkAddress(V6_ADDRESS, 127); assertEquals(V6_ADDRESS, address.getAddress()); assertEquals(127, address.getPrefixLength()); assertEquals(0, address.getFlags()); assertEquals(RT_SCOPE_UNIVERSE, address.getScope()); + assertTrue(address.isIPv6()); // Nonsensical flags/scopes or combinations thereof are acceptable. address = new LinkAddress(V6 + "/64", IFA_F_DEPRECATED | IFA_F_PERMANENT, RT_SCOPE_LINK); @@ -87,12 +97,14 @@ public class LinkAddressTest extends AndroidTestCase { assertEquals(64, address.getPrefixLength()); assertEquals(IFA_F_DEPRECATED | IFA_F_PERMANENT, address.getFlags()); assertEquals(RT_SCOPE_LINK, address.getScope()); + assertTrue(address.isIPv6()); address = new LinkAddress(V4 + "/23", 123, 456); assertEquals(V4_ADDRESS, address.getAddress()); assertEquals(23, address.getPrefixLength()); assertEquals(123, address.getFlags()); assertEquals(456, address.getScope()); + assertTrue(address.isIPv4()); // InterfaceAddress doesn't have a constructor. Fetch some from an interface. List<InterfaceAddress> addrs = NetworkInterface.getByName("lo").getInterfaceAddresses(); @@ -174,6 +186,7 @@ public class LinkAddressTest extends AndroidTestCase { } catch(IllegalArgumentException expected) {} } + @Test public void testAddressScopes() { assertEquals(RT_SCOPE_HOST, new LinkAddress("::/128").getScope()); assertEquals(RT_SCOPE_HOST, new LinkAddress("0.0.0.0/32").getScope()); @@ -216,6 +229,7 @@ public class LinkAddressTest extends AndroidTestCase { assertFalse(l2 + " unexpectedly equal to " + l1, l2.equals(l1)); } + @Test public void testEqualsAndSameAddressAs() { LinkAddress l1, l2, l3; @@ -293,26 +307,17 @@ public class LinkAddressTest extends AndroidTestCase { assertIsSameAddressAs(l1, l2); } + @Test public void testHashCode() { - LinkAddress l; - - l = new LinkAddress(V4_ADDRESS, 23); - assertEquals(-982787, l.hashCode()); - - l = new LinkAddress(V4_ADDRESS, 23, 0, RT_SCOPE_HOST); - assertEquals(-971865, l.hashCode()); - - l = new LinkAddress(V4_ADDRESS, 27); - assertEquals(-982743, l.hashCode()); - - l = new LinkAddress(V6_ADDRESS, 64); - assertEquals(1076522926, l.hashCode()); + LinkAddress l1, l2; - l = new LinkAddress(V6_ADDRESS, 128); - assertEquals(1076523630, l.hashCode()); + l1 = new LinkAddress(V4_ADDRESS, 23); + l2 = new LinkAddress(V4_ADDRESS, 23, 0, RT_SCOPE_HOST); + assertNotEquals(l1.hashCode(), l2.hashCode()); - l = new LinkAddress(V6_ADDRESS, 128, IFA_F_TENTATIVE, RT_SCOPE_UNIVERSE); - assertEquals(1076524846, l.hashCode()); + l1 = new LinkAddress(V6_ADDRESS, 128); + l2 = new LinkAddress(V6_ADDRESS, 128, IFA_F_TENTATIVE, RT_SCOPE_UNIVERSE); + assertNotEquals(l1.hashCode(), l2.hashCode()); } private LinkAddress passThroughParcel(LinkAddress l) { @@ -334,6 +339,7 @@ public class LinkAddressTest extends AndroidTestCase { assertEquals(l, l2); } + @Test public void testParceling() { LinkAddress l; @@ -352,6 +358,7 @@ public class LinkAddressTest extends AndroidTestCase { assertFalse(msg, l.isGlobalPreferred()); } + @Test public void testIsGlobalPreferred() { LinkAddress l; diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java index ac5df05373c1..dc5ba0cc83b5 100644 --- a/wifi/java/android/net/wifi/RttManager.java +++ b/wifi/java/android/net/wifi/RttManager.java @@ -1,5 +1,6 @@ package android.net.wifi; +import android.Manifest; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; @@ -313,6 +314,7 @@ public class RttManager { }; } + @RequiresPermission(Manifest.permission.LOCATION_HARDWARE) public RttCapabilities getRttCapabilities() { synchronized (mCapabilitiesLock) { if (mRttCapabilities == null) { @@ -925,6 +927,51 @@ public class RttManager { public void onAborted(); } + /** + * A parcelable that contains rtt client information. + * + * @hide + */ + public static class RttClient implements Parcelable { + // Package name of RttClient. + private final String mPackageName; + + public RttClient(String packageName) { + mPackageName = packageName; + } + + protected RttClient(Parcel in) { + mPackageName = in.readString(); + } + + public static final Creator<RttManager.RttClient> CREATOR = + new Creator<RttManager.RttClient>() { + @Override + public RttManager.RttClient createFromParcel(Parcel in) { + return new RttManager.RttClient(in); + } + + @Override + public RttManager.RttClient[] newArray(int size) { + return new RttManager.RttClient[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeString(mPackageName); + } + + public String getPackageName() { + return mPackageName; + } + } + private boolean rttParamSanity(RttParams params, int index) { if (mRttCapabilities == null) { if(getRttCapabilities() == null) { @@ -1236,7 +1283,8 @@ public class RttManager { mAsyncChannel.connectSync(mContext, handler, messenger); // We cannot use fullyConnectSync because it sends the FULL_CONNECTION message // synchronously, which causes RttService to receive the wrong replyTo value. - mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); + mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION, + new RttClient(context.getPackageName())); mAsyncChannel.sendMessage(CMD_OP_REG_BINDER, key[0]); } |