diff options
536 files changed, 10125 insertions, 8604 deletions
diff --git a/Android.bp b/Android.bp index ea14b9df5dd0..a082085f6804 100644 --- a/Android.bp +++ b/Android.bp @@ -212,6 +212,7 @@ filegroup { name: "framework-non-updatable-sources", srcs: [ // Java/AIDL sources under frameworks/base + ":framework-appsearch-sources", ":framework-blobstore-sources", ":framework-core-sources", ":framework-drm-sources", @@ -870,11 +871,13 @@ java_library { srcs: [ "core/java/android/os/HidlSupport.java", "core/java/android/annotation/IntDef.java", + "core/java/android/annotation/IntRange.java", "core/java/android/annotation/NonNull.java", "core/java/android/annotation/Nullable.java", "core/java/android/annotation/SystemApi.java", "core/java/android/annotation/TestApi.java", "core/java/android/annotation/UnsupportedAppUsage.java", + "core/java/android/os/HidlMemory.java", "core/java/android/os/HwBinder.java", "core/java/android/os/HwBlob.java", "core/java/android/os/HwParcel.java", @@ -1083,6 +1086,7 @@ stubs_defaults { ":core-current-stubs-source", ":core_public_api_files", ":updatable-media-srcs", + ":ike-api-srcs", ], libs: ["framework-internal-utils"], installable: false, @@ -1405,8 +1409,10 @@ droidstubs { srcs: [ "core/java/android/os/HidlSupport.java", "core/java/android/annotation/IntDef.java", + "core/java/android/annotation/IntRange.java", "core/java/android/annotation/NonNull.java", "core/java/android/annotation/SystemApi.java", + "core/java/android/os/HidlMemory.java", "core/java/android/os/HwBinder.java", "core/java/android/os/HwBlob.java", "core/java/android/os/HwParcel.java", diff --git a/CleanSpec.mk b/CleanSpec.mk index f7a285835126..8fac394a97fa 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -255,6 +255,7 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/DefaultContainerSer $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/CaptivePortalLogin) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/ext.jar) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/telephony/java/com/google/android/mms) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/*-service.jar) # ****************************************************************** # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER # ****************************************************************** diff --git a/apex/appsearch/framework/Android.bp b/apex/appsearch/framework/Android.bp new file mode 100644 index 000000000000..0a65f7320d8a --- /dev/null +++ b/apex/appsearch/framework/Android.bp @@ -0,0 +1,39 @@ +// Copyright (C) 2019 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. + +filegroup { + name: "framework-appsearch-sources", + srcs: [ + "java/**/*.java", + "java/**/*.aidl", + ], + path: "java", +} + +java_library { + name: "framework-appsearch", + installable: false, + sdk_version: "core_platform", + srcs: [ + ":framework-appsearch-sources", + ], + aidl: { + export_include_dirs: [ + "java", + ], + }, + libs: [ + "framework-minus-apex", + ], +} diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java new file mode 100644 index 000000000000..a8ee35c129eb --- /dev/null +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 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.app.appsearch; + +import android.annotation.SystemService; +import android.content.Context; + +/** + * TODO(b/142567528): add comments when implement this class + * @hide + */ +@SystemService(Context.APP_SEARCH_SERVICE) +public class AppSearchManager { + private final IAppSearchManager mService; + /** + * TODO(b/142567528): add comments when implement this class + * @hide + */ + public AppSearchManager(IAppSearchManager service) { + mService = service; + } +} diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java new file mode 100644 index 000000000000..fcebe3d9cf3c --- /dev/null +++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManagerFrameworkInitializer.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2019 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.app.appsearch; + +import android.app.SystemServiceRegistry; +import android.content.Context; + +/** + * This is where the AppSearchManagerService wrapper is registered. + * + * TODO(b/142567528): add comments when implement this class + * @hide + */ +public class AppSearchManagerFrameworkInitializer { + + /** + * TODO(b/142567528): add comments when implement this class + */ + public static void initialize() { + SystemServiceRegistry.registerStaticService( + Context.APP_SEARCH_SERVICE, AppSearchManager.class, + (service) -> new AppSearchManager(IAppSearchManager.Stub.asInterface(service))); + } +} diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl new file mode 100644 index 000000000000..f0f4f512d769 --- /dev/null +++ b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl @@ -0,0 +1,19 @@ +/** + * Copyright 2019, 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.app.appsearch; +/** {@hide} */ +interface IAppSearchManager { +} diff --git a/apex/appsearch/service/Android.bp b/apex/appsearch/service/Android.bp new file mode 100644 index 000000000000..2cd7aa009c46 --- /dev/null +++ b/apex/appsearch/service/Android.bp @@ -0,0 +1,24 @@ +// Copyright (C) 2019 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. +java_library { + name: "service-appsearch", + installable: true, + srcs: [ + "java/**/*.java", + ], + libs: [ + "framework", + "services.core", + ], +} diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java new file mode 100644 index 000000000000..4d44d9d04806 --- /dev/null +++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2019 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.server.appsearch; + +import android.app.appsearch.IAppSearchManager; +import android.content.Context; + +import com.android.server.SystemService; + +/** + * TODO(b/142567528): add comments when implement this class + */ +public class AppSearchManagerService extends SystemService { + + public AppSearchManagerService(Context context) { + super(context); + } + + @Override + public void onStart() { + publishBinderService(Context.APP_SEARCH_SERVICE, new Stub()); + } + + private class Stub extends IAppSearchManager.Stub { + } +} diff --git a/apex/blobstore/service/Android.bp b/apex/blobstore/service/Android.bp index 019f98937df3..d8caa5aed788 100644 --- a/apex/blobstore/service/Android.bp +++ b/apex/blobstore/service/Android.bp @@ -13,7 +13,7 @@ // limitations under the License. java_library { - name: "blobstore-service", + name: "service-blobstore", installable: true, srcs: [ @@ -24,4 +24,4 @@ java_library { "framework", "services.core", ], -}
\ No newline at end of file +} diff --git a/apex/jobscheduler/README_js-mainline.md b/apex/jobscheduler/README_js-mainline.md index ea20e3e29d99..134ff3da4507 100644 --- a/apex/jobscheduler/README_js-mainline.md +++ b/apex/jobscheduler/README_js-mainline.md @@ -2,14 +2,14 @@ ## Current structure -- JS service side classes are put in `jobscheduler-service.jar`. +- JS service side classes are put in `service-jobscheduler.jar`. It's *not* included in services.jar, and instead it's put in the system server classpath, which currently looks like the following: -`SYSTEMSERVERCLASSPATH=/system/framework/services.jar:/system/framework/ethernet-service.jar:/system/framework/com.android.location.provider.jar:/system/framework/jobscheduler-service.jar` +`SYSTEMSERVERCLASSPATH=/system/framework/services.jar:/system/framework/ethernet-service.jar:/system/framework/com.android.location.provider.jar:/system/framework/service-jobscheduler.jar` `SYSTEMSERVERCLASSPATH` is generated from `PRODUCT_SYSTEM_SERVER_JARS`. -- JS framework side classes are put in `jobscheduler-framework.jar`, +- JS framework side classes are put in `framework-jobscheduler.jar`, and the rest of the framework code is put in `framework-minus-apex.jar`, as of http://ag/9145619. diff --git a/apex/jobscheduler/framework/Android.bp b/apex/jobscheduler/framework/Android.bp index 3902aa212e32..98bbe8243183 100644 --- a/apex/jobscheduler/framework/Android.bp +++ b/apex/jobscheduler/framework/Android.bp @@ -11,7 +11,7 @@ filegroup { } java_library { - name: "jobscheduler-framework", + name: "framework-jobscheduler", installable: false, compile_dex: true, sdk_version: "core_platform", diff --git a/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java b/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java index f3ec5e5752a0..3835d93ebeb9 100644 --- a/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java +++ b/apex/jobscheduler/framework/java/android/app/job/JobSchedulerFrameworkInitializer.java @@ -21,6 +21,7 @@ import android.app.SystemServiceRegistry; import android.content.Context; import android.os.DeviceIdleManager; import android.os.IDeviceIdleController; +import android.os.PowerWhitelistManager; /** * Class holding initialization code for the job scheduler module. @@ -48,5 +49,8 @@ public class JobSchedulerFrameworkInitializer { Context.DEVICE_IDLE_CONTROLLER, DeviceIdleManager.class, (context, b) -> new DeviceIdleManager( context, IDeviceIdleController.Stub.asInterface(b))); + SystemServiceRegistry.registerContextAwareService( + Context.POWER_WHITELIST_MANAGER, PowerWhitelistManager.class, + PowerWhitelistManager::new); } } diff --git a/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java new file mode 100644 index 000000000000..06ed52d7f586 --- /dev/null +++ b/apex/jobscheduler/framework/java/android/os/PowerWhitelistManager.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 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.os; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.annotation.SystemService; +import android.annotation.TestApi; +import android.content.Context; + +/** + * Interface to access and modify the power save whitelist. + * + * @hide + */ +@SystemApi +@TestApi +@SystemService(Context.POWER_WHITELIST_MANAGER) +public class PowerWhitelistManager { + private final Context mContext; + + /** + * @hide + */ + public PowerWhitelistManager(@NonNull Context context) { + mContext = context; + } +} diff --git a/apex/jobscheduler/service/Android.bp b/apex/jobscheduler/service/Android.bp index ca6dc45a356a..c9d9d6c7d87a 100644 --- a/apex/jobscheduler/service/Android.bp +++ b/apex/jobscheduler/service/Android.bp @@ -1,7 +1,7 @@ // Job Scheduler Service jar, which will eventually be put in the jobscheduler mainline apex. -// jobscheduler-service needs to be added to PRODUCT_SYSTEM_SERVER_JARS. +// service-jobscheduler needs to be added to PRODUCT_SYSTEM_SERVER_JARS. java_library { - name: "jobscheduler-service", + name: "service-jobscheduler", installable: true, srcs: [ diff --git a/apex/statsd/service/Android.bp b/apex/statsd/service/Android.bp index 786e8b0260f8..f71d74fa03ff 100644 --- a/apex/statsd/service/Android.bp +++ b/apex/statsd/service/Android.bp @@ -1,8 +1,8 @@ // Statsd Service jar, which will eventually be put in the statsd mainline apex. -// statsd-service needs to be added to PRODUCT_SYSTEM_SERVER_JARS. +// service-statsd needs to be added to PRODUCT_SYSTEM_SERVER_JARS. // This jar will contain StatsCompanionService java_library { - name: "statsd-service", + name: "service-statsd", installable: true, srcs: [ @@ -13,4 +13,4 @@ java_library { "framework", "services.core", ], -}
\ No newline at end of file +} diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java index 8a00c8318d58..a6cc06fad7eb 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java @@ -2076,6 +2076,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private void pullDangerousPermissionState(long elapsedNanos, final long wallClockNanos, List<StatsLogEventWrapper> pulledData) { long token = Binder.clearCallingIdentity(); + Set<Integer> reportedUids = new HashSet<>(); try { PackageManager pm = mContext.getPackageManager(); @@ -2096,6 +2097,12 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { continue; } + if (reportedUids.contains(pkg.applicationInfo.uid)) { + // do not report same uid twice + continue; + } + reportedUids.add(pkg.applicationInfo.uid); + int numPerms = pkg.requestedPermissions.length; for (int permNum = 0; permNum < numPerms; permNum++) { String permName = pkg.requestedPermissions[permNum]; @@ -2120,7 +2127,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { e.writeString(permName); e.writeInt(pkg.applicationInfo.uid); - e.writeString(pkg.packageName); + e.writeString(null); e.writeBoolean((pkg.requestedPermissionsFlags[permNum] & REQUESTED_PERMISSION_GRANTED) != 0); e.writeInt(permissionFlags); diff --git a/api/current.txt b/api/current.txt index 1728c53ec720..f1c03a4e576d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -2955,7 +2955,6 @@ package android.accessibilityservice { field public static final int FEEDBACK_SPOKEN = 1; // 0x1 field public static final int FEEDBACK_VISUAL = 8; // 0x8 field public static final int FLAG_ENABLE_ACCESSIBILITY_VOLUME = 128; // 0x80 - field public static final int FLAG_HANDLE_SHORTCUT = 2048; // 0x800 field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2 field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10 field public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 256; // 0x100 @@ -4760,18 +4759,18 @@ package android.app { field public static final int VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION = 3; // 0x3 } - public class ExpandableListActivity extends android.app.Activity implements android.widget.ExpandableListView.OnChildClickListener android.widget.ExpandableListView.OnGroupCollapseListener android.widget.ExpandableListView.OnGroupExpandListener android.view.View.OnCreateContextMenuListener { - ctor public ExpandableListActivity(); - method public android.widget.ExpandableListAdapter getExpandableListAdapter(); - method public android.widget.ExpandableListView getExpandableListView(); - method public long getSelectedId(); - method public long getSelectedPosition(); - method public boolean onChildClick(android.widget.ExpandableListView, android.view.View, int, int, long); - method public void onGroupCollapse(int); - method public void onGroupExpand(int); - method public void setListAdapter(android.widget.ExpandableListAdapter); - method public boolean setSelectedChild(int, int, boolean); - method public void setSelectedGroup(int); + @Deprecated public class ExpandableListActivity extends android.app.Activity implements android.widget.ExpandableListView.OnChildClickListener android.widget.ExpandableListView.OnGroupCollapseListener android.widget.ExpandableListView.OnGroupExpandListener android.view.View.OnCreateContextMenuListener { + ctor @Deprecated public ExpandableListActivity(); + method @Deprecated public android.widget.ExpandableListAdapter getExpandableListAdapter(); + method @Deprecated public android.widget.ExpandableListView getExpandableListView(); + method @Deprecated public long getSelectedId(); + method @Deprecated public long getSelectedPosition(); + method @Deprecated public boolean onChildClick(android.widget.ExpandableListView, android.view.View, int, int, long); + method @Deprecated public void onGroupCollapse(int); + method @Deprecated public void onGroupExpand(int); + method @Deprecated public void setListAdapter(android.widget.ExpandableListAdapter); + method @Deprecated public boolean setSelectedChild(int, int, boolean); + method @Deprecated public void setSelectedGroup(int); } @Deprecated public class Fragment implements android.content.ComponentCallbacks2 android.view.View.OnCreateContextMenuListener { @@ -5213,40 +5212,40 @@ package android.app { method @Deprecated public void onKeyguardExitResult(boolean); } - public abstract class LauncherActivity extends android.app.ListActivity { - ctor public LauncherActivity(); - method protected android.content.Intent getTargetIntent(); - method protected android.content.Intent intentForPosition(int); - method protected android.app.LauncherActivity.ListItem itemForPosition(int); - method public java.util.List<android.app.LauncherActivity.ListItem> makeListItems(); - method protected java.util.List<android.content.pm.ResolveInfo> onQueryPackageManager(android.content.Intent); - method protected void onSetContentView(); + @Deprecated public abstract class LauncherActivity extends android.app.ListActivity { + ctor @Deprecated public LauncherActivity(); + method @Deprecated protected android.content.Intent getTargetIntent(); + method @Deprecated protected android.content.Intent intentForPosition(int); + method @Deprecated protected android.app.LauncherActivity.ListItem itemForPosition(int); + method @Deprecated public java.util.List<android.app.LauncherActivity.ListItem> makeListItems(); + method @Deprecated protected java.util.List<android.content.pm.ResolveInfo> onQueryPackageManager(android.content.Intent); + method @Deprecated protected void onSetContentView(); } - public class LauncherActivity.IconResizer { - ctor public LauncherActivity.IconResizer(); - method public android.graphics.drawable.Drawable createIconThumbnail(android.graphics.drawable.Drawable); + @Deprecated public class LauncherActivity.IconResizer { + ctor @Deprecated public LauncherActivity.IconResizer(); + method @Deprecated public android.graphics.drawable.Drawable createIconThumbnail(android.graphics.drawable.Drawable); } - public static class LauncherActivity.ListItem { - ctor public LauncherActivity.ListItem(); - field public String className; - field public android.os.Bundle extras; - field public android.graphics.drawable.Drawable icon; - field public CharSequence label; - field public String packageName; - field public android.content.pm.ResolveInfo resolveInfo; + @Deprecated public static class LauncherActivity.ListItem { + ctor @Deprecated public LauncherActivity.ListItem(); + field @Deprecated public String className; + field @Deprecated public android.os.Bundle extras; + field @Deprecated public android.graphics.drawable.Drawable icon; + field @Deprecated public CharSequence label; + field @Deprecated public String packageName; + field @Deprecated public android.content.pm.ResolveInfo resolveInfo; } - public class ListActivity extends android.app.Activity { - ctor public ListActivity(); - method public android.widget.ListAdapter getListAdapter(); - method public android.widget.ListView getListView(); - method public long getSelectedItemId(); - method public int getSelectedItemPosition(); - method protected void onListItemClick(android.widget.ListView, android.view.View, int, long); - method public void setListAdapter(android.widget.ListAdapter); - method public void setSelection(int); + @Deprecated public class ListActivity extends android.app.Activity { + ctor @Deprecated public ListActivity(); + method @Deprecated public android.widget.ListAdapter getListAdapter(); + method @Deprecated public android.widget.ListView getListView(); + method @Deprecated public long getSelectedItemId(); + method @Deprecated public int getSelectedItemPosition(); + method @Deprecated protected void onListItemClick(android.widget.ListView, android.view.View, int, long); + method @Deprecated public void setListAdapter(android.widget.ListAdapter); + method @Deprecated public void setSelection(int); } @Deprecated public class ListFragment extends android.app.Fragment { @@ -5616,6 +5615,7 @@ package android.app { method @Deprecated public android.app.Notification.Builder setDefaults(int); method @NonNull public android.app.Notification.Builder setDeleteIntent(android.app.PendingIntent); method @NonNull public android.app.Notification.Builder setExtras(android.os.Bundle); + method @NonNull public android.app.Notification.Builder setFlag(int, boolean); method @NonNull public android.app.Notification.Builder setFullScreenIntent(android.app.PendingIntent, boolean); method @NonNull public android.app.Notification.Builder setGroup(String); method @NonNull public android.app.Notification.Builder setGroupAlertBehavior(int); @@ -9927,6 +9927,7 @@ package android.content { field public static final String ALARM_SERVICE = "alarm"; field public static final String APPWIDGET_SERVICE = "appwidget"; field public static final String APP_OPS_SERVICE = "appops"; + field public static final String APP_SEARCH_SERVICE = "app_search"; field public static final String AUDIO_SERVICE = "audio"; field public static final String BATTERY_SERVICE = "batterymanager"; field public static final int BIND_ABOVE_CLIENT = 8; // 0x8 @@ -29164,14 +29165,17 @@ package android.net { } public class ProxyInfo implements android.os.Parcelable { + ctor public ProxyInfo(@Nullable android.net.ProxyInfo); method public static android.net.ProxyInfo buildDirectProxy(String, int); method public static android.net.ProxyInfo buildDirectProxy(String, int, java.util.List<java.lang.String>); method public static android.net.ProxyInfo buildPacProxy(android.net.Uri); + method @NonNull public static android.net.ProxyInfo buildPacProxy(@NonNull android.net.Uri, int); method public int describeContents(); method public String[] getExclusionList(); method public String getHost(); method public android.net.Uri getPacFileUrl(); method public int getPort(); + method public boolean isValid(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.ProxyInfo> CREATOR; } @@ -30058,9 +30062,9 @@ package android.net.wifi { method @Deprecated public int addNetwork(android.net.wifi.WifiConfiguration); method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public int addNetworkSuggestions(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>); method public void addOrUpdatePasspointConfiguration(android.net.wifi.hotspot2.PasspointConfiguration); - method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void addScanResultsListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.ScanResultsListener); method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE}) public void addSuggestionConnectionStatusListener(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.SuggestionConnectionStatusListener); - method public static int calculateSignalLevel(int, int); + method @Deprecated public static int calculateSignalLevel(int, int); + method public int calculateSignalLevel(int); method @Deprecated public void cancelWps(android.net.wifi.WifiManager.WpsCallback); method public static int compareSignalLevel(int, int); method public android.net.wifi.WifiManager.MulticastLock createMulticastLock(String); @@ -30073,6 +30077,7 @@ package android.net.wifi { method public android.net.wifi.WifiInfo getConnectionInfo(); method public android.net.DhcpInfo getDhcpInfo(); method public int getMaxNumberOfNetworkSuggestionsPerApp(); + method public int getMaxSignalLevel(); method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public java.util.List<android.net.wifi.WifiNetworkSuggestion> getNetworkSuggestions(); method @Deprecated @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", "android.permission.NETWORK_SETUP_WIZARD"}) public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations(); method public java.util.List<android.net.wifi.ScanResult> getScanResults(); @@ -30093,10 +30098,10 @@ package android.net.wifi { method @Deprecated public boolean pingSupplicant(); method @Deprecated public boolean reassociate(); method @Deprecated public boolean reconnect(); + method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void registerScanResultsCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.ScanResultsCallback); method @Deprecated public boolean removeNetwork(int); method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public int removeNetworkSuggestions(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>); method @Deprecated @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", "android.permission.NETWORK_CARRIER_PROVISIONING"}) public void removePasspointConfiguration(String); - method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void removeScanResultsListener(@NonNull android.net.wifi.WifiManager.ScanResultsListener); method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void removeSuggestionConnectionStatusListener(@NonNull android.net.wifi.WifiManager.SuggestionConnectionStatusListener); method @Deprecated public boolean saveConfiguration(); method public void setTdlsEnabled(java.net.InetAddress, boolean); @@ -30105,6 +30110,7 @@ package android.net.wifi { method @RequiresPermission(allOf={android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void startLocalOnlyHotspot(android.net.wifi.WifiManager.LocalOnlyHotspotCallback, @Nullable android.os.Handler); method @Deprecated public boolean startScan(); method @Deprecated public void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback); + method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void unregisterScanResultsCallback(@NonNull android.net.wifi.WifiManager.ScanResultsCallback); method @Deprecated public int updateNetwork(android.net.wifi.WifiConfiguration); field public static final String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK"; field public static final String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE"; @@ -30178,8 +30184,9 @@ package android.net.wifi { method public void setReferenceCounted(boolean); } - public static interface WifiManager.ScanResultsListener { - method public void onScanResultsAvailable(); + public abstract static class WifiManager.ScanResultsCallback { + ctor public WifiManager.ScanResultsCallback(); + method public abstract void onScanResultsAvailable(); } public static interface WifiManager.SuggestionConnectionStatusListener { @@ -34823,8 +34830,8 @@ package android.os { } public final class FileUtils { - method public static void closeQuietly(@Nullable AutoCloseable); - method public static void closeQuietly(@Nullable java.io.FileDescriptor); + method @Deprecated public static void closeQuietly(@Nullable AutoCloseable); + method @Deprecated public static void closeQuietly(@Nullable java.io.FileDescriptor); method public static long copy(@NonNull java.io.InputStream, @NonNull java.io.OutputStream) throws java.io.IOException; method public static long copy(@NonNull java.io.InputStream, @NonNull java.io.OutputStream, @Nullable android.os.CancellationSignal, @Nullable java.util.concurrent.Executor, @Nullable android.os.FileUtils.ProgressListener) throws java.io.IOException; method public static long copy(@NonNull java.io.FileDescriptor, @NonNull java.io.FileDescriptor) throws java.io.IOException; @@ -34961,7 +34968,7 @@ package android.os { method @Nullable public static android.os.Looper myLooper(); method @NonNull public static android.os.MessageQueue myQueue(); method public static void prepare(); - method public static void prepareMainLooper(); + method @Deprecated public static void prepareMainLooper(); method public void quit(); method public void quitSafely(); method public void setMessageLogging(@Nullable android.util.Printer); @@ -35908,6 +35915,7 @@ package android.os.storage { method public boolean isAllocationSupported(@NonNull java.io.FileDescriptor); method public boolean isCacheBehaviorGroup(java.io.File) throws java.io.IOException; method public boolean isCacheBehaviorTombstone(java.io.File) throws java.io.IOException; + method public boolean isCheckpointSupported(); method public boolean isEncrypted(java.io.File); method public boolean isObbMounted(String); method public boolean mountObb(String, String, android.os.storage.OnObbStateChangeListener); @@ -44412,6 +44420,7 @@ package android.telephony { field public static final String KEY_CALL_BARRING_VISIBILITY_BOOL = "call_barring_visibility_bool"; field public static final String KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY = "call_forwarding_blocks_while_roaming_string_array"; field public static final String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL = "carrier_allow_turnoff_ims_bool"; + field public static final String KEY_CARRIER_APP_REQUIRED_DURING_SIM_SETUP_BOOL = "carrier_app_required_during_setup_bool"; field public static final String KEY_CARRIER_CALL_SCREENING_APP_STRING = "call_screening_app"; field public static final String KEY_CARRIER_CONFIG_VERSION_STRING = "carrier_config_version_string"; field public static final String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS = "carrier_data_call_permanent_failure_strings"; @@ -48897,12 +48906,12 @@ package android.util { method @Nullable public static java.util.List<java.lang.String> getTimeZoneIdsForCountryCode(@NonNull String); } - public class TimingLogger { - ctor public TimingLogger(String, String); - method public void addSplit(String); - method public void dumpToLog(); - method public void reset(String, String); - method public void reset(); + @Deprecated public class TimingLogger { + ctor @Deprecated public TimingLogger(String, String); + method @Deprecated public void addSplit(String); + method @Deprecated public void dumpToLog(); + method @Deprecated public void reset(String, String); + method @Deprecated public void reset(); } public class TypedValue { @@ -50815,7 +50824,7 @@ package android.view { method public final int getScrollY(); method @android.view.ViewDebug.ExportedProperty(category="drawing") @ColorInt public int getSolidColor(); method @LayoutRes public int getSourceLayoutResId(); - method @android.view.ViewDebug.ExportedProperty(category="accessibility") @Nullable public CharSequence getStateDescription(); + method @android.view.ViewDebug.ExportedProperty(category="accessibility") @Nullable public final CharSequence getStateDescription(); method public android.animation.StateListAnimator getStateListAnimator(); method protected int getSuggestedMinimumHeight(); method protected int getSuggestedMinimumWidth(); @@ -53448,6 +53457,23 @@ package android.view.contentcapture { } +package android.view.inline { + + public final class InlinePresentationSpec implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.util.Size getMaxSize(); + method @NonNull public android.util.Size getMinSize(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.view.inline.InlinePresentationSpec> CREATOR; + } + + public static final class InlinePresentationSpec.Builder { + ctor public InlinePresentationSpec.Builder(@NonNull android.util.Size, @NonNull android.util.Size); + method @NonNull public android.view.inline.InlinePresentationSpec build(); + } + +} + package android.view.inputmethod { public class BaseInputConnection implements android.view.inputmethod.InputConnection { @@ -53611,6 +53637,48 @@ package android.view.inputmethod { field public int token; } + public final class InlineSuggestion implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.view.inputmethod.InlineSuggestionInfo getInfo(); + method public void inflate(@NonNull android.content.Context, @NonNull android.util.Size, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.View>); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.InlineSuggestion> CREATOR; + } + + public final class InlineSuggestionInfo implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public String[] getAutofillHints(); + method @NonNull public android.view.inline.InlinePresentationSpec getPresentationSpec(); + method @NonNull public String getSource(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.InlineSuggestionInfo> CREATOR; + field public static final String SOURCE_AUTOFILL = "android:autofill"; + field public static final String SOURCE_PLATFORM = "android:platform"; + } + + public final class InlineSuggestionsRequest implements android.os.Parcelable { + method public int describeContents(); + method public int getMaxSuggestionCount(); + method @NonNull public java.util.List<android.view.inline.InlinePresentationSpec> getPresentationSpecs(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.InlineSuggestionsRequest> CREATOR; + field public static final int SUGGESTION_COUNT_UNLIMITED = 2147483647; // 0x7fffffff + } + + public static final class InlineSuggestionsRequest.Builder { + ctor public InlineSuggestionsRequest.Builder(@NonNull java.util.List<android.view.inline.InlinePresentationSpec>); + method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder addPresentationSpecs(@NonNull android.view.inline.InlinePresentationSpec); + method @NonNull public android.view.inputmethod.InlineSuggestionsRequest build(); + method @NonNull public android.view.inputmethod.InlineSuggestionsRequest.Builder setMaxSuggestionCount(int); + } + + public final class InlineSuggestionsResponse implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public java.util.List<android.view.inputmethod.InlineSuggestion> getInlineSuggestions(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.InlineSuggestionsResponse> CREATOR; + } + public final class InputBinding implements android.os.Parcelable { ctor public InputBinding(android.view.inputmethod.InputConnection, android.os.IBinder, int, int); ctor public InputBinding(android.view.inputmethod.InputConnection, android.view.inputmethod.InputBinding); @@ -57052,7 +57120,7 @@ package android.widget { method public int describeContents(); method public int getLayoutId(); method public String getPackage(); - method public boolean onLoadClass(Class); + method @Deprecated public boolean onLoadClass(Class); method public void reapply(android.content.Context, android.view.View); method public void removeAllViews(int); method public void setAccessibilityTraversalAfter(int, int); diff --git a/api/system-current.txt b/api/system-current.txt index f74b74318180..adfda2fe527a 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -604,6 +604,10 @@ package android.app { method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean); } + public class SearchManager implements android.content.DialogInterface.OnCancelListener android.content.DialogInterface.OnDismissListener { + method public void launchAssist(@Nullable android.os.Bundle); + } + public final class StatsManager { method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void addConfig(long, byte[]) throws android.app.StatsManager.StatsUnavailableException; method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean addConfiguration(long, byte[]); @@ -1356,7 +1360,23 @@ package android.bluetooth { method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setPriority(android.bluetooth.BluetoothDevice, int); } + public final class BluetoothPan implements android.bluetooth.BluetoothProfile { + method protected void finalize(); + method @NonNull public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(); + method public int getConnectionState(@Nullable android.bluetooth.BluetoothDevice); + method public boolean isTetheringOn(); + method public void setBluetoothTethering(boolean); + field public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED"; + field public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE"; + field public static final int LOCAL_NAP_ROLE = 1; // 0x1 + field public static final int LOCAL_PANU_ROLE = 2; // 0x2 + field public static final int PAN_ROLE_NONE = 0; // 0x0 + field public static final int REMOTE_NAP_ROLE = 1; // 0x1 + field public static final int REMOTE_PANU_ROLE = 2; // 0x2 + } + public interface BluetoothProfile { + field public static final int PAN = 5; // 0x5 field public static final int PRIORITY_OFF = 0; // 0x0 field public static final int PRIORITY_ON = 100; // 0x64 } @@ -4183,6 +4203,33 @@ package android.net { method public void onUpstreamChanged(@Nullable android.net.Network); } + public final class IpConfiguration implements android.os.Parcelable { + ctor public IpConfiguration(); + ctor public IpConfiguration(@NonNull android.net.IpConfiguration); + method @Nullable public android.net.ProxyInfo getHttpProxy(); + method @NonNull public android.net.IpConfiguration.IpAssignment getIpAssignment(); + method @NonNull public android.net.IpConfiguration.ProxySettings getProxySettings(); + method @Nullable public android.net.StaticIpConfiguration getStaticIpConfiguration(); + method public void setHttpProxy(@Nullable android.net.ProxyInfo); + method public void setIpAssignment(@NonNull android.net.IpConfiguration.IpAssignment); + method public void setProxySettings(@NonNull android.net.IpConfiguration.ProxySettings); + method public void setStaticIpConfiguration(@Nullable android.net.StaticIpConfiguration); + field @NonNull public static final android.os.Parcelable.Creator<android.net.IpConfiguration> CREATOR; + } + + public enum IpConfiguration.IpAssignment { + enum_constant public static final android.net.IpConfiguration.IpAssignment DHCP; + enum_constant public static final android.net.IpConfiguration.IpAssignment STATIC; + enum_constant public static final android.net.IpConfiguration.IpAssignment UNASSIGNED; + } + + public enum IpConfiguration.ProxySettings { + enum_constant public static final android.net.IpConfiguration.ProxySettings NONE; + enum_constant public static final android.net.IpConfiguration.ProxySettings PAC; + enum_constant public static final android.net.IpConfiguration.ProxySettings STATIC; + enum_constant public static final android.net.IpConfiguration.ProxySettings UNASSIGNED; + } + public final class IpPrefix implements android.os.Parcelable { ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int); ctor public IpPrefix(@NonNull String); @@ -4255,6 +4302,7 @@ package android.net { public class NetworkKey implements android.os.Parcelable { ctor public NetworkKey(android.net.WifiKey); + method @Nullable public static android.net.NetworkKey createFromScanResult(@Nullable android.net.wifi.ScanResult); method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkKey> CREATOR; @@ -4277,16 +4325,23 @@ package android.net { method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public boolean clearScores() throws java.lang.SecurityException; method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public void disableScoring() throws java.lang.SecurityException; method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public String getActiveScorerPackage(); + method @RequiresPermission("android.permission.REQUEST_NETWORK_SCORES") public void registerNetworkScoreCallback(int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.NetworkScoreManager.NetworkScoreCallback) throws java.lang.SecurityException; + method @RequiresPermission("android.permission.REQUEST_NETWORK_SCORES") public boolean requestScores(@NonNull android.net.NetworkKey[]) throws java.lang.SecurityException; method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public boolean setActiveScorer(String) throws java.lang.SecurityException; - method @RequiresPermission(android.Manifest.permission.SCORE_NETWORKS) public boolean updateScores(android.net.ScoredNetwork[]) throws java.lang.SecurityException; - field public static final String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE"; + method @RequiresPermission(android.Manifest.permission.SCORE_NETWORKS) public boolean updateScores(@NonNull android.net.ScoredNetwork[]) throws java.lang.SecurityException; + field @Deprecated public static final String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE"; field public static final String ACTION_CUSTOM_ENABLE = "android.net.scoring.CUSTOM_ENABLE"; field public static final String ACTION_RECOMMEND_NETWORKS = "android.net.action.RECOMMEND_NETWORKS"; field public static final String ACTION_SCORER_CHANGED = "android.net.scoring.SCORER_CHANGED"; - field public static final String ACTION_SCORE_NETWORKS = "android.net.scoring.SCORE_NETWORKS"; - field public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore"; + field @Deprecated public static final String ACTION_SCORE_NETWORKS = "android.net.scoring.SCORE_NETWORKS"; + field @Deprecated public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore"; field public static final String EXTRA_NEW_SCORER = "newScorer"; - field public static final String EXTRA_PACKAGE_NAME = "packageName"; + field @Deprecated public static final String EXTRA_PACKAGE_NAME = "packageName"; + } + + public static interface NetworkScoreManager.NetworkScoreCallback { + method public void clearScores(); + method public void updateScores(@NonNull java.util.List<android.net.ScoredNetwork>); } public class NetworkStack { @@ -4408,6 +4463,258 @@ package android.net.apf { } +package android.net.eap { + + public final class EapSessionConfig { + } + + public static final class EapSessionConfig.Builder { + ctor public EapSessionConfig.Builder(); + method @NonNull public android.net.eap.EapSessionConfig build(); + method @NonNull public android.net.eap.EapSessionConfig.Builder setEapAkaConfig(int, int); + method @NonNull public android.net.eap.EapSessionConfig.Builder setEapAkaPrimeConfig(int, int, @NonNull String, boolean); + method @NonNull public android.net.eap.EapSessionConfig.Builder setEapIdentity(@NonNull byte[]); + method @NonNull public android.net.eap.EapSessionConfig.Builder setEapMsChapV2Config(@NonNull String, @NonNull String); + method @NonNull public android.net.eap.EapSessionConfig.Builder setEapSimConfig(int, int); + } + + public static class EapSessionConfig.EapAkaConfig extends android.net.eap.EapSessionConfig.EapUiccConfig { + } + + public static class EapSessionConfig.EapAkaPrimeConfig extends android.net.eap.EapSessionConfig.EapAkaConfig { + method public boolean allowsMismatchedNetworkNames(); + method @NonNull public String getNetworkName(); + } + + public abstract static class EapSessionConfig.EapMethodConfig { + method public int getMethodType(); + } + + public static class EapSessionConfig.EapMsChapV2Config extends android.net.eap.EapSessionConfig.EapMethodConfig { + method @NonNull public String getPassword(); + method @NonNull public String getUsername(); + } + + public static class EapSessionConfig.EapSimConfig extends android.net.eap.EapSessionConfig.EapUiccConfig { + } + + public abstract static class EapSessionConfig.EapUiccConfig extends android.net.eap.EapSessionConfig.EapMethodConfig { + method public int getAppType(); + method public int getSubId(); + } + +} + +package android.net.ipsec.ike { + + public final class ChildSaProposal extends android.net.ipsec.ike.SaProposal { + } + + public static final class ChildSaProposal.Builder { + ctor public ChildSaProposal.Builder(); + method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addDhGroup(int); + method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addEncryptionAlgorithm(int, int); + method @NonNull public android.net.ipsec.ike.ChildSaProposal.Builder addIntegrityAlgorithm(int); + method @NonNull public android.net.ipsec.ike.ChildSaProposal build(); + } + + public interface ChildSessionCallback { + method public void onClosed(); + method public void onClosedExceptionally(@NonNull android.net.ipsec.ike.exceptions.IkeException); + method public void onIpSecTransformCreated(@NonNull android.net.IpSecTransform, int); + method public void onIpSecTransformDeleted(@NonNull android.net.IpSecTransform, int); + method public void onOpened(@NonNull android.net.ipsec.ike.ChildSessionConfiguration); + } + + public final class ChildSessionConfiguration { + method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getInboundTrafficSelectors(); + method @NonNull public java.util.List<android.net.LinkAddress> getInternalAddresses(); + method @NonNull public java.util.List<java.net.InetAddress> getInternalDhcpServers(); + method @NonNull public java.util.List<java.net.InetAddress> getInternalDnsServers(); + method @NonNull public java.util.List<android.net.LinkAddress> getInternalSubnets(); + method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getOutboundTrafficSelectors(); + } + + public abstract class ChildSessionOptions { + } + + public class IkeFqdnIdentification extends android.net.ipsec.ike.IkeIdentification { + ctor public IkeFqdnIdentification(@NonNull String); + field @NonNull public final String fqdn; + } + + public abstract class IkeIdentification { + } + + public final class IkeIpv4AddrIdentification extends android.net.ipsec.ike.IkeIdentification { + ctor public IkeIpv4AddrIdentification(@NonNull java.net.Inet4Address); + field @NonNull public final java.net.Inet4Address ipv4Address; + } + + public class IkeIpv6AddrIdentification extends android.net.ipsec.ike.IkeIdentification { + ctor public IkeIpv6AddrIdentification(@NonNull java.net.Inet6Address); + field @NonNull public final java.net.Inet6Address ipv6Address; + } + + public final class IkeKeyIdIdentification extends android.net.ipsec.ike.IkeIdentification { + ctor public IkeKeyIdIdentification(@NonNull byte[]); + field @NonNull public final byte[] keyId; + } + + public final class IkeRfc822AddrIdentification extends android.net.ipsec.ike.IkeIdentification { + ctor public IkeRfc822AddrIdentification(@NonNull String); + field @NonNull public final String rfc822Name; + } + + public final class IkeSaProposal extends android.net.ipsec.ike.SaProposal { + method @NonNull public java.util.List<java.lang.Integer> getPseudorandomFunctions(); + } + + public static final class IkeSaProposal.Builder { + ctor public IkeSaProposal.Builder(); + method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addDhGroup(int); + method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addEncryptionAlgorithm(int, int); + method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addIntegrityAlgorithm(int); + method @NonNull public android.net.ipsec.ike.IkeSaProposal.Builder addPseudorandomFunction(int); + method @NonNull public android.net.ipsec.ike.IkeSaProposal build(); + } + + public final class IkeSession implements java.lang.AutoCloseable { + ctor public IkeSession(@NonNull android.content.Context, @NonNull android.net.ipsec.ike.IkeSessionOptions, @NonNull android.net.ipsec.ike.ChildSessionOptions, @NonNull java.util.concurrent.Executor, @NonNull android.net.ipsec.ike.IkeSessionCallback, @NonNull android.net.ipsec.ike.ChildSessionCallback); + method public void close(); + method public void closeChildSession(@NonNull android.net.ipsec.ike.ChildSessionCallback); + method public void kill(); + method public void openChildSession(@NonNull android.net.ipsec.ike.ChildSessionOptions, @NonNull android.net.ipsec.ike.ChildSessionCallback); + } + + public interface IkeSessionCallback { + method public void onClosed(); + method public void onClosedExceptionally(@NonNull android.net.ipsec.ike.exceptions.IkeException); + method public void onError(@NonNull android.net.ipsec.ike.exceptions.IkeProtocolException); + method public void onOpened(@NonNull android.net.ipsec.ike.IkeSessionConfiguration); + } + + public final class IkeSessionConfiguration { + ctor public IkeSessionConfiguration(); + method @NonNull public String getRemoteApplicationVersion(); + method public boolean isIkeExtensionEnabled(int); + field public static final int EXTENSION_TYPE_FRAGMENTATION = 1; // 0x1 + field public static final int EXTENSION_TYPE_MOBIKE = 2; // 0x2 + } + + public final class IkeSessionOptions { + } + + public static final class IkeSessionOptions.Builder { + ctor public IkeSessionOptions.Builder(); + method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder addSaProposal(@NonNull android.net.ipsec.ike.IkeSaProposal); + method @NonNull public android.net.ipsec.ike.IkeSessionOptions build(); + method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setAuthDigitalSignature(@NonNull java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.security.PrivateKey); + method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setAuthDigitalSignature(@NonNull java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.util.List<java.security.cert.X509Certificate>, @NonNull java.security.PrivateKey); + method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setAuthEap(@NonNull java.security.cert.X509Certificate, @NonNull android.net.eap.EapSessionConfig); + method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setAuthPsk(@NonNull byte[]); + method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setLocalIdentification(@NonNull android.net.ipsec.ike.IkeIdentification); + method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setRemoteIdentification(@NonNull android.net.ipsec.ike.IkeIdentification); + method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setServerAddress(@NonNull java.net.InetAddress); + method @NonNull public android.net.ipsec.ike.IkeSessionOptions.Builder setUdpEncapsulationSocket(@NonNull android.net.IpSecManager.UdpEncapsulationSocket); + } + + public final class IkeTrafficSelector { + ctor public IkeTrafficSelector(int, int, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress); + field public final int endPort; + field @NonNull public final java.net.InetAddress endingAddress; + field public final int startPort; + field @NonNull public final java.net.InetAddress startingAddress; + } + + public abstract class SaProposal { + method @NonNull public java.util.List<java.lang.Integer> getDhGroups(); + method @NonNull public java.util.List<android.util.Pair<java.lang.Integer,java.lang.Integer>> getEncryptionAlgorithms(); + method @NonNull public java.util.List<java.lang.Integer> getIntegrityAlgorithms(); + field public static final int DH_GROUP_1024_BIT_MODP = 2; // 0x2 + field public static final int DH_GROUP_2048_BIT_MODP = 14; // 0xe + field public static final int DH_GROUP_NONE = 0; // 0x0 + field public static final int ENCRYPTION_ALGORITHM_3DES = 3; // 0x3 + field public static final int ENCRYPTION_ALGORITHM_AES_CBC = 12; // 0xc + field public static final int ENCRYPTION_ALGORITHM_AES_GCM_12 = 19; // 0x13 + field public static final int ENCRYPTION_ALGORITHM_AES_GCM_16 = 20; // 0x14 + field public static final int ENCRYPTION_ALGORITHM_AES_GCM_8 = 18; // 0x12 + field public static final int INTEGRITY_ALGORITHM_AES_XCBC_96 = 5; // 0x5 + field public static final int INTEGRITY_ALGORITHM_HMAC_SHA1_96 = 2; // 0x2 + field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_256_128 = 12; // 0xc + field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_384_192 = 13; // 0xd + field public static final int INTEGRITY_ALGORITHM_HMAC_SHA2_512_256 = 14; // 0xe + field public static final int INTEGRITY_ALGORITHM_NONE = 0; // 0x0 + field public static final int KEY_LEN_AES_128 = 128; // 0x80 + field public static final int KEY_LEN_AES_192 = 192; // 0xc0 + field public static final int KEY_LEN_AES_256 = 256; // 0x100 + field public static final int KEY_LEN_UNUSED = 0; // 0x0 + field public static final int PSEUDORANDOM_FUNCTION_AES128_XCBC = 4; // 0x4 + field public static final int PSEUDORANDOM_FUNCTION_HMAC_SHA1 = 2; // 0x2 + } + + public final class TransportModeChildSessionOptions extends android.net.ipsec.ike.ChildSessionOptions { + } + + public static final class TransportModeChildSessionOptions.Builder { + ctor public TransportModeChildSessionOptions.Builder(); + method @NonNull public android.net.ipsec.ike.TransportModeChildSessionOptions.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector); + method @NonNull public android.net.ipsec.ike.TransportModeChildSessionOptions.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector); + method @NonNull public android.net.ipsec.ike.TransportModeChildSessionOptions.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal); + method @NonNull public android.net.ipsec.ike.TransportModeChildSessionOptions build(); + } + + public final class TunnelModeChildSessionOptions extends android.net.ipsec.ike.ChildSessionOptions { + } + + public static final class TunnelModeChildSessionOptions.Builder { + ctor public TunnelModeChildSessionOptions.Builder(); + method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector); + method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalAddressRequest(int); + method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalAddressRequest(@NonNull java.net.InetAddress, int); + method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalDhcpServerRequest(int); + method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalDhcpServerRequest(@NonNull java.net.InetAddress); + method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalDnsServerRequest(int); + method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalDnsServerRequest(@NonNull java.net.InetAddress); + method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addInternalSubnetRequest(int); + method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector); + method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal); + method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionOptions build(); + } + +} + +package android.net.ipsec.ike.exceptions { + + public abstract class IkeException extends java.lang.Exception { + } + + public final class IkeInternalException extends android.net.ipsec.ike.exceptions.IkeException { + } + + public abstract class IkeProtocolException extends android.net.ipsec.ike.exceptions.IkeException { + method @Nullable public byte[] getErrorData(); + method public int getErrorType(); + field public static final int ERROR_TYPE_AUTHENTICATION_FAILED = 24; // 0x18 + field public static final int ERROR_TYPE_CHILD_SA_NOT_FOUND = 44; // 0x2c + field public static final int ERROR_TYPE_FAILED_CP_REQUIRED = 37; // 0x25 + field public static final int ERROR_TYPE_INTERNAL_ADDRESS_FAILURE = 36; // 0x24 + field public static final int ERROR_TYPE_INVALID_IKE_SPI = 4; // 0x4 + field public static final int ERROR_TYPE_INVALID_KE_PAYLOAD = 17; // 0x11 + field public static final int ERROR_TYPE_INVALID_MAJOR_VERSION = 5; // 0x5 + field public static final int ERROR_TYPE_INVALID_MESSAGE_ID = 9; // 0x9 + field public static final int ERROR_TYPE_INVALID_SELECTORS = 39; // 0x27 + field public static final int ERROR_TYPE_INVALID_SYNTAX = 7; // 0x7 + field public static final int ERROR_TYPE_NO_ADDITIONAL_SAS = 35; // 0x23 + field public static final int ERROR_TYPE_NO_PROPOSAL_CHOSEN = 14; // 0xe + field public static final int ERROR_TYPE_SINGLE_PAIR_REQUIRED = 34; // 0x22 + field public static final int ERROR_TYPE_TEMPORARY_FAILURE = 43; // 0x2b + field public static final int ERROR_TYPE_TS_UNACCEPTABLE = 38; // 0x26 + field public static final int ERROR_TYPE_UNSUPPORTED_CRITICAL_PAYLOAD = 1; // 0x1 + } + +} + package android.net.metrics { public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event { @@ -4833,19 +5140,46 @@ package android.net.wifi { } @Deprecated public class WifiConfiguration implements android.os.Parcelable { + method @Deprecated public int getAuthType(); + method @Deprecated @NonNull public android.net.IpConfiguration.IpAssignment getIpAssignment(); + method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus getNetworkSelectionStatus(); + method @Deprecated @NonNull public String getPrintableSsid(); + method @Deprecated @NonNull public android.net.IpConfiguration.ProxySettings getProxySettings(); + method @Deprecated @Nullable public android.net.StaticIpConfiguration getStaticIpConfiguration(); method @Deprecated public boolean hasNoInternetAccess(); method @Deprecated public boolean isEphemeral(); + method @Deprecated public static boolean isMetered(@Nullable android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiInfo); method @Deprecated public boolean isNoInternetAccessExpected(); + method @Deprecated public void setIpConfiguration(@Nullable android.net.IpConfiguration); + method @Deprecated public void setProxy(@NonNull android.net.IpConfiguration.ProxySettings, @NonNull android.net.ProxyInfo); + field @Deprecated public static final int AP_BAND_2GHZ = 0; // 0x0 + field @Deprecated public static final int AP_BAND_5GHZ = 1; // 0x1 + field @Deprecated public static final int AP_BAND_ANY = -1; // 0xffffffff + field @Deprecated public static final int INVALID_NETWORK_ID = -1; // 0xffffffff + field @Deprecated public static final int METERED_OVERRIDE_METERED = 1; // 0x1 + field @Deprecated public static final int METERED_OVERRIDE_NONE = 0; // 0x0 + field @Deprecated public static final int METERED_OVERRIDE_NOT_METERED = 2; // 0x2 + field @Deprecated public static final int RANDOMIZATION_NONE = 0; // 0x0 + field @Deprecated public static final int RANDOMIZATION_PERSISTENT = 1; // 0x1 field @Deprecated public boolean allowAutojoin; + field @Deprecated public int apBand; field @Deprecated public int carrierId; field @Deprecated public String creatorName; field @Deprecated public int creatorUid; + field @Deprecated public boolean fromWifiNetworkSpecifier; + field @Deprecated public boolean fromWifiNetworkSuggestion; field @Deprecated public String lastUpdateName; field @Deprecated public int lastUpdateUid; + field @Deprecated public int macRandomizationSetting; field @Deprecated public boolean meteredHint; + field @Deprecated public int meteredOverride; field @Deprecated public int numAssociation; field @Deprecated public int numScorerOverride; field @Deprecated public int numScorerOverrideAndSwitchedNetwork; + field @Deprecated @NonNull public final android.net.wifi.WifiConfiguration.RecentFailure recentFailure; + field @Deprecated public boolean requirePMF; + field @Deprecated @Nullable public String saePasswordId; + field @Deprecated public boolean shared; field @Deprecated public boolean useExternalScores; } @@ -4853,6 +5187,53 @@ package android.net.wifi { field @Deprecated public static final int WPA2_PSK = 4; // 0x4 } + @Deprecated public static class WifiConfiguration.NetworkSelectionStatus { + method @Deprecated public int getDisableReasonCounter(int); + method @Deprecated public long getDisableTime(); + method @Deprecated public boolean getHasEverConnected(); + method @Deprecated @Nullable public static String getNetworkDisableReasonString(int); + method @Deprecated public int getNetworkSelectionDisableReason(); + method @Deprecated @NonNull public String getNetworkStatusString(); + method @Deprecated public boolean isNetworkEnabled(); + method @Deprecated public boolean isNetworkPermanentlyDisabled(); + field @Deprecated public static final int DISABLED_ASSOCIATION_REJECTION = 1; // 0x1 + field @Deprecated public static final int DISABLED_AUTHENTICATION_FAILURE = 2; // 0x2 + field @Deprecated public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 5; // 0x5 + field @Deprecated public static final int DISABLED_AUTHENTICATION_NO_SUBSCRIPTION = 9; // 0x9 + field @Deprecated public static final int DISABLED_BY_WIFI_MANAGER = 7; // 0x7 + field @Deprecated public static final int DISABLED_BY_WRONG_PASSWORD = 8; // 0x8 + field @Deprecated public static final int DISABLED_DHCP_FAILURE = 3; // 0x3 + field @Deprecated public static final int DISABLED_NO_INTERNET_PERMANENT = 6; // 0x6 + field @Deprecated public static final int DISABLED_NO_INTERNET_TEMPORARY = 4; // 0x4 + field @Deprecated public static final int NETWORK_SELECTION_DISABLED_MAX = 10; // 0xa + field @Deprecated public static final int NETWORK_SELECTION_ENABLE = 0; // 0x0 + } + + @Deprecated public static class WifiConfiguration.RecentFailure { + method @Deprecated public int getAssociationStatus(); + field @Deprecated public static final int NONE = 0; // 0x0 + field @Deprecated public static final int STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17; // 0x11 + } + + public class WifiEnterpriseConfig implements android.os.Parcelable { + method @Nullable public String[] getCaCertificateAliases(); + method @NonNull public String getCaPath(); + method @NonNull public String getClientCertificateAlias(); + method public int getOcsp(); + method public void setCaCertificateAliases(@Nullable String[]); + method public void setCaPath(@Nullable String); + method public void setClientCertificateAlias(@Nullable String); + method public void setOcsp(int); + field public static final int OCSP_NONE = 0; // 0x0 + field public static final int OCSP_REQUEST_CERT_STATUS = 1; // 0x1 + field public static final int OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS = 3; // 0x3 + field public static final int OCSP_REQUIRE_CERT_STATUS = 2; // 0x2 + } + + public class WifiFrameworkInitializer { + method public static void registerServiceWrappers(); + } + public class WifiInfo implements android.os.Parcelable { method @Nullable public String getAppPackageName(); method public double getRxSuccessRate(); @@ -5024,6 +5405,7 @@ package android.net.wifi { method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public java.util.List<java.lang.Integer> getAvailableChannels(int); method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean getScanResults(); method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public java.util.List<android.net.wifi.ScanResult> getSingleScanResults(); + method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setScanningEnabled(boolean); method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener); method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener, android.os.WorkSource); method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener); @@ -5489,6 +5871,17 @@ package android.os { method @NonNull public static java.io.File getVendorDirectory(); } + public class HidlMemory implements java.io.Closeable { + ctor public HidlMemory(@NonNull String, @IntRange(from=0) long, @Nullable android.os.NativeHandle); + method public void close() throws java.io.IOException; + method @NonNull public android.os.HidlMemory dup() throws java.io.IOException; + method protected void finalize(); + method @Nullable public android.os.NativeHandle getHandle(); + method @NonNull public String getName(); + method public long getSize(); + method @NonNull public android.os.NativeHandle releaseHandle(); + } + public class HidlSupport { method public static boolean deepEquals(Object, Object); method public static int deepHashCode(Object); @@ -5519,6 +5912,7 @@ package android.os { method public final void copyToInt8Array(long, byte[], int); method public final boolean getBool(long); method public final double getDouble(long); + method public final long getFieldHandle(long); method public final float getFloat(long); method public final short getInt16(long); method public final int getInt32(long); @@ -5533,6 +5927,7 @@ package android.os { method public final void putDoubleArray(long, double[]); method public final void putFloat(long, float); method public final void putFloatArray(long, float[]); + method public final void putHidlMemory(long, @NonNull android.os.HidlMemory); method public final void putInt16(long, short); method public final void putInt16Array(long, short[]); method public final void putInt32(long, int); @@ -5561,9 +5956,11 @@ package android.os { method public final double readDouble(); method public final java.util.ArrayList<java.lang.Double> readDoubleVector(); method public final android.os.HwBlob readEmbeddedBuffer(long, long, long, boolean); + method @NonNull @Nullable public final android.os.HidlMemory readEmbeddedHidlMemory(long, long, long); method @Nullable public final android.os.NativeHandle readEmbeddedNativeHandle(long, long); method public final float readFloat(); method public final java.util.ArrayList<java.lang.Float> readFloatVector(); + method @NonNull public final android.os.HidlMemory readHidlMemory(); method public final short readInt16(); method public final java.util.ArrayList<java.lang.Short> readInt16Vector(); method public final int readInt32(); @@ -5588,6 +5985,7 @@ package android.os { method public final void writeDoubleVector(java.util.ArrayList<java.lang.Double>); method public final void writeFloat(float); method public final void writeFloatVector(java.util.ArrayList<java.lang.Float>); + method public final void writeHidlMemory(@NonNull android.os.HidlMemory); method public final void writeInt16(short); method public final void writeInt16Vector(java.util.ArrayList<java.lang.Short>); method public final void writeInt32(int); @@ -5712,6 +6110,9 @@ package android.os { field public static final int USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS = 1; // 0x1 } + public class PowerWhitelistManager { + } + public class RecoverySystem { method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void cancelScheduledUpdate(android.content.Context) throws java.io.IOException; method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void installPackage(android.content.Context, java.io.File, boolean) throws java.io.IOException; @@ -6214,6 +6615,7 @@ package android.provider { method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getString(@NonNull String, @NonNull String, @Nullable String); method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener); method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String); + method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperties(@NonNull android.provider.DeviceConfig.Properties); method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(@NonNull String, @NonNull String, @Nullable String, boolean); field public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager"; field public static final String NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT = "activity_manager_native_boot"; @@ -6420,7 +6822,7 @@ package android.provider { public static final class Settings.Secure extends android.provider.Settings.NameValueTable { method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static boolean putString(@NonNull android.content.ContentResolver, @NonNull String, @Nullable String, @Nullable String, boolean); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static void resetToDefaults(@NonNull android.content.ContentResolver, @Nullable String); - field public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED = "accessibility_display_magnification_navbar_enabled"; + field @Deprecated public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED = "accessibility_display_magnification_navbar_enabled"; field public static final String ASSIST_GESTURE_SETUP_COMPLETE = "assist_gesture_setup_complete"; field public static final String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = "autofill_field_classification"; field public static final String AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT = "autofill_user_data_max_category_count"; @@ -6524,6 +6926,7 @@ package android.provider { field public static final String SERIAL_NUMBER = "serial_number"; field public static final String SERVICE_CATEGORY = "service_category"; field public static final String SLOT_INDEX = "slot_index"; + field public static final String SUB_ID = "sub_id"; } public static final class Telephony.Sms.Intents { @@ -8223,7 +8626,7 @@ package android.telephony { } public final class ModemActivityInfo implements android.os.Parcelable { - ctor public ModemActivityInfo(long, int, int, @NonNull int[], int); + ctor public ModemActivityInfo(long, int, int, @Nullable int[], int); method public int describeContents(); method public int getIdleTimeMillis(); method public int getReceiveTimeMillis(); @@ -8583,7 +8986,7 @@ package android.telephony { } public final class SmsCbMessage implements android.os.Parcelable { - ctor public SmsCbMessage(int, int, int, @NonNull android.telephony.SmsCbLocation, int, @Nullable String, @Nullable String, int, @Nullable android.telephony.SmsCbEtwsInfo, @Nullable android.telephony.SmsCbCmasInfo, int, @Nullable java.util.List<android.telephony.CbGeoUtils.Geometry>, long, int); + ctor public SmsCbMessage(int, int, int, @NonNull android.telephony.SmsCbLocation, int, @Nullable String, @Nullable String, int, @Nullable android.telephony.SmsCbEtwsInfo, @Nullable android.telephony.SmsCbCmasInfo, int, @Nullable java.util.List<android.telephony.CbGeoUtils.Geometry>, long, int, int); method @NonNull public static android.telephony.SmsCbMessage createFromCursor(@NonNull android.database.Cursor); method public int describeContents(); method @Nullable public android.telephony.SmsCbCmasInfo getCmasWarningInfo(); @@ -8600,6 +9003,7 @@ package android.telephony { method public int getSerialNumber(); method public int getServiceCategory(); method public int getSlotIndex(); + method public int getSubscriptionId(); method public boolean isCmasMessage(); method public boolean isEmergencyMessage(); method public boolean isEtwsMessage(); @@ -8719,6 +9123,7 @@ package android.telephony { method @NonNull public static String getDefaultSimCountryIso(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDeviceSoftwareVersion(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode(); + method public int getEmergencyNumberDbVersion(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst(); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.Map<java.lang.Integer,java.lang.Integer> getLogicalToPhysicalSlotMapping(); @@ -8748,6 +9153,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataEnabledForApn(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled(); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle(); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isInEmergencySmsMode(); method public boolean isModemEnabledForSlot(int); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isOpportunisticNetworkEnabled(); @@ -8758,6 +9164,7 @@ package android.telephony { method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isVideoCallingEnabled(); method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle); method public boolean needsOtaServiceProvisioning(); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean rebootRadio(); method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.MODIFY_PHONE_STATE}) public void requestCellInfoUpdate(@NonNull android.os.WorkSource, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.TelephonyManager.CellInfoCallback); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void requestNumberVerification(@NonNull android.telephony.PhoneNumberRange, long, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.NumberVerificationCallback); @@ -8786,8 +9193,8 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean switchSlots(int[]); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void toggleRadioOnOff(); method public void updateServiceLocation(); + method @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public void updateTestOtaEmergencyNumberDbFilePath(@NonNull String); field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_ANOMALY_REPORTED = "android.telephony.action.ANOMALY_REPORTED"; - field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final String ACTION_OTA_EMERGENCY_NUMBER_DB_INSTALLED = "android.telephony.action.OTA_EMERGENCY_NUMBER_DB_INSTALLED"; field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED"; field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED"; field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED"; @@ -8800,6 +9207,7 @@ package android.telephony { field public static final String EXTRA_SIM_STATE = "android.telephony.extra.SIM_STATE"; field public static final String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL"; field public static final String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING"; + field public static final int INVALID_EMERGENCY_NUMBER_DB_VERSION = -1; // 0xffffffff field public static final int KEY_TYPE_EPDG = 1; // 0x1 field public static final int KEY_TYPE_WLAN = 2; // 0x2 field public static final long NETWORK_TYPE_BITMASK_1xRTT = 64L; // 0x40L diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt index 7eb54434f556..ab0f0f987d54 100644 --- a/api/system-lint-baseline.txt +++ b/api/system-lint-baseline.txt @@ -152,10 +152,35 @@ MissingNullability: android.telephony.mbms.DownloadRequest.Builder#setServiceId( + +MutableBareField: android.net.IpConfiguration#httpProxy: + Bare field httpProxy must be marked final, or moved behind accessors if mutable +MutableBareField: android.net.IpConfiguration#ipAssignment: + Bare field ipAssignment must be marked final, or moved behind accessors if mutable +MutableBareField: android.net.IpConfiguration#proxySettings: + Bare field proxySettings must be marked final, or moved behind accessors if mutable +MutableBareField: android.net.IpConfiguration#staticIpConfiguration: + Bare field staticIpConfiguration must be marked final, or moved behind accessors if mutable MutableBareField: android.net.wifi.WifiConfiguration#allowAutojoin: +MutableBareField: android.net.wifi.WifiConfiguration#apBand: + Bare field apBand must be marked final, or moved behind accessors if mutable MutableBareField: android.net.wifi.WifiConfiguration#carrierId: +MutableBareField: android.net.wifi.WifiConfiguration#fromWifiNetworkSpecifier: + Bare field fromWifiNetworkSpecifier must be marked final, or moved behind accessors if mutable +MutableBareField: android.net.wifi.WifiConfiguration#fromWifiNetworkSuggestion: + Bare field fromWifiNetworkSuggestion must be marked final, or moved behind accessors if mutable +MutableBareField: android.net.wifi.WifiConfiguration#macRandomizationSetting: + Bare field macRandomizationSetting must be marked final, or moved behind accessors if mutable +MutableBareField: android.net.wifi.WifiConfiguration#meteredOverride: + Bare field meteredOverride must be marked final, or moved behind accessors if mutable +MutableBareField: android.net.wifi.WifiConfiguration#requirePMF: + Bare field requirePMF must be marked final, or moved behind accessors if mutable +MutableBareField: android.net.wifi.WifiConfiguration#saePasswordId: + Bare field saePasswordId must be marked final, or moved behind accessors if mutable +MutableBareField: android.net.wifi.WifiConfiguration#shared: + Bare field shared must be marked final, or moved behind accessors if mutable NoClone: android.service.contentcapture.ContentCaptureService#dump(java.io.FileDescriptor, java.io.PrintWriter, String[]) parameter #0: diff --git a/api/test-current.txt b/api/test-current.txt index 95b0caea0d43..dacc5d67b730 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -707,6 +707,7 @@ package android.content { field public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture"; field public static final String DEVICE_IDLE_CONTROLLER = "deviceidle"; field public static final String PERMISSION_SERVICE = "permission"; + field public static final String POWER_WHITELIST_MANAGER = "power_whitelist"; field public static final String ROLLBACK_SERVICE = "rollback"; field public static final String STATUS_BAR_SERVICE = "statusbar"; field public static final String TEST_NETWORK_SERVICE = "test_network"; @@ -1808,6 +1809,17 @@ package android.os { method public static boolean contains(java.io.File, java.io.File); } + public class HidlMemory implements java.io.Closeable { + ctor public HidlMemory(@NonNull String, @IntRange(from=0) long, @Nullable android.os.NativeHandle); + method public void close() throws java.io.IOException; + method @NonNull public android.os.HidlMemory dup() throws java.io.IOException; + method protected void finalize(); + method @Nullable public android.os.NativeHandle getHandle(); + method @NonNull public String getName(); + method public long getSize(); + method @NonNull public android.os.NativeHandle releaseHandle(); + } + public abstract class HwBinder implements android.os.IHwBinder { ctor public HwBinder(); method public static final void configureRpcThreadpool(long, boolean); @@ -1831,6 +1843,7 @@ package android.os { method public final void copyToInt8Array(long, byte[], int); method public final boolean getBool(long); method public final double getDouble(long); + method public final long getFieldHandle(long); method public final float getFloat(long); method public final short getInt16(long); method public final int getInt32(long); @@ -1845,6 +1858,7 @@ package android.os { method public final void putDoubleArray(long, double[]); method public final void putFloat(long, float); method public final void putFloatArray(long, float[]); + method public final void putHidlMemory(long, @NonNull android.os.HidlMemory); method public final void putInt16(long, short); method public final void putInt16Array(long, short[]); method public final void putInt32(long, int); @@ -1873,9 +1887,11 @@ package android.os { method public final double readDouble(); method public final java.util.ArrayList<java.lang.Double> readDoubleVector(); method public final android.os.HwBlob readEmbeddedBuffer(long, long, long, boolean); + method @NonNull @Nullable public final android.os.HidlMemory readEmbeddedHidlMemory(long, long, long); method @Nullable public final android.os.NativeHandle readEmbeddedNativeHandle(long, long); method public final float readFloat(); method public final java.util.ArrayList<java.lang.Float> readFloatVector(); + method @NonNull public final android.os.HidlMemory readHidlMemory(); method public final short readInt16(); method public final java.util.ArrayList<java.lang.Short> readInt16Vector(); method public final int readInt32(); @@ -1900,6 +1916,7 @@ package android.os { method public final void writeDoubleVector(java.util.ArrayList<java.lang.Double>); method public final void writeFloat(float); method public final void writeFloatVector(java.util.ArrayList<java.lang.Float>); + method public final void writeHidlMemory(@NonNull android.os.HidlMemory); method public final void writeInt16(short); method public final void writeInt16Vector(java.util.ArrayList<java.lang.Short>); method public final void writeInt32(int); @@ -2026,6 +2043,9 @@ package android.os { field public static final int POWER_SAVE_MODE_TRIGGER_PERCENTAGE = 0; // 0x0 } + public class PowerWhitelistManager { + } + public class Process { method public static final int getThreadScheduler(int) throws java.lang.IllegalArgumentException; field public static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000; // 0x15f90 @@ -2449,6 +2469,7 @@ package android.provider { field public static final String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD = "dynamic_power_savings_disable_threshold"; field public static final String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled"; field public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions"; + field public static final String HIDE_ERROR_DIALOGS = "hide_error_dialogs"; field public static final String LOCATION_GLOBAL_KILL_SWITCH = "location_global_kill_switch"; field public static final String LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST = "location_ignore_settings_package_whitelist"; field public static final String LOW_POWER_MODE = "low_power"; @@ -2510,6 +2531,7 @@ package android.provider { field public static final String SERIAL_NUMBER = "serial_number"; field public static final String SERVICE_CATEGORY = "service_category"; field public static final String SLOT_INDEX = "slot_index"; + field public static final String SUB_ID = "sub_id"; } public static final class Telephony.Sms.Intents { @@ -3135,16 +3157,19 @@ package android.telephony { method public int getCarrierIdListVersion(); method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent); method @Nullable public static android.content.ComponentName getDefaultRespondViaMessageApplication(@NonNull android.content.Context, boolean); + method public int getEmergencyNumberDbVersion(); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag(); method @NonNull @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getNetworkCountryIso(int); method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile(); method @Deprecated public void setCarrierTestOverride(String, String, String, String, String, String, String); method public void setCarrierTestOverride(String, String, String, String, String, String, String, String, String); + method @RequiresPermission("android.permission.READ_ACTIVE_EMERGENCY_SESSION") public void updateTestOtaEmergencyNumberDbFilePath(@NonNull String); field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1 field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0 field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff + field public static final int INVALID_EMERGENCY_NUMBER_DB_VERSION = -1; // 0xffffffff field public static final int UNKNOWN_CARRIER_ID_LIST_VERSION = -1; // 0xffffffff } diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index b0570fd83bbf..49cc3c4c059e 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -164,7 +164,7 @@ message Atom { BiometricAcquired biometric_acquired = 87; BiometricAuthenticated biometric_authenticated = 88; BiometricErrorOccurred biometric_error_occurred = 89; - // Atom number 90 is available for use. + UiEventReported ui_event_reported = 90; BatteryHealthSnapshot battery_health_snapshot = 91; SlowIo slow_io = 92; BatteryCausedShutdown battery_caused_shutdown = 93; @@ -340,6 +340,8 @@ message Atom { PerfettoUploaded perfetto_uploaded = 229 [(log_from_module) = "perfetto"]; VmsClientConnectionStateChanged vms_client_connection_state_changed = 230; + GpsLocationStatusReported gps_location_status_reported = 231; + GpsTimeToFirstFixReported gps_time_to_first_fix_reported = 232; } // Pulled events will start at field 10000. @@ -734,6 +736,27 @@ message GpsSignalQualityChanged { optional android.server.location.GpsSignalQualityEnum level = 1; } +/** + * Gps location status report + * + * Logged from: + * /frameworks/base/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java + */ +message GpsLocationStatusReported { + // Boolean stating if location was acquired + optional bool location_success = 1; +} + +/** + * Gps log time to first fix report + * + * Logged from: + * /frameworks/base/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java + */ +message GpsTimeToFirstFixReported { + // int32 reporting the time to first fix in milliseconds + optional int32 time_to_first_fix_millis = 1; +} /** * Logs when a sync manager sync state changes. @@ -3266,6 +3289,21 @@ message GenericAtom { } /** + * Atom for simple logging of user interaction and impression events, such as "the user touched + * this button" or "this dialog was displayed". + * Keep the UI event stream clean: don't use for system or background events. + * Log using the UiEventLogger wrapper - don't write with the StatsLog API directly. + */ +message UiEventReported { + // The event_id. + optional int32 event_id = 1; + // The event's source or target uid and package, if applicable. + // For example, the package posting a notification, or the destination package of a share. + optional int32 uid = 2 [(is_uid) = true]; + optional string package_name = 3; +} + +/** * Logs when a biometric acquire event occurs. * * Logged from: diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index ce27ce6853e8..b5bad0530503 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -499,8 +499,9 @@ void StatsPullerManager::RegisterPullAtomCallback(const int uid, const int32_t a StatsdStats::getInstance().notePullerCallbackRegistrationChanged(atomTag, /*registered=*/true); kAllPullAtomInfo[{.atomTag = atomTag}] = {.additiveFields = additiveFields, .coolDownNs = coolDownNs, + .puller = new StatsCallbackPuller(atomTag, callback), .pullTimeoutNs = timeoutNs, - .puller = new StatsCallbackPuller(atomTag, callback)}; + }; } void StatsPullerManager::UnregisterPullerCallback(int32_t atomTag) { diff --git a/cmds/svc/src/com/android/commands/svc/Svc.java b/cmds/svc/src/com/android/commands/svc/Svc.java index 68fb8e694e6f..e602e2abbe03 100644 --- a/cmds/svc/src/com/android/commands/svc/Svc.java +++ b/cmds/svc/src/com/android/commands/svc/Svc.java @@ -94,7 +94,7 @@ public class Svc { COMMAND_HELP, new PowerCommand(), new DataCommand(), - new WifiCommand(), + // `svc wifi` has been migrated to WifiShellCommand new UsbCommand(), new NfcCommand(), new BluetoothCommand(), diff --git a/cmds/svc/src/com/android/commands/svc/WifiCommand.java b/cmds/svc/src/com/android/commands/svc/WifiCommand.java deleted file mode 100644 index e31cb5381afc..000000000000 --- a/cmds/svc/src/com/android/commands/svc/WifiCommand.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.commands.svc; - -import android.os.ServiceManager; -import android.os.RemoteException; -import android.net.wifi.IWifiManager; -import android.content.Context; - -public class WifiCommand extends Svc.Command { - public WifiCommand() { - super("wifi"); - } - - public String shortHelp() { - return "Control the Wi-Fi manager"; - } - - public String longHelp() { - return shortHelp() + "\n" - + "\n" - + "usage: svc wifi [enable|disable]\n" - + " Turn Wi-Fi on or off.\n\n"; - } - - public void run(String[] args) { - boolean validCommand = false; - if (args.length >= 2) { - boolean flag = false; - if ("enable".equals(args[1])) { - flag = true; - validCommand = true; - } else if ("disable".equals(args[1])) { - flag = false; - validCommand = true; - } - if (validCommand) { - IWifiManager wifiMgr - = IWifiManager.Stub.asInterface(ServiceManager.getService(Context.WIFI_SERVICE)); - if (wifiMgr == null) { - System.err.println("Wi-Fi service is not ready"); - return; - } - try { - wifiMgr.setWifiEnabled("com.android.shell", flag); - } - catch (RemoteException e) { - System.err.println("Wi-Fi operation failed: " + e); - } - return; - } - } - System.err.println(longHelp()); - } -} diff --git a/cmds/svc/svc b/cmds/svc/svc index c122e981e4c7..60c95c7ec855 100755 --- a/cmds/svc/svc +++ b/cmds/svc/svc @@ -1,3 +1,24 @@ #!/system/bin/sh + +# `svc wifi` has been migrated to WifiShellCommand, +# simply perform translation to `cmd wifi set-wifi-enabled` here. +if [ "x$1" == "xwifi" ]; then + # `cmd wifi` by convention uses enabled/disabled + # instead of enable/disable + if [ "x$2" == "xenable" ]; then + exec cmd wifi set-wifi-enabled enabled + elif [ "x$2" == "xdisable" ]; then + exec cmd wifi set-wifi-enabled disabled + else + echo "Control the Wi-Fi manager" + echo "" + echo "usage: svc wifi [enable|disable]" + echo " Turn Wi-Fi on or off." + echo "" + fi + exit 1 +fi + export CLASSPATH=/system/framework/svc.jar exec app_process /system/bin com.android.commands.svc.Svc "$@" + diff --git a/config/preloaded-classes b/config/preloaded-classes index ab98e5b1f87a..0394a7a489ba 100644 --- a/config/preloaded-classes +++ b/config/preloaded-classes @@ -514,6 +514,7 @@ android.app.admin.SystemUpdateInfo$1 android.app.admin.SystemUpdateInfo android.app.admin.SystemUpdatePolicy$1 android.app.admin.SystemUpdatePolicy +android.app.appsearch.AppSearchManagerFrameworkInitializer android.app.assist.AssistContent$1 android.app.assist.AssistContent android.app.assist.AssistStructure$1 diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java index 61c5dac03da6..3db0b2612c78 100644 --- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java +++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java @@ -18,7 +18,6 @@ package android.accessibilityservice; import static android.content.pm.PackageManager.FEATURE_FINGERPRINT; -import android.accessibilityservice.AccessibilityButtonController.AccessibilityButtonCallback; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.UnsupportedAppUsage; @@ -333,14 +332,6 @@ public class AccessibilityServiceInfo implements Parcelable { */ public static final int FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK = 0x00000400; - /** - * This flag indicates that the accessibility service will handle the shortcut action itself. - * A callback {@link AccessibilityButtonCallback#onClicked(AccessibilityButtonController)} is - * called when the user presses the accessibility shortcut. Otherwise, the service is enabled - * or disabled by the system instead. - */ - public static final int FLAG_HANDLE_SHORTCUT = 0x00000800; - /** {@hide} */ public static final int FLAG_FORCE_DIRECT_BOOT_AWARE = 0x00010000; @@ -448,7 +439,6 @@ public class AccessibilityServiceInfo implements Parcelable { * @see #FLAG_ENABLE_ACCESSIBILITY_VOLUME * @see #FLAG_REQUEST_ACCESSIBILITY_BUTTON * @see #FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK - * @see #FLAG_HANDLE_SHORTCUT */ public int flags; @@ -680,9 +670,8 @@ public class AccessibilityServiceInfo implements Parcelable { } try { if (platformCompat != null) { - return platformCompat.isChangeEnabledByPackageName( - REQUEST_ACCESSIBILITY_BUTTON_CHANGE, mResolveInfo.serviceInfo.packageName, - mResolveInfo.serviceInfo.applicationInfo.uid); + return platformCompat.isChangeEnabled(REQUEST_ACCESSIBILITY_BUTTON_CHANGE, + mResolveInfo.serviceInfo.applicationInfo); } } catch (RemoteException ignore) { } @@ -1163,8 +1152,6 @@ public class AccessibilityServiceInfo implements Parcelable { return "FLAG_REQUEST_FINGERPRINT_GESTURES"; case FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK: return "FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK"; - case FLAG_HANDLE_SHORTCUT: - return "FLAG_HANDLE_SHORTCUT"; default: return null; } diff --git a/core/java/android/accessibilityservice/TEST_MAPPING b/core/java/android/accessibilityservice/TEST_MAPPING index c7c4c3a7e8f4..df85b6157630 100644 --- a/core/java/android/accessibilityservice/TEST_MAPPING +++ b/core/java/android/accessibilityservice/TEST_MAPPING @@ -14,6 +14,9 @@ ], "postsubmit": [ { + "name": "CtsAccessibilityServiceSdk29TestCases" + }, + { "name": "CtsAccessibilityServiceTestCases" }, { diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index afb787118107..5032f776f8f0 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1213,7 +1213,6 @@ public class AppOpsManager { OP_START_FOREGROUND, OP_SMS_FINANCIAL_TRANSACTIONS, OP_MANAGE_IPSEC_TUNNELS, - OP_GET_USAGE_STATS, OP_INSTANT_APP_START_FOREGROUND }; diff --git a/core/java/android/app/ExpandableListActivity.java b/core/java/android/app/ExpandableListActivity.java index e08f25a1c40c..22de87843341 100644 --- a/core/java/android/app/ExpandableListActivity.java +++ b/core/java/android/app/ExpandableListActivity.java @@ -150,7 +150,11 @@ import java.util.Map; * * @see #setListAdapter * @see android.widget.ExpandableListView + * + * @deprecated Use {@link androidx.recyclerview.widget.RecyclerView} or use + * {@link android.widget.ExpandableListView} directly */ +@Deprecated public class ExpandableListActivity extends Activity implements OnCreateContextMenuListener, ExpandableListView.OnChildClickListener, ExpandableListView.OnGroupCollapseListener, diff --git a/core/java/android/app/ISearchManager.aidl b/core/java/android/app/ISearchManager.aidl index 53f1a46c1b8b..011970764071 100644 --- a/core/java/android/app/ISearchManager.aidl +++ b/core/java/android/app/ISearchManager.aidl @@ -31,6 +31,5 @@ interface ISearchManager { @UnsupportedAppUsage ComponentName getGlobalSearchActivity(); ComponentName getWebSearchActivity(); - void launchAssist(in Bundle args); - boolean launchLegacyAssist(String hint, int userHandle, in Bundle args); + void launchAssist(int userHandle, in Bundle args); } diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java index 88e235660c09..b495b3c98047 100644 --- a/core/java/android/app/LauncherActivity.java +++ b/core/java/android/app/LauncherActivity.java @@ -53,7 +53,11 @@ import java.util.List; * Displays a list of all activities which can be performed * for a given intent. Launches when clicked. * + * @deprecated Applications can implement this UI themselves using + * {@link androidx.recyclerview.widget.RecyclerView} and + * {@link android.content.pm.PackageManager#queryIntentActivities(Intent, int)} */ +@Deprecated public abstract class LauncherActivity extends ListActivity { Intent mIntent; PackageManager mPackageManager; diff --git a/core/java/android/app/ListActivity.java b/core/java/android/app/ListActivity.java index 2162521edce1..810cca22a918 100644 --- a/core/java/android/app/ListActivity.java +++ b/core/java/android/app/ListActivity.java @@ -171,7 +171,11 @@ import android.widget.ListView; * * @see #setListAdapter * @see android.widget.ListView + * + * @deprecated Use {@link androidx.fragment.app.ListFragment} or + * {@link androidx.recyclerview.widget.RecyclerView} to implement your Activity instead. */ +@Deprecated public class ListActivity extends Activity { /** * This field should be made private, so it is hidden from the SDK. diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index fce74496d9c4..b37cc266a156 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -627,6 +627,13 @@ public class Notification implements Parcelable */ public static final int FLAG_BUBBLE = 0x00001000; + /** @hide */ + @IntDef({FLAG_SHOW_LIGHTS, FLAG_ONGOING_EVENT, FLAG_INSISTENT, FLAG_ONLY_ALERT_ONCE, + FLAG_AUTO_CANCEL, FLAG_NO_CLEAR, FLAG_FOREGROUND_SERVICE, FLAG_HIGH_PRIORITY, + FLAG_LOCAL_ONLY, FLAG_GROUP_SUMMARY, FLAG_AUTOGROUP_SUMMARY, FLAG_BUBBLE}) + @Retention(RetentionPolicy.SOURCE) + public @interface NotificationFlags{}; + public int flags; /** @hide */ @@ -4545,10 +4552,15 @@ public class Notification implements Parcelable } /** - * @hide + * Set the value for a notification flag + * + * @param mask Bit mask of the flag + * @param value Status (on/off) of the flag + * + * @return The same Builder. */ @NonNull - public Builder setFlag(int mask, boolean value) { + public Builder setFlag(@NotificationFlags int mask, boolean value) { if (value) { mN.flags |= mask; } else { @@ -10410,6 +10422,16 @@ public class Notification implements Parcelable p.recycle(); return brv; } + + /** + * Override and return true, since {@link RemoteViews#onLoadClass(Class)} is not overridden. + * + * @see RemoteViews#shouldUseStaticFilter() + */ + @Override + protected boolean shouldUseStaticFilter() { + return true; + } } /** diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java index acca6fc177b8..b10c3e2dd7df 100644 --- a/core/java/android/app/SearchManager.java +++ b/core/java/android/app/SearchManager.java @@ -16,6 +16,8 @@ package android.app; +import android.annotation.Nullable; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.UnsupportedAppUsage; import android.content.ActivityNotFoundException; @@ -973,37 +975,22 @@ public class SearchManager } /** - * Starts the assistant. + * Starts the {@link android.provider.Settings.Secure#ASSISTANT assistant}. * - * @param args the args to pass to the assistant + * @param args a {@code Bundle} that will be passed to the assistant's + * {@link android.service.voice.VoiceInteractionSession#onShow VoiceInteractionSession} + * (or as {@link Intent#getExtras() extras} along + * {@link Intent#ACTION_ASSIST ACTION_ASSIST} for legacy assistants) * * @hide */ - @UnsupportedAppUsage - public void launchAssist(Bundle args) { + @SystemApi + public void launchAssist(@Nullable Bundle args) { try { if (mService == null) { return; } - mService.launchAssist(args); - } catch (RemoteException re) { - throw re.rethrowFromSystemServer(); - } - } - - /** - * Starts the legacy assistant (i.e. the {@link Intent#ACTION_ASSIST}). - * - * @param args the args to pass to the assistant - * - * @hide - */ - public boolean launchLegacyAssist(String hint, int userHandle, Bundle args) { - try { - if (mService == null) { - return false; - } - return mService.launchLegacyAssist(hint, userHandle, args); + mService.launchAssist(mContext.getUserId(), args); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index d40261f7452a..0bfd2c6f5f70 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.app.ContextImpl.ServiceInitializationState; import android.app.admin.DevicePolicyManager; import android.app.admin.IDevicePolicyManager; +import android.app.appsearch.AppSearchManagerFrameworkInitializer; import android.app.blob.BlobStoreManagerFrameworkInitializer; import android.app.contentsuggestions.ContentSuggestionsManager; import android.app.contentsuggestions.IContentSuggestionsManager; @@ -115,16 +116,7 @@ import android.net.lowpan.ILowpanManager; import android.net.lowpan.LowpanManager; import android.net.nsd.INsdManager; import android.net.nsd.NsdManager; -import android.net.wifi.IWifiScanner; -import android.net.wifi.RttManager; -import android.net.wifi.WifiManager; -import android.net.wifi.WifiScanner; -import android.net.wifi.aware.IWifiAwareManager; -import android.net.wifi.aware.WifiAwareManager; -import android.net.wifi.p2p.IWifiP2pManager; -import android.net.wifi.p2p.WifiP2pManager; -import android.net.wifi.rtt.IWifiRttManager; -import android.net.wifi.rtt.WifiRttManager; +import android.net.wifi.WifiFrameworkInitializer; import android.nfc.NfcManager; import android.os.BatteryManager; import android.os.BatteryStats; @@ -690,66 +682,6 @@ public final class SystemServiceRegistry { ConnectivityThread.getInstanceLooper()); }}); - registerService(Context.WIFI_SERVICE, WifiManager.class, - new CachedServiceFetcher<WifiManager>() { - @Override - public WifiManager createService(ContextImpl ctx) { - return new WifiManager(ctx.getOuterContext(), - ConnectivityThread.getInstanceLooper()); - }}); - - registerService(Context.WIFI_P2P_SERVICE, WifiP2pManager.class, - new StaticServiceFetcher<WifiP2pManager>() { - @Override - public WifiP2pManager createService() throws ServiceNotFoundException { - IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_P2P_SERVICE); - IWifiP2pManager service = IWifiP2pManager.Stub.asInterface(b); - return new WifiP2pManager(service); - }}); - - registerService(Context.WIFI_AWARE_SERVICE, WifiAwareManager.class, - new CachedServiceFetcher<WifiAwareManager>() { - @Override - public WifiAwareManager createService(ContextImpl ctx) throws ServiceNotFoundException { - IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_AWARE_SERVICE); - IWifiAwareManager service = IWifiAwareManager.Stub.asInterface(b); - if (service == null) { - return null; - } - return new WifiAwareManager(ctx.getOuterContext(), service); - }}); - - registerService(Context.WIFI_SCANNING_SERVICE, WifiScanner.class, - new CachedServiceFetcher<WifiScanner>() { - @Override - public WifiScanner createService(ContextImpl ctx) throws ServiceNotFoundException { - IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_SCANNING_SERVICE); - IWifiScanner service = IWifiScanner.Stub.asInterface(b); - return new WifiScanner(ctx.getOuterContext(), service, - ConnectivityThread.getInstanceLooper()); - }}); - - registerService(Context.WIFI_RTT_SERVICE, RttManager.class, - new CachedServiceFetcher<RttManager>() { - @Override - public RttManager createService(ContextImpl ctx) throws ServiceNotFoundException { - IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_RTT_RANGING_SERVICE); - IWifiRttManager service = IWifiRttManager.Stub.asInterface(b); - return new RttManager(ctx.getOuterContext(), - new WifiRttManager(ctx.getOuterContext(), service)); - }}); - - registerService(Context.WIFI_RTT_RANGING_SERVICE, WifiRttManager.class, - new CachedServiceFetcher<WifiRttManager>() { - @Override - public WifiRttManager createService(ContextImpl ctx) - throws ServiceNotFoundException { - IBinder b = ServiceManager.getServiceOrThrow( - Context.WIFI_RTT_RANGING_SERVICE); - IWifiRttManager service = IWifiRttManager.Stub.asInterface(b); - return new WifiRttManager(ctx.getOuterContext(), service); - }}); - registerService(Context.ETHERNET_SERVICE, EthernetManager.class, new CachedServiceFetcher<EthernetManager>() { @Override @@ -1263,6 +1195,8 @@ public final class SystemServiceRegistry { JobSchedulerFrameworkInitializer.registerServiceWrappers(); BlobStoreManagerFrameworkInitializer.initialize(); TelephonyFrameworkInitializer.registerServiceWrappers(); + AppSearchManagerFrameworkInitializer.initialize(); + WifiFrameworkInitializer.registerServiceWrappers(); } finally { // If any of the above code throws, we're in a pretty bad shape and the process // will likely crash, but we'll reset it just in case there's an exception handler... diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java index cfb363a0834c..4e9762737c07 100644 --- a/core/java/android/bluetooth/BluetoothPan.java +++ b/core/java/android/bluetooth/BluetoothPan.java @@ -16,8 +16,13 @@ package android.bluetooth; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Binder; @@ -25,6 +30,8 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.Log; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; @@ -40,6 +47,7 @@ import java.util.List; * * @hide */ +@SystemApi public final class BluetoothPan implements BluetoothProfile { private static final String TAG = "BluetoothPan"; private static final boolean DBG = true; @@ -67,6 +75,7 @@ public final class BluetoothPan implements BluetoothProfile { * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to * receive. */ + @SuppressLint("ActionValue") @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_CONNECTION_STATE_CHANGED = "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED"; @@ -76,19 +85,32 @@ public final class BluetoothPan implements BluetoothProfile { * The local role of the PAN profile that the remote device is bound to. * It can be one of {@link #LOCAL_NAP_ROLE} or {@link #LOCAL_PANU_ROLE}. */ + @SuppressLint("ActionValue") public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE"; + /** @hide */ + @IntDef({PAN_ROLE_NONE, LOCAL_NAP_ROLE, LOCAL_PANU_ROLE}) + @Retention(RetentionPolicy.SOURCE) + public @interface LocalPanRole {} + public static final int PAN_ROLE_NONE = 0; /** * The local device is acting as a Network Access Point. */ public static final int LOCAL_NAP_ROLE = 1; - public static final int REMOTE_NAP_ROLE = 1; /** * The local device is acting as a PAN User. */ public static final int LOCAL_PANU_ROLE = 2; + + /** @hide */ + @IntDef({PAN_ROLE_NONE, REMOTE_NAP_ROLE, REMOTE_PANU_ROLE}) + @Retention(RetentionPolicy.SOURCE) + public @interface RemotePanRole {} + + public static final int REMOTE_NAP_ROLE = 1; + public static final int REMOTE_PANU_ROLE = 2; /** @@ -134,6 +156,8 @@ public final class BluetoothPan implements BluetoothProfile { /** * Create a BluetoothPan proxy object for interacting with the local * Bluetooth Service which handles the Pan profile + * + * @hide */ @UnsupportedAppUsage /*package*/ BluetoothPan(Context context, ServiceListener listener) { @@ -235,7 +259,7 @@ public final class BluetoothPan implements BluetoothProfile { * {@inheritDoc} */ @Override - public List<BluetoothDevice> getConnectedDevices() { + public @NonNull List<BluetoothDevice> getConnectedDevices() { if (VDBG) log("getConnectedDevices()"); final IBluetoothPan service = getService(); if (service != null && isEnabled()) { @@ -252,6 +276,7 @@ public final class BluetoothPan implements BluetoothProfile { /** * {@inheritDoc} + * @hide */ @Override public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { @@ -273,7 +298,7 @@ public final class BluetoothPan implements BluetoothProfile { * {@inheritDoc} */ @Override - public int getConnectionState(BluetoothDevice device) { + public int getConnectionState(@Nullable BluetoothDevice device) { if (VDBG) log("getState(" + device + ")"); final IBluetoothPan service = getService(); if (service != null && isEnabled() && isValidDevice(device)) { @@ -288,7 +313,11 @@ public final class BluetoothPan implements BluetoothProfile { return BluetoothProfile.STATE_DISCONNECTED; } - @UnsupportedAppUsage + /** + * Turns on/off bluetooth tethering + * + * @param value is whether to enable or disable bluetooth tethering + */ public void setBluetoothTethering(boolean value) { String pkgName = mContext.getOpPackageName(); if (DBG) log("setBluetoothTethering(" + value + "), calling package:" + pkgName); @@ -302,7 +331,11 @@ public final class BluetoothPan implements BluetoothProfile { } } - @UnsupportedAppUsage + /** + * Determines whether tethering is enabled + * + * @return true if tethering is on, false if not or some error occurred + */ public boolean isTetheringOn() { if (VDBG) log("isTetheringOn()"); final IBluetoothPan service = getService(); diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java index f5aa01458481..f1ac76527487 100644 --- a/core/java/android/bluetooth/BluetoothProfile.java +++ b/core/java/android/bluetooth/BluetoothProfile.java @@ -20,9 +20,9 @@ package android.bluetooth; import android.Manifest; import android.annotation.IntDef; import android.annotation.RequiresPermission; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; -import android.os.Build; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -43,6 +43,7 @@ public interface BluetoothProfile { * This extra represents the current connection state of the profile of the * Bluetooth device. */ + @SuppressLint("ActionValue") String EXTRA_STATE = "android.bluetooth.profile.extra.STATE"; /** @@ -51,6 +52,7 @@ public interface BluetoothProfile { * This extra represents the previous connection state of the profile of the * Bluetooth device. */ + @SuppressLint("ActionValue") String EXTRA_PREVIOUS_STATE = "android.bluetooth.profile.extra.PREVIOUS_STATE"; @@ -106,7 +108,7 @@ public interface BluetoothProfile { * * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) + @SystemApi int PAN = 5; /** diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 7703e087bcea..0fdb51359cf9 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3335,6 +3335,7 @@ public abstract class Context { ROLLBACK_SERVICE, DROPBOX_SERVICE, //@hide: DEVICE_IDLE_CONTROLLER, + //@hide: POWER_WHITELIST_MANAGER, DEVICE_POLICY_SERVICE, UI_MODE_SERVICE, DOWNLOAD_SERVICE, @@ -4345,6 +4346,15 @@ public abstract class Context { public static final String DEVICE_IDLE_CONTROLLER = "deviceidle"; /** + * System service name for the PowerWhitelistManager. + * + * @see #getSystemService(String) + * @hide + */ + @TestApi + public static final String POWER_WHITELIST_MANAGER = "power_whitelist"; + + /** * Use with {@link #getSystemService(String)} to retrieve a * {@link android.app.admin.DevicePolicyManager} for working with global * device policy management. @@ -4898,6 +4908,15 @@ public abstract class Context { public static final String BATTERY_STATS_SERVICE = "batterystats"; /** + * Use with {@link #getSystemService(String)} to retrieve an + * AppSearchManager for indexing and querying app data managed + * by the system. + * + * @see #getSystemService(String) + */ + public static final String APP_SEARCH_SERVICE = "app_search"; + + /** * Determine whether the given permission is allowed for a particular * process and user ID running in the system. * diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 2d9ca67a236d..168eae65ddf2 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -206,7 +206,7 @@ public final class AssetManager implements AutoCloseable { @VisibleForTesting public static void createSystemAssetsInZygoteLocked(boolean reinitialize, String frameworkPath) { - if (sSystem != null || reinitialize) { + if (sSystem != null && !reinitialize) { return; } @@ -225,7 +225,9 @@ public final class AssetManager implements AutoCloseable { sSystemApkAssetsSet = new ArraySet<>(apkAssets); sSystemApkAssets = apkAssets.toArray(new ApkAssets[apkAssets.size()]); - sSystem = new AssetManager(true /*sentinel*/); + if (sSystem == null) { + sSystem = new AssetManager(true /*sentinel*/); + } sSystem.setApkAssets(sSystemApkAssets, false /*invalidateCaches*/); } catch (IOException e) { throw new IllegalStateException("Failed to create system AssetManager", e); diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java index 2af82d7214bf..143467b15fe8 100644 --- a/core/java/android/net/IpConfiguration.java +++ b/core/java/android/net/IpConfiguration.java @@ -16,6 +16,10 @@ package android.net; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.net.StaticIpConfiguration; import android.os.Parcel; @@ -27,13 +31,17 @@ import java.util.Objects; * A class representing a configured network. * @hide */ -public class IpConfiguration implements Parcelable { +@SystemApi +public final class IpConfiguration implements Parcelable { private static final String TAG = "IpConfiguration"; + // This enum has been used by apps through reflection for many releases. + // Therefore they can't just be removed. Duplicating these constants to + // give an alternate SystemApi is a worse option than exposing them. + @SuppressLint("Enum") public enum IpAssignment { /* Use statically configured IP settings. Configuration can be accessed * with staticIpConfiguration */ - @UnsupportedAppUsage STATIC, /* Use dynamically configured IP settings */ DHCP, @@ -42,14 +50,19 @@ public class IpConfiguration implements Parcelable { UNASSIGNED } + /** @hide */ public IpAssignment ipAssignment; + /** @hide */ public StaticIpConfiguration staticIpConfiguration; + // This enum has been used by apps through reflection for many releases. + // Therefore they can't just be removed. Duplicating these constants to + // give an alternate SystemApi is a worse option than exposing them. + @SuppressLint("Enum") public enum ProxySettings { /* No proxy is to be used. Any existing proxy settings * should be cleared. */ - @UnsupportedAppUsage NONE, /* Use statically configured proxy. Configuration can be accessed * with httpProxy. */ @@ -62,8 +75,10 @@ public class IpConfiguration implements Parcelable { PAC } + /** @hide */ public ProxySettings proxySettings; + /** @hide */ @UnsupportedAppUsage public ProxyInfo httpProxy; @@ -83,6 +98,7 @@ public class IpConfiguration implements Parcelable { init(IpAssignment.UNASSIGNED, ProxySettings.UNASSIGNED, null, null); } + /** @hide */ @UnsupportedAppUsage public IpConfiguration(IpAssignment ipAssignment, ProxySettings proxySettings, @@ -91,7 +107,7 @@ public class IpConfiguration implements Parcelable { init(ipAssignment, proxySettings, staticIpConfiguration, httpProxy); } - public IpConfiguration(IpConfiguration source) { + public IpConfiguration(@NonNull IpConfiguration source) { this(); if (source != null) { init(source.ipAssignment, source.proxySettings, @@ -99,35 +115,35 @@ public class IpConfiguration implements Parcelable { } } - public IpAssignment getIpAssignment() { + public @NonNull IpAssignment getIpAssignment() { return ipAssignment; } - public void setIpAssignment(IpAssignment ipAssignment) { + public void setIpAssignment(@NonNull IpAssignment ipAssignment) { this.ipAssignment = ipAssignment; } - public StaticIpConfiguration getStaticIpConfiguration() { + public @Nullable StaticIpConfiguration getStaticIpConfiguration() { return staticIpConfiguration; } - public void setStaticIpConfiguration(StaticIpConfiguration staticIpConfiguration) { + public void setStaticIpConfiguration(@Nullable StaticIpConfiguration staticIpConfiguration) { this.staticIpConfiguration = staticIpConfiguration; } - public ProxySettings getProxySettings() { + public @NonNull ProxySettings getProxySettings() { return proxySettings; } - public void setProxySettings(ProxySettings proxySettings) { + public void setProxySettings(@NonNull ProxySettings proxySettings) { this.proxySettings = proxySettings; } - public ProxyInfo getHttpProxy() { + public @Nullable ProxyInfo getHttpProxy() { return httpProxy; } - public void setHttpProxy(ProxyInfo httpProxy) { + public void setHttpProxy(@Nullable ProxyInfo httpProxy) { this.httpProxy = httpProxy; } @@ -175,13 +191,19 @@ public class IpConfiguration implements Parcelable { 83 * httpProxy.hashCode(); } - /** Implement the Parcelable interface */ + /** + * Implement the Parcelable interface + * @hide + */ public int describeContents() { return 0; } - /** Implement the Parcelable interface */ - public void writeToParcel(Parcel dest, int flags) { + /** + * Implement the Parcelable interface + * @hide + */ + public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString(ipAssignment.name()); dest.writeString(proxySettings.name()); dest.writeParcelable(staticIpConfiguration, flags); @@ -189,7 +211,7 @@ public class IpConfiguration implements Parcelable { } /** Implement the Parcelable interface */ - public static final @android.annotation.NonNull Creator<IpConfiguration> CREATOR = + public static final @NonNull Creator<IpConfiguration> CREATOR = new Creator<IpConfiguration>() { public IpConfiguration createFromParcel(Parcel in) { IpConfiguration config = new IpConfiguration(); diff --git a/core/java/android/net/NetworkKey.java b/core/java/android/net/NetworkKey.java index 425424041354..47c08a450fc4 100644 --- a/core/java/android/net/NetworkKey.java +++ b/core/java/android/net/NetworkKey.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; @@ -27,6 +28,8 @@ import android.os.Parcelable; import android.text.TextUtils; import android.util.Log; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** @@ -48,6 +51,13 @@ public class NetworkKey implements Parcelable { /** A wifi network, for which {@link #wifiKey} will be populated. */ public static final int TYPE_WIFI = 1; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"TYPE_"}, value = { + TYPE_WIFI + }) + public @interface NetworkType {} + /** * The type of this network. * @see #TYPE_WIFI @@ -65,7 +75,6 @@ public class NetworkKey implements Parcelable { * * @return A new {@link NetworkKey} instance or <code>null</code> if the given * {@link ScanResult} instance is malformed. - * @hide */ @Nullable public static NetworkKey createFromScanResult(@Nullable ScanResult result) { diff --git a/core/java/android/net/NetworkScore.java b/core/java/android/net/NetworkScore.java index 1ab63352401c..13f2994110a1 100644 --- a/core/java/android/net/NetworkScore.java +++ b/core/java/android/net/NetworkScore.java @@ -154,4 +154,9 @@ public final class NetworkScore implements Parcelable { } return true; } + + /** Convert to a string */ + public String toString() { + return "NetworkScore[" + mExtensions.toString() + "]"; + } } diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java index 50dd468aa905..f6dc52522cb2 100644 --- a/core/java/android/net/NetworkScoreManager.java +++ b/core/java/android/net/NetworkScoreManager.java @@ -17,7 +17,9 @@ package android.net; import android.Manifest.permission; +import android.annotation.CallbackExecutor; import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SdkConstant; @@ -25,13 +27,16 @@ import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; +import android.os.Binder; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; +import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; +import java.util.concurrent.Executor; /** * Class that manages communication between network subsystems and a network scorer. @@ -50,19 +55,25 @@ import java.util.List; @SystemApi @SystemService(Context.NETWORK_SCORE_SERVICE) public class NetworkScoreManager { + private static final String TAG = "NetworkScoreManager"; + /** * Activity action: ask the user to change the active network scorer. This will show a dialog * that asks the user whether they want to replace the current active scorer with the one * specified in {@link #EXTRA_PACKAGE_NAME}. The activity will finish with RESULT_OK if the * active scorer was changed or RESULT_CANCELED if it failed for any reason. + * @deprecated No longer sent. */ + @Deprecated @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE"; /** * Extra used with {@link #ACTION_CHANGE_ACTIVE} to specify the new scorer package. Set with * {@link android.content.Intent#putExtra(String, String)}. + * @deprecated No longer sent. */ + @Deprecated public static final String EXTRA_PACKAGE_NAME = "packageName"; /** @@ -73,7 +84,9 @@ public class NetworkScoreManager { * configured by the user as well as any open networks. * * <p class="note">This is a protected intent that can only be sent by the system. + * @deprecated Use {@link #ACTION_RECOMMEND_NETWORKS} to bind scorer app instead. */ + @Deprecated @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_SCORE_NETWORKS = "android.net.scoring.SCORE_NETWORKS"; @@ -81,7 +94,9 @@ public class NetworkScoreManager { * Extra used with {@link #ACTION_SCORE_NETWORKS} to specify the networks to be scored, as an * array of {@link NetworkKey}s. Can be obtained with * {@link android.content.Intent#getParcelableArrayExtra(String)}}. + * @deprecated Use {@link #ACTION_RECOMMEND_NETWORKS} to bind scorer app instead. */ + @Deprecated public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore"; /** @@ -285,7 +300,7 @@ public class NetworkScoreManager { * @throws SecurityException if the caller is not the active scorer. */ @RequiresPermission(android.Manifest.permission.SCORE_NETWORKS) - public boolean updateScores(ScoredNetwork[] networks) throws SecurityException { + public boolean updateScores(@NonNull ScoredNetwork[] networks) throws SecurityException { try { return mService.updateScores(networks); } catch (RemoteException e) { @@ -359,13 +374,21 @@ public class NetworkScoreManager { /** * Request scoring for networks. * - * @return true if the broadcast was sent, or false if there is no active scorer. + * <p> + * Note: The results (i.e scores) for these networks, when available will be provided via the + * callback registered with {@link #registerNetworkScoreCallback(int, int, Executor, + * NetworkScoreCallback)}. The calling module is responsible for registering a callback to + * receive the results before requesting new scores via this API. + * + * @return true if the request was successfully sent, or false if there is no active scorer. * @throws SecurityException if the caller does not hold the * {@link permission#REQUEST_NETWORK_SCORES} permission. + * * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES) - public boolean requestScores(NetworkKey[] networks) throws SecurityException { + public boolean requestScores(@NonNull NetworkKey[] networks) throws SecurityException { try { return mService.requestScores(networks); } catch (RemoteException e) { @@ -431,6 +454,88 @@ public class NetworkScoreManager { } /** + * Base class for network score cache callback. Should be extended by applications and set + * when calling {@link #registerNetworkScoreCallback(int, int, NetworkScoreCallback, + * Executor)} + * + * @hide + */ + @SystemApi + public interface NetworkScoreCallback { + /** + * Called when a new set of network scores are available. + * This is triggered in response when the client invokes + * {@link #requestScores(NetworkKey[])} to score a new set of networks. + * + * @param networks List of {@link ScoredNetwork} containing updated scores. + */ + void updateScores(@NonNull List<ScoredNetwork> networks); + + /** + * Invokes when all the previously provided scores are no longer valid. + */ + void clearScores(); + } + + /** + * Callback proxy for {@link NetworkScoreCallback} objects. + */ + private class NetworkScoreCallbackProxy extends INetworkScoreCache.Stub { + private final Executor mExecutor; + private final NetworkScoreCallback mCallback; + + NetworkScoreCallbackProxy(Executor executor, NetworkScoreCallback callback) { + mExecutor = executor; + mCallback = callback; + } + + @Override + public void updateScores(@NonNull List<ScoredNetwork> networks) { + Binder.clearCallingIdentity(); + mExecutor.execute(() -> { + mCallback.updateScores(networks); + }); + } + + @Override + public void clearScores() { + Binder.clearCallingIdentity(); + mExecutor.execute(() -> { + mCallback.clearScores(); + }); + } + } + + /** + * Register a network score callback. + * + * @param networkType the type of network this cache can handle. See {@link NetworkKey#type} + * @param filterType the {@link CacheUpdateFilter} to apply + * @param callback implementation of {@link NetworkScoreCallback} that will be invoked when the + * scores change. + * @param executor The executor on which to execute the callbacks. + * @throws SecurityException if the caller does not hold the + * {@link permission#REQUEST_NETWORK_SCORES} permission. + * @throws IllegalArgumentException if a callback is already registered for this type. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES) + public void registerNetworkScoreCallback(@NetworkKey.NetworkType int networkType, + @CacheUpdateFilter int filterType, + @NonNull @CallbackExecutor Executor executor, + @NonNull NetworkScoreCallback callback) throws SecurityException { + if (callback == null || executor == null) { + throw new IllegalArgumentException("callback / executor cannot be null"); + } + Log.v(TAG, "registerNetworkScoreCallback: callback=" + callback + ", executor=" + + executor); + // Use the @hide method. + registerNetworkScoreCache( + networkType, new NetworkScoreCallbackProxy(executor, callback), filterType); + } + + /** * Determine whether the application with the given UID is the enabled scorer. * * @param callingUid the UID to check diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java index 807c467053a6..9d92db448668 100644 --- a/core/java/android/net/ProxyInfo.java +++ b/core/java/android/net/ProxyInfo.java @@ -16,7 +16,8 @@ package android.net; - +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -89,6 +90,15 @@ public class ProxyInfo implements Parcelable { } /** + * Construct a {@link ProxyInfo} object that will download and run the PAC script at the + * specified URL and port. + */ + @NonNull + public static ProxyInfo buildPacProxy(@NonNull Uri pacUrl, int port) { + return new ProxyInfo(pacUrl, port); + } + + /** * Create a ProxyProperties that points at a HTTP Proxy. * @hide */ @@ -105,7 +115,7 @@ public class ProxyInfo implements Parcelable { * Create a ProxyProperties that points at a PAC URL. * @hide */ - public ProxyInfo(Uri pacFileUrl) { + public ProxyInfo(@NonNull Uri pacFileUrl) { mHost = LOCAL_HOST; mPort = LOCAL_PORT; mExclusionList = LOCAL_EXCL_LIST; @@ -132,7 +142,7 @@ public class ProxyInfo implements Parcelable { * Only used in PacManager after Local Proxy is bound. * @hide */ - public ProxyInfo(Uri pacFileUrl, int localProxyPort) { + public ProxyInfo(@NonNull Uri pacFileUrl, int localProxyPort) { mHost = LOCAL_HOST; mPort = localProxyPort; mExclusionList = LOCAL_EXCL_LIST; @@ -159,11 +169,10 @@ public class ProxyInfo implements Parcelable { mPacFileUrl = Uri.EMPTY; } - // copy constructor instead of clone /** - * @hide + * A copy constructor to hold proxy properties. */ - public ProxyInfo(ProxyInfo source) { + public ProxyInfo(@Nullable ProxyInfo source) { if (source != null) { mHost = source.getHost(); mPort = source.getPort(); @@ -226,12 +235,13 @@ public class ProxyInfo implements Parcelable { * comma separated * @hide */ + @Nullable public String getExclusionListAsString() { return mExclusionList; } /** - * @hide + * Return true if the pattern of proxy is valid, otherwise return false. */ public boolean isValid() { if (!Uri.EMPTY.equals(mPacFileUrl)) return true; diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java index f789b723f732..2ac3def3a3f9 100644 --- a/core/java/android/os/FileUtils.java +++ b/core/java/android/os/FileUtils.java @@ -1275,7 +1275,13 @@ public final class FileUtils { /** * Closes the given object quietly, ignoring any checked exceptions. Does * nothing if the given object is {@code null}. + * + * @deprecated This method may suppress potentially significant exceptions, particularly when + * closing writable resources. With a writable resource, a failure thrown from {@code close()} + * should be considered as significant as a failure thrown from a write method because it may + * indicate a failure to flush bytes to the underlying resource. */ + @Deprecated public static void closeQuietly(@Nullable AutoCloseable closeable) { IoUtils.closeQuietly(closeable); } @@ -1283,7 +1289,13 @@ public final class FileUtils { /** * Closes the given object quietly, ignoring any checked exceptions. Does * nothing if the given object is {@code null}. + * + * @deprecated This method may suppress potentially significant exceptions, particularly when + * closing writable resources. With a writable resource, a failure thrown from {@code close()} + * should be considered as significant as a failure thrown from a write method because it may + * indicate a failure to flush bytes to the underlying resource. */ + @Deprecated public static void closeQuietly(@Nullable FileDescriptor fd) { IoUtils.closeQuietly(fd); } diff --git a/core/java/android/os/HidlMemory.java b/core/java/android/os/HidlMemory.java new file mode 100644 index 000000000000..aeb65892a425 --- /dev/null +++ b/core/java/android/os/HidlMemory.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2019 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.os; + +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.annotation.TestApi; + +import java.io.Closeable; +import java.io.IOException; + +/** + * An abstract representation of a memory block, as representing by the HIDL system. + * + * The block is defined by a {name, size, handle} tuple, where the name is used to determine how to + * interpret the handle. The underlying handle is assumed to be owned by this instance and will be + * closed as soon as {@link #close()} is called on this instance, or this instance has been + * finalized (the latter supports using it in a shared manner without having to worry about who owns + * this instance, the former is more efficient resource-wise and is recommended for most use-cases). + * Note, however, that ownership of the handle does not necessarily imply ownership of the + * underlying file descriptors - the underlying handle may or may not own them. If you want the + * underlying handle to outlive this instance, call {@link #releaseHandle()} to obtain the handle + * and detach the ownership relationship. + * + * @hide + */ +@SystemApi +@TestApi +public class HidlMemory implements Closeable { + private final @NonNull String mName; + private final long mSize; + private @Nullable NativeHandle mHandle; + private long mNativeContext; // For use of native code. + + /** + * Constructor. + * + * @param name The name of the IMapper service used to resolve the handle (e.g. "ashmem"). + * @param size The (non-negative) size in bytes of the memory block. + * @param handle The handle. May be null. This instance will own the handle and will close it + * as soon as {@link #close()} is called or the object is destroyed. This, this + * handle instance should generally not be shared with other clients. + */ + public HidlMemory(@NonNull String name, @IntRange(from = 0) long size, + @Nullable NativeHandle handle) { + mName = name; + mSize = size; + mHandle = handle; + } + + /** + * Create a copy of this instance, where the underlying handle (and its file descriptors) have + * been duplicated. + */ + @NonNull + public HidlMemory dup() throws IOException { + return new HidlMemory(mName, mSize, mHandle != null ? mHandle.dup() : null); + } + + /** + * Close the underlying native handle. No-op if handle is null or has been released using {@link + * #releaseHandle()}. + */ + @Override + public void close() throws IOException { + if (mHandle != null) { + mHandle.close(); + } + } + + /** + * Disowns the underlying handle and returns it. This object becomes invalid. + * + * @return The underlying handle. + */ + @NonNull + public NativeHandle releaseHandle() { + NativeHandle handle = mHandle; + mHandle = null; + return handle; + } + + /** + * Gets the name, which represents how the handle is to be interpreted. + * + * @return The name. + */ + @NonNull + public String getName() { + return mName; + } + + /** + * Gets the size of the block, in bytes. + * + * @return The size. + */ + public long getSize() { + return mSize; + } + + /** + * Gets a native handle. The actual interpretation depends on the name and is implementation + * defined. + * + * @return The native handle. + */ + @Nullable + public NativeHandle getHandle() { + return mHandle; + } + + @Override + protected void finalize() { + try { + close(); + } catch (IOException e) { + throw new RuntimeException(e); + } finally { + nativeFinalize(); + } + } + + private native void nativeFinalize(); +} diff --git a/core/java/android/os/HidlMemoryUtil.java b/core/java/android/os/HidlMemoryUtil.java new file mode 100644 index 000000000000..b08822ddd751 --- /dev/null +++ b/core/java/android/os/HidlMemoryUtil.java @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2019 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.os; + +import static android.system.OsConstants.MAP_SHARED; +import static android.system.OsConstants.PROT_READ; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; +import android.annotation.TestApi; +import android.system.ErrnoException; +import android.system.Os; +import android.util.Log; + +import com.android.internal.util.Preconditions; + +import java.nio.ByteBuffer; +import java.nio.DirectByteBuffer; +import java.util.ArrayList; +import java.util.List; + +/** + * Provides utilities for dealing with HidlMemory. + * + * @hide + */ +public final class HidlMemoryUtil { + static private final String TAG = "HidlMemoryUtil"; + + private HidlMemoryUtil() { + } + + /** + * Copies a byte-array into a new Ashmem region and return it as HidlMemory. + * The returned instance owns the underlying file descriptors, and the client should generally + * call close on it when no longer in use (or otherwise, when the object gets destroyed it will + * be closed). + * + * @param input The input byte array. + * @return A HidlMemory instance, containing a copy of the input. + */ + public static @NonNull + HidlMemory byteArrayToHidlMemory(@NonNull byte[] input) { + return byteArrayToHidlMemory(input, null); + } + + /** + * Copies a byte-array into a new Ashmem region and return it as HidlMemory. + * The returned instance owns the underlying file descriptors, and the client should generally + * call close on it when no longer in use (or otherwise, when the object gets destroyed it will + * be closed). + * + * @param input The input byte array. + * @param name An optional name for the ashmem region. + * @return A HidlMemory instance, containing a copy of the input. + */ + public static @NonNull + HidlMemory byteArrayToHidlMemory(@NonNull byte[] input, @Nullable String name) { + Preconditions.checkNotNull(input); + + if (input.length == 0) { + return new HidlMemory("ashmem", 0, null); + } + + try { + SharedMemory shmem = SharedMemory.create(name != null ? name : "", input.length); + ByteBuffer buffer = shmem.mapReadWrite(); + buffer.put(input); + shmem.unmap(buffer); + NativeHandle handle = new NativeHandle(shmem.getFileDescriptor(), true); + return new HidlMemory("ashmem", input.length, handle); + } catch (ErrnoException e) { + throw new RuntimeException(e); + } + } + + /** + * Copies a byte list into a new Ashmem region and return it as HidlMemory. + * The returned instance owns the underlying file descriptors, and the client should generally + * call close on it when no longer in use (or otherwise, when the object gets destroyed it will + * be closed). + * + * @param input The input byte list. + * @return A HidlMemory instance, containing a copy of the input. + */ + public static @NonNull + HidlMemory byteListToHidlMemory(@NonNull List<Byte> input) { + return byteListToHidlMemory(input, null); + } + + /** + * Copies a byte list into a new Ashmem region and return it as HidlMemory. + * The returned instance owns the underlying file descriptors, and the client should generally + * call close on it when no longer in use (or otherwise, when the object gets destroyed it will + * be closed). + * + * @param input The input byte list. + * @param name An optional name for the ashmem region. + * @return A HidlMemory instance, containing a copy of the input. + */ + public static @NonNull + HidlMemory byteListToHidlMemory(@NonNull List<Byte> input, @Nullable String name) { + Preconditions.checkNotNull(input); + + if (input.isEmpty()) { + return new HidlMemory("ashmem", 0, null); + } + + try { + SharedMemory shmem = SharedMemory.create(name != null ? name : "", input.size()); + ByteBuffer buffer = shmem.mapReadWrite(); + for (Byte b : input) { + buffer.put(b); + } + shmem.unmap(buffer); + NativeHandle handle = new NativeHandle(shmem.getFileDescriptor(), true); + return new HidlMemory("ashmem", input.size(), handle); + } catch (ErrnoException e) { + throw new RuntimeException(e); + } + } + + /** + * Copies all data from a HidlMemory instance into a byte array. + * + * @param mem The HidlMemory instance. Must be of name "ashmem" and of size that doesn't exceed + * {@link Integer#MAX_VALUE}. + * @return A byte array, containing a copy of the input. + */ + public static @NonNull + byte[] hidlMemoryToByteArray(@NonNull HidlMemory mem) { + Preconditions.checkNotNull(mem); + Preconditions.checkArgumentInRange(mem.getSize(), 0L, (long) Integer.MAX_VALUE, + "Memory size"); + Preconditions.checkArgument(mem.getSize() == 0 || mem.getName().equals("ashmem"), + "Unsupported memory type: %s", mem.getName()); + + if (mem.getSize() == 0) { + return new byte[0]; + } + + ByteBuffer buffer = getBuffer(mem); + byte[] result = new byte[buffer.remaining()]; + buffer.get(result); + return result; + } + + /** + * Copies all data from a HidlMemory instance into a byte list. + * + * @param mem The HidlMemory instance. Must be of name "ashmem" and of size that doesn't exceed + * {@link Integer#MAX_VALUE}. + * @return A byte list, containing a copy of the input. + */ + @SuppressLint("ConcreteCollection") + public static @NonNull + ArrayList<Byte> hidlMemoryToByteList(@NonNull HidlMemory mem) { + Preconditions.checkNotNull(mem); + Preconditions.checkArgumentInRange(mem.getSize(), 0L, (long) Integer.MAX_VALUE, + "Memory size"); + Preconditions.checkArgument(mem.getSize() == 0 || mem.getName().equals("ashmem"), + "Unsupported memory type: %s", mem.getName()); + + if (mem.getSize() == 0) { + return new ArrayList<>(); + } + + ByteBuffer buffer = getBuffer(mem); + + ArrayList<Byte> result = new ArrayList<>(buffer.remaining()); + while (buffer.hasRemaining()) { + result.add(buffer.get()); + } + return result; + } + + private static ByteBuffer getBuffer(@NonNull HidlMemory mem) { + try { + final int size = (int) mem.getSize(); + + if (size == 0) { + return ByteBuffer.wrap(new byte[0]); + } + + NativeHandle handle = mem.getHandle(); + + final long address = Os.mmap(0, size, PROT_READ, MAP_SHARED, handle.getFileDescriptor(), + 0); + return new DirectByteBuffer(size, address, handle.getFileDescriptor(), () -> { + try { + Os.munmap(address, size); + } catch (ErrnoException e) { + Log.wtf(TAG, e); + } + }, true); + } catch (ErrnoException e) { + throw new RuntimeException(e); + } + } +} diff --git a/core/java/android/os/HwBlob.java b/core/java/android/os/HwBlob.java index 2c453bfc4d42..154227b2a786 100644 --- a/core/java/android/os/HwBlob.java +++ b/core/java/android/os/HwBlob.java @@ -92,6 +92,14 @@ public class HwBlob { * @throws IndexOutOfBoundsException when offset is out of this HwBlob */ public native final String getString(long offset); + /** + * For embedded fields that follow a two-step approach for reading, first obtain their field + * handle using this method, and pass that field handle to the respective + * HwParcel.readEmbedded*() method. + * @param offset The field offset. + * @return The field handle. + */ + public native final long getFieldHandle(long offset); /** * Copy the blobs data starting from the given byte offset into the range, copying @@ -312,6 +320,20 @@ public class HwBlob { public native final void putBlob(long offset, HwBlob blob); /** + * Writes a HidlMemory instance (without duplicating the underlying file descriptors) at an + * offset. + * + * @param offset location to write value + * @param mem a {@link HidlMemory} instance to write + * @throws IndexOutOfBoundsException when [offset, offset + sizeof(jobject)] is out of range + */ + public final void putHidlMemory(long offset, @NonNull HidlMemory mem) { + putNativeHandle(offset + 0 /* offset of 'handle' field. */, mem.getHandle()); + putInt64(offset + 16 /* offset of 'size' field. */, mem.getSize()); + putString(offset + 24 /* offset of 'name' field. */, mem.getName()); + } + + /** * @return current handle of HwBlob for reference in a parcelled binder transaction */ public native final long handle(); diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java index 5e8929c6c999..9786f16bebaa 100644 --- a/core/java/android/os/HwParcel.java +++ b/core/java/android/os/HwParcel.java @@ -324,6 +324,15 @@ public class HwParcel { public native final void writeStrongBinder(IHwBinder binder); /** + * Write a HidlMemory object (without duplicating the underlying file descriptors) to the end + * of the parcel. + * + * @param memory value to write + */ + @FastNative + public native final void writeHidlMemory(@NonNull HidlMemory memory); + + /** * Checks to make sure that the interface name matches the name written by the parcel * sender by writeInterfaceToken * @@ -582,6 +591,38 @@ public class HwParcel { public native final IHwBinder readStrongBinder(); /** + * Reads a HidlMemory value (without duplicating the underlying file + * descriptors) from the parcel. These file descriptors will only + * be open for the duration that the binder window is open. If they + * are needed further, you must call {@link HidlMemory#dup()}, which makes you also + * responsible for calling {@link HidlMemory#close()}. + * + * @return HidlMemory object read from parcel. + * @throws IllegalArgumentException if the parcel has no more data or is otherwise corrupt. + */ + @FastNative + @NonNull + public native final HidlMemory readHidlMemory(); + + /** + * Reads an embedded HidlMemory (without duplicating the underlying + * file descriptors) from the parcel. These file descriptors will only + * be open for the duration that the binder window is open. If they + * are needed further, you must call {@link HidlMemory#dup()}. You + * do not need to call close on the HidlMemory returned from this. + * + * @param fieldHandle handle of the field, obtained from the {@link HwBlob}. + * @param parentHandle parentHandle from which to read the embedded object + * @param offset offset into parent + * @return a {@link HidlMemory} instance parsed from the parcel + * @throws IllegalArgumentException if the parcel has no more data + */ + @FastNative + @NonNull + public native final @Nullable + HidlMemory readEmbeddedHidlMemory(long fieldHandle, long parentHandle, long offset); + + /** * Read opaque segment of data as a blob. * @return blob of size expectedSize * @throws IllegalArgumentException if the parcel has no more data diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java index 3222fc43b213..d468972df413 100644 --- a/core/java/android/os/Looper.java +++ b/core/java/android/os/Looper.java @@ -112,10 +112,12 @@ public final class Looper { /** * Initialize the current thread as a looper, marking it as an - * application's main looper. The main looper for your application - * is created by the Android environment, so you should never need - * to call this function yourself. See also: {@link #prepare()} + * application's main looper. See also: {@link #prepare()} + * + * @deprecated The main looper for your application is created by the Android environment, + * so you should never need to call this function yourself. */ + @Deprecated public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java index a510e42edcb6..c104abdcb097 100644 --- a/core/java/android/os/SystemClock.java +++ b/core/java/android/os/SystemClock.java @@ -154,6 +154,7 @@ public final class SystemClock { final IAlarmManager mgr = IAlarmManager.Stub .asInterface(ServiceManager.getService(Context.ALARM_SERVICE)); if (mgr == null) { + Slog.e(TAG, "Unable to set RTC: mgr == null"); return false; } diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index deeeddc5fb71..2d70986dddee 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -2362,6 +2362,19 @@ public class StorageManager { } } + /** + * Check whether the device supports filesystem checkpoint. + * + * @return true if the device supports filesystem checkpoint, false otherwise. + */ + public boolean isCheckpointSupported() { + try { + return mStorageManager.supportsCheckpoint(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + private final Object mFuseAppLoopLock = new Object(); @GuardedBy("mFuseAppLoopLock") diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 1d7e33806e0c..abf34ca2d21a 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -391,8 +391,9 @@ public final class DeviceConfig { * Look up the values of multiple properties for a particular namespace. The lookup is atomic, * such that the values of these properties cannot change between the time when the first is * fetched and the time when the last is fetched. - * - * TODO: reference setProperties when it is added. + * <p> + * Each call to {@link #setProperties(Properties)} is also atomic and ensures that either none + * or all of the change is picked up here, but never only part of it. * * @param namespace The namespace containing the properties to look up. * @param names The names of properties to look up, or empty to fetch all properties for the @@ -560,6 +561,27 @@ public final class DeviceConfig { } /** + * Set all of the properties for a specific namespace. Pre-existing properties will be updated + * and new properties will be added if necessary. Any pre-existing properties for the specific + * namespace which are not part of the provided {@link Properties} object will be deleted from + * the namespace. These changes are all applied atomically, such that no calls to read or reset + * these properties can happen in the middle of this update. + * <p> + * Each call to {@link #getProperties(String, String...)} is also atomic and ensures that either + * none or all of this update is picked up, but never only part of it. + * + * @param properties the complete set of properties to set for a specific namespace. + * @hide + */ + @SystemApi + @RequiresPermission(WRITE_DEVICE_CONFIG) + public static boolean setProperties(@NonNull Properties properties) { + ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver(); + return Settings.Config.setStrings(contentResolver, properties.getNamespace(), + properties.mMap); + } + + /** * Reset properties to their default values. * <p> * The method accepts an optional namespace parameter. If provided, only properties set within @@ -703,23 +725,26 @@ public final class DeviceConfig { List<String> pathSegments = uri.getPathSegments(); // pathSegments(0) is "config" final String namespace = pathSegments.get(1); - final String name = pathSegments.get(2); - final String value; + Map<String, String> propertyMap = new ArrayMap<>(); try { - value = getProperty(namespace, name); + Properties allProperties = getProperties(namespace); + for (int i = 2; i < pathSegments.size(); ++i) { + String key = pathSegments.get(i); + propertyMap.put(key, allProperties.getString(key, null)); + } } catch (SecurityException e) { // Silently failing to not crash binder or listener threads. Log.e(TAG, "OnPropertyChangedListener update failed: permission violation."); return; } + Properties properties = new Properties(namespace, propertyMap); + synchronized (sLock) { for (int i = 0; i < sListeners.size(); i++) { if (namespace.equals(sListeners.valueAt(i).first)) { final OnPropertiesChangedListener listener = sListeners.keyAt(i); sListeners.valueAt(i).second.execute(() -> { - Map<String, String> propertyMap = new ArrayMap<>(1); - propertyMap.put(name, value); - listener.onPropertiesChanged(new Properties(namespace, propertyMap)); + listener.onPropertiesChanged(properties); }); } } @@ -741,7 +766,11 @@ public final class DeviceConfig { } /** - * Interface for monitoring changes to properties. + * Interface for monitoring changes to properties. Implementations will receive callbacks when + * properties change, including a {@link Properties} object which contains a single namespace + * and all of the properties which changed for that namespace. This includes properties which + * were added, updated, or deleted. This is not necessarily a complete list of all properties + * belonging to the namespace, as properties which don't change are omitted. * <p> * Override {@link #onPropertiesChanged(Properties)} to handle callbacks for changes. * @@ -751,10 +780,13 @@ public final class DeviceConfig { @TestApi public interface OnPropertiesChangedListener { /** - * Called when one or more properties have changed. + * Called when one or more properties have changed, providing a Properties object with all + * of the changed properties. This object will contain only properties which have changed, + * not the complete set of all properties belonging to the namespace. * * @param properties Contains the complete collection of properties which have changed for a - * single namespace. + * single namespace. This includes only those which were added, updated, + * or deleted. */ void onPropertiesChanged(@NonNull Properties properties); } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 3ac7deb0db08..0af2c36108df 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -1960,6 +1960,11 @@ public final class Settings { */ public static final String CALL_METHOD_PREFIX_KEY = "_prefix"; + /** + * @hide - String argument extra to the fast-path call()-based requests + */ + public static final String CALL_METHOD_FLAGS_KEY = "_flags"; + /** @hide - Private call() method to write to 'system' table */ public static final String CALL_METHOD_PUT_SYSTEM = "PUT_system"; @@ -1972,6 +1977,9 @@ public final class Settings { /** @hide - Private call() method to write to 'configuration' table */ public static final String CALL_METHOD_PUT_CONFIG = "PUT_config"; + /** @hide - Private call() method to write to and delete from the 'configuration' table */ + public static final String CALL_METHOD_SET_ALL_CONFIG = "SET_ALL_config"; + /** @hide - Private call() method to delete from the 'system' table */ public static final String CALL_METHOD_DELETE_SYSTEM = "DELETE_system"; @@ -2304,21 +2312,23 @@ public final class Settings { private final String mCallGetCommand; private final String mCallSetCommand; private final String mCallListCommand; + private final String mCallSetAllCommand; @GuardedBy("this") private GenerationTracker mGenerationTracker; public NameValueCache(Uri uri, String getCommand, String setCommand, ContentProviderHolder providerHolder) { - this(uri, getCommand, setCommand, null, providerHolder); + this(uri, getCommand, setCommand, null, null, providerHolder); } NameValueCache(Uri uri, String getCommand, String setCommand, String listCommand, - ContentProviderHolder providerHolder) { + String setAllCommand, ContentProviderHolder providerHolder) { mUri = uri; mCallGetCommand = getCommand; mCallSetCommand = setCommand; mCallListCommand = listCommand; + mCallSetAllCommand = setAllCommand; mProviderHolder = providerHolder; } @@ -2344,6 +2354,26 @@ public final class Settings { return true; } + public boolean setStringsForPrefix(ContentResolver cr, String prefix, + HashMap<String, String> keyValues) { + if (mCallSetAllCommand == null) { + // This NameValueCache does not support atomically setting multiple flags + return false; + } + try { + Bundle args = new Bundle(); + args.putString(CALL_METHOD_PREFIX_KEY, prefix); + args.putSerializable(CALL_METHOD_FLAGS_KEY, keyValues); + IContentProvider cp = mProviderHolder.getProvider(cr); + cp.call(cr.getPackageName(), cr.getFeatureId(), mProviderHolder.mUri.getAuthority(), + mCallSetAllCommand, null, args); + } catch (RemoteException e) { + // Not supported by the remote side + return false; + } + return true; + } + @UnsupportedAppUsage public String getStringForUser(ContentResolver cr, String name, final int userHandle) { final boolean isSelf = (userHandle == UserHandle.myUserId()); @@ -6161,8 +6191,12 @@ public final class Settings { "accessibility_shortcut_dialog_shown"; /** - * Setting specifying the accessibility service to be toggled via the accessibility - * shortcut. Must be its flattened {@link ComponentName}. + * Setting specifying the accessibility services, accessibility shortcut targets, + * or features to be toggled via the accessibility shortcut. + * + * <p> This is a colon-separated string list which contains the flattened + * {@link ComponentName} and the class name of a system class implementing a supported + * accessibility feature. * @hide */ @UnsupportedAppUsage @@ -6171,9 +6205,11 @@ public final class Settings { "accessibility_shortcut_target_service"; /** - * Setting specifying the accessibility service or feature to be toggled via the - * accessibility button in the navigation bar. This is either a flattened - * {@link ComponentName} or the class name of a system class implementing a supported + * Setting specifying the accessibility services, accessibility shortcut targets, + * or features to be toggled via the accessibility button in the navigation bar. + * + * <p> This is a colon-separated string list which contains the flattened + * {@link ComponentName} and the class name of a system class implementing a supported * accessibility feature. * @hide */ @@ -6334,6 +6370,9 @@ public final class Settings { * zoom in the display content and is targeted to low vision users. The current * magnification scale is controlled by {@link #ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE}. * + * @deprecated Use {@link #ACCESSIBILITY_BUTTON_TARGET_COMPONENT} instead. + * {@link #ACCESSIBILITY_BUTTON_TARGET_COMPONENT} holds the magnification system class name + * when navigation bar magnification is enabled. * @hide */ @SystemApi @@ -7140,16 +7179,6 @@ public final class Settings { public static final String VOICE_RECOGNITION_SERVICE = "voice_recognition_service"; /** - * Stores whether an user has consented to have apps verified through PAM. - * The value is boolean (1 or 0). - * - * @hide - */ - @UnsupportedAppUsage - public static final String PACKAGE_VERIFIER_USER_CONSENT = - "package_verifier_user_consent"; - - /** * The {@link ComponentName} string of the selected spell checker service which is * one of the services managed by the text service manager. * @@ -11889,6 +11918,7 @@ public final class Settings { * as if they had been accepted by the user. * @hide */ + @TestApi public static final String HIDE_ERROR_DIALOGS = "hide_error_dialogs"; /** @@ -13718,6 +13748,7 @@ public final class Settings { CALL_METHOD_GET_CONFIG, CALL_METHOD_PUT_CONFIG, CALL_METHOD_LIST_CONFIG, + CALL_METHOD_SET_ALL_CONFIG, sProviderHolder); /** @@ -13792,6 +13823,29 @@ public final class Settings { } /** + * Clear all name/value pairs for the provided namespace and save new name/value pairs in + * their place. + * + * @param resolver to access the database with. + * @param namespace to which the names should be set. + * @param keyValues map of key names (without the prefix) to values. + * @return + * + * @hide + */ + @RequiresPermission(Manifest.permission.WRITE_DEVICE_CONFIG) + static boolean setStrings(@NonNull ContentResolver resolver, @NonNull String namespace, + @NonNull Map<String, String> keyValues) { + HashMap<String, String> compositeKeyValueMap = new HashMap<>(keyValues.keySet().size()); + for (Map.Entry<String, String> entry : keyValues.entrySet()) { + compositeKeyValueMap.put( + createCompositeName(namespace, entry.getKey()), entry.getValue()); + } + return sNameValueCache.setStringsForPrefix(resolver, createPrefix(namespace), + compositeKeyValueMap); + } + + /** * Reset the values to their defaults. * <p> * The method accepts an optional prefix parameter. If provided, only pairs with a name that diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java index 484894f98023..d3367c10bff5 100644 --- a/core/java/android/util/SparseArray.java +++ b/core/java/android/util/SparseArray.java @@ -106,6 +106,9 @@ public class SparseArray<E> implements Cloneable { /** * Returns true if the key exists in the array. This is equivalent to * {@link #indexOfKey(int)} >= 0. + * + * @param key Potential key in the mapping + * @return true if the key is defined in the mapping */ public boolean contains(int key) { return indexOfKey(key) >= 0; diff --git a/core/java/android/util/TimingLogger.java b/core/java/android/util/TimingLogger.java index be442dac630a..5a4a512c283b 100644 --- a/core/java/android/util/TimingLogger.java +++ b/core/java/android/util/TimingLogger.java @@ -44,7 +44,14 @@ import android.os.SystemClock; * D/TAG ( 3459): methodA: 6 ms, work C * D/TAG ( 3459): methodA: end, 16 ms * </pre> + * + * @deprecated Use {@link android.os.Trace}, or + * <a href="https://developer.android.com/studio/profile/benchmark">Android Studio</a>. In + * general, milliseconds is the wrong granularity for method-level tracing. Rounding errors + * can overemphasize cheap operations, or underemphasize repeated operations. This timing + * system also does not take CPU scheduling or frequency into account. */ +@Deprecated public class TimingLogger { /** diff --git a/core/java/android/view/IDisplayWindowListener.aidl b/core/java/android/view/IDisplayWindowListener.aidl index 725cd6f38aaa..973a208bf485 100644 --- a/core/java/android/view/IDisplayWindowListener.aidl +++ b/core/java/android/view/IDisplayWindowListener.aidl @@ -16,12 +16,16 @@ package android.view; +import android.content.res.Configuration; + /** * Interface to listen for changes to display window-containers. * - * This differs from DisplayManager's DisplayListener: + * This differs from DisplayManager's DisplayListener in a couple ways: * - onDisplayAdded is always called after the display is actually added to the WM hierarchy. * This corresponds to the DisplayContent and not the raw Dislay from DisplayManager. + * - onDisplayConfigurationChanged is called for all configuration changes, not just changes + * to displayinfo (eg. windowing-mode). * * @hide */ @@ -33,6 +37,11 @@ oneway interface IDisplayWindowListener { void onDisplayAdded(int displayId); /** + * Called when a display's window-container configuration has changed. + */ + void onDisplayConfigurationChanged(int displayId, in Configuration newConfig); + + /** * Called when a display is removed from the hierarchy. */ void onDisplayRemoved(int displayId); diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index db76b71eab9f..9d4f387895bb 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -8732,7 +8732,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, structure.setContextClickable(true); } structure.setClassName(getAccessibilityClassName().toString()); - structure.setContentDescription(mContentDescription); + structure.setContentDescription(getContentDescription()); } /** @@ -9939,8 +9939,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, info.setImportantForAccessibility(isImportantForAccessibility()); info.setPackageName(mContext.getPackageName()); info.setClassName(getAccessibilityClassName()); - info.setStateDescription(mStateDescription); - info.setContentDescription(mContentDescription); + info.setStateDescription(getStateDescription()); + info.setContentDescription(getContentDescription()); info.setEnabled(isEnabled()); info.setClickable(isClickable()); @@ -10323,7 +10323,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see #setStateDescription(CharSequence) */ @ViewDebug.ExportedProperty(category = "accessibility") - public @Nullable CharSequence getStateDescription() { + public final @Nullable CharSequence getStateDescription() { return mStateDescription; } @@ -13717,7 +13717,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @UnsupportedAppUsage public CharSequence getIterableTextForAccessibility() { - return mContentDescription; + return getContentDescription(); } /** @@ -29498,10 +29498,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, stream.addProperty("text:textAlignment", getTextAlignment()); // accessibility + CharSequence contentDescription = getContentDescription(); stream.addProperty("accessibility:contentDescription", - mContentDescription == null ? "" : mContentDescription.toString()); - stream.addProperty("accessibility:stateDescription", - mStateDescription == null ? "" : mStateDescription.toString()); + contentDescription == null ? "" : contentDescription.toString()); stream.addProperty("accessibility:labelFor", getLabelFor()); stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 89b111ddfb0b..afa661e26d4c 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -4966,6 +4966,8 @@ public final class ViewRootImpl implements ViewParent, protected static final int FINISH_HANDLED = 1; protected static final int FINISH_NOT_HANDLED = 2; + private String mTracePrefix; + /** * Creates an input stage. * @param next The next stage to which events should be forwarded. @@ -4983,7 +4985,14 @@ public final class ViewRootImpl implements ViewParent, } else if (shouldDropInputEvent(q)) { finish(q, false); } else { - apply(q, onProcess(q)); + traceEvent(q, Trace.TRACE_TAG_VIEW); + final int result; + try { + result = onProcess(q); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_VIEW); + } + apply(q, result); } } @@ -5093,6 +5102,17 @@ public final class ViewRootImpl implements ViewParent, return false; } } + + private void traceEvent(QueuedInputEvent q, long traceTag) { + if (!Trace.isTagEnabled(traceTag)) { + return; + } + + if (mTracePrefix == null) { + mTracePrefix = getClass().getSimpleName(); + } + Trace.traceBegin(traceTag, mTracePrefix + " seq#=" + q.mEvent.getSequenceNumber()); + } } /** @@ -7709,26 +7729,46 @@ public final class ViewRootImpl implements ViewParent, private void deliverInputEvent(QueuedInputEvent q) { Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent", q.mEvent.getSequenceNumber()); - if (mInputEventConsistencyVerifier != null) { - mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0); - } - InputStage stage; - if (q.shouldSendToSynthesizer()) { - stage = mSyntheticInputStage; - } else { - stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage; + if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { + Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent src=0x" + + Integer.toHexString(q.mEvent.getSource()) + " eventTimeNano=" + + q.mEvent.getEventTimeNano() + " seq#=" + q.mEvent.getSequenceNumber()); } + try { + if (mInputEventConsistencyVerifier != null) { + Trace.traceBegin(Trace.TRACE_TAG_VIEW, "verifyEventConsistency"); + try { + mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_VIEW); + } + } - if (q.mEvent instanceof KeyEvent) { - mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent); - } + InputStage stage; + if (q.shouldSendToSynthesizer()) { + stage = mSyntheticInputStage; + } else { + stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage; + } - if (stage != null) { - handleWindowFocusChanged(); - stage.deliver(q); - } else { - finishInputEvent(q); + if (q.mEvent instanceof KeyEvent) { + Trace.traceBegin(Trace.TRACE_TAG_VIEW, "preDispatchToUnhandledKeyManager"); + try { + mUnhandledKeyManager.preDispatch((KeyEvent) q.mEvent); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_VIEW); + } + } + + if (stage != null) { + handleWindowFocusChanged(); + stage.deliver(q); + } else { + finishInputEvent(q); + } + } finally { + Trace.traceEnd(Trace.TRACE_TAG_VIEW); } } diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 0ff6063d4ae2..cf39979ff7f9 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -103,8 +103,7 @@ class WindowlessWindowManager implements IWindowSession { } if (((attrs.inputFeatures & - WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) && - (mHostInputToken != null)) { + WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0)) { try { mRealWm.grantInputChannel(displayId, sc, window, mHostInputToken, outInputChannel); } catch (RemoteException e) { diff --git a/core/java/android/view/accessibility/TEST_MAPPING b/core/java/android/view/accessibility/TEST_MAPPING index d2bd6ea2b702..9b1b67709d19 100644 --- a/core/java/android/view/accessibility/TEST_MAPPING +++ b/core/java/android/view/accessibility/TEST_MAPPING @@ -36,6 +36,9 @@ ], "postsubmit": [ { + "name": "CtsAccessibilityServiceSdk29TestCases" + }, + { "name": "CtsAccessibilityServiceTestCases" }, { diff --git a/core/java/android/view/inline/InlineContentView.java b/core/java/android/view/inline/InlineContentView.java new file mode 100644 index 000000000000..4bc2176e8279 --- /dev/null +++ b/core/java/android/view/inline/InlineContentView.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2019 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.view.inline; + +import android.annotation.NonNull; +import android.content.Context; +import android.graphics.PixelFormat; +import android.view.SurfaceControl; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +/** + * This class represents a view that can hold an opaque content that may be from a different source. + * + * @hide + */ +public class InlineContentView extends SurfaceView { + public InlineContentView(@NonNull Context context, + @NonNull SurfaceControl surfaceControl) { + super(context); + setZOrderOnTop(true); + getHolder().addCallback(new SurfaceHolder.Callback() { + @Override + public void surfaceCreated(SurfaceHolder holder) { + holder.setFormat(PixelFormat.TRANSPARENT); + new SurfaceControl.Transaction() + .reparent(surfaceControl, getSurfaceControl()) + .setVisibility(surfaceControl, /* visible */ true) + .apply(); + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + // TODO(b/137800469): implement this. + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + // TODO(b/137800469): implement this. + } + }); + } +} diff --git a/core/java/android/view/inline/InlinePresentationSpec.aidl b/core/java/android/view/inline/InlinePresentationSpec.aidl new file mode 100644 index 000000000000..efa46c8932b9 --- /dev/null +++ b/core/java/android/view/inline/InlinePresentationSpec.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 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.view.inline; + +parcelable InlinePresentationSpec; diff --git a/core/java/android/view/inline/InlinePresentationSpec.java b/core/java/android/view/inline/InlinePresentationSpec.java new file mode 100644 index 000000000000..1eddef554397 --- /dev/null +++ b/core/java/android/view/inline/InlinePresentationSpec.java @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2019 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.view.inline; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcelable; +import android.util.Size; + +import com.android.internal.util.DataClass; + +/** + * This class represents the presentation specification by which an inline suggestion + * should abide when constructing its UI. Since suggestions are inlined in a + * host application while provided by another source, they need to be consistent + * with the host's look at feel to allow building smooth and integrated UIs. + */ +@DataClass(genEqualsHashCode = true, genToString = true, genBuilder = true) +public final class InlinePresentationSpec implements Parcelable { + /** The minimal size of the suggestion. */ + @NonNull + private final Size mMinSize; + /** The maximal size of the suggestion. */ + @NonNull + private final Size mMaxSize; + + // TODO(b/137800469): add more attributes, such as text appearance info. + + /** @hide */ + @DataClass.Suppress({"setMaxSize", "setMinSize"}) + abstract static class BaseBuilder { + } + + + + // Code below generated by codegen v1.0.14. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/inline/InlinePresentationSpec.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + /* package-private */ InlinePresentationSpec( + @NonNull Size minSize, + @NonNull Size maxSize) { + this.mMinSize = minSize; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mMinSize); + this.mMaxSize = maxSize; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mMaxSize); + + // onConstructed(); // You can define this method to get a callback + } + + /** + * The minimal size of the suggestion. + */ + @DataClass.Generated.Member + public @NonNull Size getMinSize() { + return mMinSize; + } + + /** + * The maximal size of the suggestion. + */ + @DataClass.Generated.Member + public @NonNull Size getMaxSize() { + return mMaxSize; + } + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "InlinePresentationSpec { " + + "minSize = " + mMinSize + ", " + + "maxSize = " + mMaxSize + + " }"; + } + + @Override + @DataClass.Generated.Member + public boolean equals(@Nullable Object o) { + // You can override field equality logic by defining either of the methods like: + // boolean fieldNameEquals(InlinePresentationSpec other) { ... } + // boolean fieldNameEquals(FieldType otherValue) { ... } + + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + @SuppressWarnings("unchecked") + InlinePresentationSpec that = (InlinePresentationSpec) o; + //noinspection PointlessBooleanExpression + return true + && java.util.Objects.equals(mMinSize, that.mMinSize) + && java.util.Objects.equals(mMaxSize, that.mMaxSize); + } + + @Override + @DataClass.Generated.Member + public int hashCode() { + // You can override field hashCode logic by defining methods like: + // int fieldNameHashCode() { ... } + + int _hash = 1; + _hash = 31 * _hash + java.util.Objects.hashCode(mMinSize); + _hash = 31 * _hash + java.util.Objects.hashCode(mMaxSize); + return _hash; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeSize(mMinSize); + dest.writeSize(mMaxSize); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ InlinePresentationSpec(@NonNull android.os.Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + Size minSize = (Size) in.readSize(); + Size maxSize = (Size) in.readSize(); + + this.mMinSize = minSize; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mMinSize); + this.mMaxSize = maxSize; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mMaxSize); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<InlinePresentationSpec> CREATOR + = new Parcelable.Creator<InlinePresentationSpec>() { + @Override + public InlinePresentationSpec[] newArray(int size) { + return new InlinePresentationSpec[size]; + } + + @Override + public InlinePresentationSpec createFromParcel(@NonNull android.os.Parcel in) { + return new InlinePresentationSpec(in); + } + }; + + /** + * A builder for {@link InlinePresentationSpec} + */ + @SuppressWarnings("WeakerAccess") + @DataClass.Generated.Member + public static final class Builder extends BaseBuilder { + + private @NonNull Size mMinSize; + private @NonNull Size mMaxSize; + + private long mBuilderFieldsSet = 0L; + + /** + * Creates a new Builder. + * + * @param minSize + * The minimal size of the suggestion. + * @param maxSize + * The maximal size of the suggestion. + */ + public Builder( + @NonNull Size minSize, + @NonNull Size maxSize) { + mMinSize = minSize; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mMinSize); + mMaxSize = maxSize; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mMaxSize); + } + + /** Builds the instance. This builder should not be touched after calling this! */ + public @NonNull InlinePresentationSpec build() { + checkNotUsed(); + mBuilderFieldsSet |= 0x4; // Mark builder used + + InlinePresentationSpec o = new InlinePresentationSpec( + mMinSize, + mMaxSize); + return o; + } + + private void checkNotUsed() { + if ((mBuilderFieldsSet & 0x4) != 0) { + throw new IllegalStateException( + "This Builder should not be reused. Use a new Builder instance instead"); + } + } + } + + @DataClass.Generated( + time = 1574406062532L, + codegenVersion = "1.0.14", + sourceFile = "frameworks/base/core/java/android/view/inline/InlinePresentationSpec.java", + inputSignatures = "private final @android.annotation.NonNull android.util.Size mMinSize\nprivate final @android.annotation.NonNull android.util.Size mMaxSize\nclass InlinePresentationSpec extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nclass BaseBuilder extends java.lang.Object implements []") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/view/inputmethod/InlineSuggestion.aidl b/core/java/android/view/inputmethod/InlineSuggestion.aidl new file mode 100644 index 000000000000..208d964c94f8 --- /dev/null +++ b/core/java/android/view/inputmethod/InlineSuggestion.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 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.view.inputmethod; + +parcelable InlineSuggestion; diff --git a/core/java/android/view/inputmethod/InlineSuggestion.java b/core/java/android/view/inputmethod/InlineSuggestion.java new file mode 100644 index 000000000000..25e34d36aa9a --- /dev/null +++ b/core/java/android/view/inputmethod/InlineSuggestion.java @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2019 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.view.inputmethod; + +import android.annotation.CallbackExecutor; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.os.AsyncTask; +import android.os.Parcelable; +import android.os.RemoteException; +import android.util.Size; +import android.util.Slog; +import android.view.SurfaceControl; +import android.view.View; +import android.view.inline.InlineContentView; +import android.view.inline.InlinePresentationSpec; + +import com.android.internal.util.DataClass; +import com.android.internal.view.inline.IInlineContentCallback; +import com.android.internal.view.inline.IInlineContentProvider; + +import java.lang.ref.WeakReference; +import java.util.concurrent.Executor; +import java.util.function.Consumer; + +/** + * This class represents an inline suggestion which is made by one app + * and can be embedded into the UI of another. Suggestions may contain + * sensitive information not known to the host app which needs to be + * protected from spoofing. To address that the suggestion view inflated + * on demand for embedding is created in such a way that the hosting app + * cannot introspect its content and cannot interact with it. + */ +@DataClass( + genEqualsHashCode = true, + genToString = true, + genHiddenConstDefs = true, + genHiddenConstructor = true) +@DataClass.Suppress({"getContentProvider"}) +public final class InlineSuggestion implements Parcelable { + + private static final String TAG = "InlineSuggestion"; + + private final @NonNull InlineSuggestionInfo mInfo; + + private final @Nullable IInlineContentProvider mContentProvider; + + /** + * Inflates a view with the content of this suggestion at a specific size. + * The size must be between the {@link InlinePresentationSpec#getMinSize() min size} + * and the {@link InlinePresentationSpec#getMaxSize() max size} of the presentation + * spec returned by {@link InlineSuggestionInfo#getPresentationSpec()}. If an invalid + * argument is passed an exception is thrown. + * + * @param context Context in which to inflate the view. + * @param size The size at which to inflate the suggestion. + * @param callback Callback for receiving the inflated view. + */ + public void inflate(@NonNull Context context, @NonNull Size size, + @NonNull @CallbackExecutor Executor callbackExecutor, + @NonNull Consumer<View> callback) { + final Size minSize = mInfo.getPresentationSpec().getMinSize(); + final Size maxSize = mInfo.getPresentationSpec().getMaxSize(); + if (size.getHeight() < minSize.getHeight() || size.getHeight() > maxSize.getHeight() + || size.getWidth() < minSize.getWidth() || size.getWidth() > maxSize.getWidth()) { + throw new IllegalArgumentException("size not between min:" + + minSize + " and max:" + maxSize); + } + AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> { + if (mContentProvider == null) { + callback.accept(/* view */ null); + return; + } + // TODO(b/137800469): keep a strong reference to the contentCallback so it doesn't + // get GC'd. Also add a isInflated() method and make sure the view can only be + // inflated once. + try { + InlineContentCallbackImpl contentCallback = new InlineContentCallbackImpl(context, + callbackExecutor, callback); + mContentProvider.provideContent(size.getWidth(), size.getHeight(), + new InlineContentCallbackWrapper(contentCallback)); + } catch (RemoteException e) { + Slog.w(TAG, "Error creating suggestion content surface: " + e); + callback.accept(/* view */ null); + } + }); + } + + private static final class InlineContentCallbackWrapper extends IInlineContentCallback.Stub { + + private final WeakReference<InlineContentCallbackImpl> mCallbackImpl; + + InlineContentCallbackWrapper(InlineContentCallbackImpl callbackImpl) { + mCallbackImpl = new WeakReference<>(callbackImpl); + } + + @Override + public void onContent(SurfaceControl content) { + final InlineContentCallbackImpl callbackImpl = mCallbackImpl.get(); + if (callbackImpl != null) { + callbackImpl.onContent(content); + } + } + } + + private static final class InlineContentCallbackImpl { + + private final @NonNull Context mContext; + private final @NonNull Executor mCallbackExecutor; + private final @NonNull Consumer<View> mCallback; + + InlineContentCallbackImpl(@NonNull Context context, + @NonNull @CallbackExecutor Executor callbackExecutor, + @NonNull Consumer<View> callback) { + mContext = context; + mCallbackExecutor = callbackExecutor; + mCallback = callback; + } + + public void onContent(SurfaceControl content) { + if (content == null) { + mCallbackExecutor.execute(() -> mCallback.accept(/* view */null)); + } else { + mCallbackExecutor.execute( + () -> mCallback.accept(new InlineContentView(mContext, content))); + } + } + } + + + + // Code below generated by codegen v1.0.14. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/inputmethod/InlineSuggestion.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + /** + * Creates a new InlineSuggestion. + * + * @hide + */ + @DataClass.Generated.Member + public InlineSuggestion( + @NonNull InlineSuggestionInfo info, + @Nullable IInlineContentProvider contentProvider) { + this.mInfo = info; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mInfo); + this.mContentProvider = contentProvider; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public @NonNull InlineSuggestionInfo getInfo() { + return mInfo; + } + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "InlineSuggestion { " + + "info = " + mInfo + ", " + + "contentProvider = " + mContentProvider + + " }"; + } + + @Override + @DataClass.Generated.Member + public boolean equals(@Nullable Object o) { + // You can override field equality logic by defining either of the methods like: + // boolean fieldNameEquals(InlineSuggestion other) { ... } + // boolean fieldNameEquals(FieldType otherValue) { ... } + + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + @SuppressWarnings("unchecked") + InlineSuggestion that = (InlineSuggestion) o; + //noinspection PointlessBooleanExpression + return true + && java.util.Objects.equals(mInfo, that.mInfo) + && java.util.Objects.equals(mContentProvider, that.mContentProvider); + } + + @Override + @DataClass.Generated.Member + public int hashCode() { + // You can override field hashCode logic by defining methods like: + // int fieldNameHashCode() { ... } + + int _hash = 1; + _hash = 31 * _hash + java.util.Objects.hashCode(mInfo); + _hash = 31 * _hash + java.util.Objects.hashCode(mContentProvider); + return _hash; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + byte flg = 0; + if (mContentProvider != null) flg |= 0x2; + dest.writeByte(flg); + dest.writeTypedObject(mInfo, flags); + if (mContentProvider != null) dest.writeStrongInterface(mContentProvider); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ InlineSuggestion(@NonNull android.os.Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + byte flg = in.readByte(); + InlineSuggestionInfo info = (InlineSuggestionInfo) in.readTypedObject(InlineSuggestionInfo.CREATOR); + IInlineContentProvider contentProvider = (flg & 0x2) == 0 ? null : IInlineContentProvider.Stub.asInterface(in.readStrongBinder()); + + this.mInfo = info; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mInfo); + this.mContentProvider = contentProvider; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<InlineSuggestion> CREATOR + = new Parcelable.Creator<InlineSuggestion>() { + @Override + public InlineSuggestion[] newArray(int size) { + return new InlineSuggestion[size]; + } + + @Override + public InlineSuggestion createFromParcel(@NonNull android.os.Parcel in) { + return new InlineSuggestion(in); + } + }; + + @DataClass.Generated( + time = 1574446220398L, + codegenVersion = "1.0.14", + sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestion.java", + inputSignatures = "private static final java.lang.String TAG\nprivate final @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo mInfo\nprivate final @android.annotation.Nullable com.android.internal.view.inline.IInlineContentProvider mContentProvider\npublic void inflate(android.content.Context,android.util.Size,java.util.concurrent.Executor,java.util.function.Consumer<android.view.View>)\nclass InlineSuggestion extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/view/inputmethod/InlineSuggestionInfo.aidl b/core/java/android/view/inputmethod/InlineSuggestionInfo.aidl new file mode 100644 index 000000000000..168bd0b2d242 --- /dev/null +++ b/core/java/android/view/inputmethod/InlineSuggestionInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 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.view.inputmethod; + +parcelable InlineSuggestionInfo; diff --git a/core/java/android/view/inputmethod/InlineSuggestionInfo.java b/core/java/android/view/inputmethod/InlineSuggestionInfo.java new file mode 100644 index 000000000000..07fce3101d85 --- /dev/null +++ b/core/java/android/view/inputmethod/InlineSuggestionInfo.java @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2019 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.view.inputmethod; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcelable; +import android.view.inline.InlinePresentationSpec; + +import com.android.internal.util.DataClass; + +/** + * This class represents the description of an inline suggestion. It contains information to help + * the IME to decide where and when to show the suggestions. See {@link InlineSuggestion} for more + * information. + */ +@DataClass( + genEqualsHashCode = true, + genToString = true, + genHiddenConstDefs = true, + genHiddenConstructor = true) +public final class InlineSuggestionInfo implements Parcelable { + + /** + * Suggestion source: the suggestion is made by the user selected autofill service. + */ + public static final @Source String SOURCE_AUTOFILL = "android:autofill"; + /** + * Suggestion source: the suggestion is made by the platform. + */ + public static final @Source String SOURCE_PLATFORM = "android:platform"; + + /** The presentation spec to which the inflated suggestion view abides. */ + private final @NonNull InlinePresentationSpec mPresentationSpec; + + /** The source from which the suggestion is provided. */ + private final @NonNull @Source String mSource; + + /** Hints for the type of data being suggested. */ + private final @Nullable String[] mAutofillHints; + + + + + // Code below generated by codegen v1.0.14. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/inputmethod/InlineSuggestionInfo.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + /** @hide */ + @android.annotation.StringDef(prefix = "SOURCE_", value = { + SOURCE_AUTOFILL, + SOURCE_PLATFORM + }) + @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) + @DataClass.Generated.Member + public @interface Source {} + + /** + * Creates a new InlineSuggestionInfo. + * + * @param presentationSpec + * The presentation spec to which the inflated suggestion view abides. + * @param source + * The source from which the suggestion is provided. + * @param autofillHints + * Hints for the type of data being suggested. + * @hide + */ + @DataClass.Generated.Member + public InlineSuggestionInfo( + @NonNull InlinePresentationSpec presentationSpec, + @NonNull @Source String source, + @Nullable String[] autofillHints) { + this.mPresentationSpec = presentationSpec; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mPresentationSpec); + this.mSource = source; + + if (!(java.util.Objects.equals(mSource, SOURCE_AUTOFILL)) + && !(java.util.Objects.equals(mSource, SOURCE_PLATFORM))) { + throw new java.lang.IllegalArgumentException( + "source was " + mSource + " but must be one of: " + + "SOURCE_AUTOFILL(" + SOURCE_AUTOFILL + "), " + + "SOURCE_PLATFORM(" + SOURCE_PLATFORM + ")"); + } + + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mSource); + this.mAutofillHints = autofillHints; + + // onConstructed(); // You can define this method to get a callback + } + + /** + * The presentation spec to which the inflated suggestion view abides. + */ + @DataClass.Generated.Member + public @NonNull InlinePresentationSpec getPresentationSpec() { + return mPresentationSpec; + } + + /** + * The source from which the suggestion is provided. + */ + @DataClass.Generated.Member + public @NonNull @Source String getSource() { + return mSource; + } + + /** + * Hints for the type of data being suggested. + */ + @DataClass.Generated.Member + public @Nullable String[] getAutofillHints() { + return mAutofillHints; + } + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "InlineSuggestionInfo { " + + "presentationSpec = " + mPresentationSpec + ", " + + "source = " + mSource + ", " + + "autofillHints = " + java.util.Arrays.toString(mAutofillHints) + + " }"; + } + + @Override + @DataClass.Generated.Member + public boolean equals(@Nullable Object o) { + // You can override field equality logic by defining either of the methods like: + // boolean fieldNameEquals(InlineSuggestionInfo other) { ... } + // boolean fieldNameEquals(FieldType otherValue) { ... } + + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + @SuppressWarnings("unchecked") + InlineSuggestionInfo that = (InlineSuggestionInfo) o; + //noinspection PointlessBooleanExpression + return true + && java.util.Objects.equals(mPresentationSpec, that.mPresentationSpec) + && java.util.Objects.equals(mSource, that.mSource) + && java.util.Arrays.equals(mAutofillHints, that.mAutofillHints); + } + + @Override + @DataClass.Generated.Member + public int hashCode() { + // You can override field hashCode logic by defining methods like: + // int fieldNameHashCode() { ... } + + int _hash = 1; + _hash = 31 * _hash + java.util.Objects.hashCode(mPresentationSpec); + _hash = 31 * _hash + java.util.Objects.hashCode(mSource); + _hash = 31 * _hash + java.util.Arrays.hashCode(mAutofillHints); + return _hash; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + byte flg = 0; + if (mAutofillHints != null) flg |= 0x4; + dest.writeByte(flg); + dest.writeTypedObject(mPresentationSpec, flags); + dest.writeString(mSource); + if (mAutofillHints != null) dest.writeStringArray(mAutofillHints); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ InlineSuggestionInfo(@NonNull android.os.Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + byte flg = in.readByte(); + InlinePresentationSpec presentationSpec = (InlinePresentationSpec) in.readTypedObject(InlinePresentationSpec.CREATOR); + String source = in.readString(); + String[] autofillHints = (flg & 0x4) == 0 ? null : in.createStringArray(); + + this.mPresentationSpec = presentationSpec; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mPresentationSpec); + this.mSource = source; + + if (!(java.util.Objects.equals(mSource, SOURCE_AUTOFILL)) + && !(java.util.Objects.equals(mSource, SOURCE_PLATFORM))) { + throw new java.lang.IllegalArgumentException( + "source was " + mSource + " but must be one of: " + + "SOURCE_AUTOFILL(" + SOURCE_AUTOFILL + "), " + + "SOURCE_PLATFORM(" + SOURCE_PLATFORM + ")"); + } + + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mSource); + this.mAutofillHints = autofillHints; + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<InlineSuggestionInfo> CREATOR + = new Parcelable.Creator<InlineSuggestionInfo>() { + @Override + public InlineSuggestionInfo[] newArray(int size) { + return new InlineSuggestionInfo[size]; + } + + @Override + public InlineSuggestionInfo createFromParcel(@NonNull android.os.Parcel in) { + return new InlineSuggestionInfo(in); + } + }; + + @DataClass.Generated( + time = 1574406074120L, + codegenVersion = "1.0.14", + sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionInfo.java", + inputSignatures = "public static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_AUTOFILL\npublic static final @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String SOURCE_PLATFORM\nprivate final @android.annotation.NonNull android.view.inline.InlinePresentationSpec mPresentationSpec\nprivate final @android.annotation.NonNull @android.view.inputmethod.InlineSuggestionInfo.Source java.lang.String mSource\nprivate final @android.annotation.Nullable java.lang.String[] mAutofillHints\nclass InlineSuggestionInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/view/inputmethod/InlineSuggestionsRequest.aidl b/core/java/android/view/inputmethod/InlineSuggestionsRequest.aidl new file mode 100644 index 000000000000..5a8abd2bf6a3 --- /dev/null +++ b/core/java/android/view/inputmethod/InlineSuggestionsRequest.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 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.view.inputmethod; + +parcelable InlineSuggestionsRequest; diff --git a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java new file mode 100644 index 000000000000..dd609ee70810 --- /dev/null +++ b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java @@ -0,0 +1,261 @@ +/* + * Copyright (C) 2019 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.view.inputmethod; + +import android.annotation.NonNull; +import android.os.Parcelable; +import android.view.inline.InlinePresentationSpec; + +import com.android.internal.util.DataClass; +import com.android.internal.util.Preconditions; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class represents an inline suggestion request made by one app to get suggestions from the + * other source. See {@link InlineSuggestion} for more information. + */ +@DataClass(genEqualsHashCode = true, genToString = true, genBuilder = true) +public final class InlineSuggestionsRequest implements Parcelable { + + /** Constant used to indicate not putting a cap on the number of suggestions to return. */ + public static final int SUGGESTION_COUNT_UNLIMITED = Integer.MAX_VALUE; + + private final int mMaxSuggestionCount; + private final @NonNull List<InlinePresentationSpec> mPresentationSpecs; + + private void onConstructed() { + Preconditions.checkState(mMaxSuggestionCount >= mPresentationSpecs.size()); + } + + private static int defaultMaxSuggestionCount() { + return SUGGESTION_COUNT_UNLIMITED; + } + + /** @hide */ + abstract static class BaseBuilder { + abstract Builder setPresentationSpecs(@NonNull List<InlinePresentationSpec> value); + } + + + + // Code below generated by codegen v1.0.14. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + @DataClass.Generated.Member + /* package-private */ InlineSuggestionsRequest( + int maxSuggestionCount, + @NonNull List<InlinePresentationSpec> presentationSpecs) { + this.mMaxSuggestionCount = maxSuggestionCount; + this.mPresentationSpecs = presentationSpecs; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mPresentationSpecs); + + onConstructed(); + } + + @DataClass.Generated.Member + public int getMaxSuggestionCount() { + return mMaxSuggestionCount; + } + + @DataClass.Generated.Member + public @NonNull List<InlinePresentationSpec> getPresentationSpecs() { + return mPresentationSpecs; + } + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "InlineSuggestionsRequest { " + + "maxSuggestionCount = " + mMaxSuggestionCount + ", " + + "presentationSpecs = " + mPresentationSpecs + + " }"; + } + + @Override + @DataClass.Generated.Member + public boolean equals(@android.annotation.Nullable Object o) { + // You can override field equality logic by defining either of the methods like: + // boolean fieldNameEquals(InlineSuggestionsRequest other) { ... } + // boolean fieldNameEquals(FieldType otherValue) { ... } + + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + @SuppressWarnings("unchecked") + InlineSuggestionsRequest that = (InlineSuggestionsRequest) o; + //noinspection PointlessBooleanExpression + return true + && mMaxSuggestionCount == that.mMaxSuggestionCount + && java.util.Objects.equals(mPresentationSpecs, that.mPresentationSpecs); + } + + @Override + @DataClass.Generated.Member + public int hashCode() { + // You can override field hashCode logic by defining methods like: + // int fieldNameHashCode() { ... } + + int _hash = 1; + _hash = 31 * _hash + mMaxSuggestionCount; + _hash = 31 * _hash + java.util.Objects.hashCode(mPresentationSpecs); + return _hash; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeInt(mMaxSuggestionCount); + dest.writeParcelableList(mPresentationSpecs, flags); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ InlineSuggestionsRequest(@NonNull android.os.Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + int maxSuggestionCount = in.readInt(); + List<InlinePresentationSpec> presentationSpecs = new ArrayList<>(); + in.readParcelableList(presentationSpecs, InlinePresentationSpec.class.getClassLoader()); + + this.mMaxSuggestionCount = maxSuggestionCount; + this.mPresentationSpecs = presentationSpecs; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mPresentationSpecs); + + onConstructed(); + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<InlineSuggestionsRequest> CREATOR + = new Parcelable.Creator<InlineSuggestionsRequest>() { + @Override + public InlineSuggestionsRequest[] newArray(int size) { + return new InlineSuggestionsRequest[size]; + } + + @Override + public InlineSuggestionsRequest createFromParcel(@NonNull android.os.Parcel in) { + return new InlineSuggestionsRequest(in); + } + }; + + /** + * A builder for {@link InlineSuggestionsRequest} + */ + @SuppressWarnings("WeakerAccess") + @DataClass.Generated.Member + public static final class Builder extends BaseBuilder { + + private int mMaxSuggestionCount; + private @NonNull List<InlinePresentationSpec> mPresentationSpecs; + + private long mBuilderFieldsSet = 0L; + + public Builder( + @NonNull List<InlinePresentationSpec> presentationSpecs) { + mPresentationSpecs = presentationSpecs; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mPresentationSpecs); + } + + @DataClass.Generated.Member + public @NonNull Builder setMaxSuggestionCount(int value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x1; + mMaxSuggestionCount = value; + return this; + } + + @DataClass.Generated.Member + @Override + @NonNull Builder setPresentationSpecs(@NonNull List<InlinePresentationSpec> value) { + checkNotUsed(); + mBuilderFieldsSet |= 0x2; + mPresentationSpecs = value; + return this; + } + + /** @see #setPresentationSpecs */ + @DataClass.Generated.Member + public @NonNull Builder addPresentationSpecs(@NonNull InlinePresentationSpec value) { + // You can refine this method's name by providing item's singular name, e.g.: + // @DataClass.PluralOf("item")) mItems = ... + + if (mPresentationSpecs == null) setPresentationSpecs(new ArrayList<>()); + mPresentationSpecs.add(value); + return this; + } + + /** Builds the instance. This builder should not be touched after calling this! */ + public @NonNull InlineSuggestionsRequest build() { + checkNotUsed(); + mBuilderFieldsSet |= 0x4; // Mark builder used + + if ((mBuilderFieldsSet & 0x1) == 0) { + mMaxSuggestionCount = defaultMaxSuggestionCount(); + } + InlineSuggestionsRequest o = new InlineSuggestionsRequest( + mMaxSuggestionCount, + mPresentationSpecs); + return o; + } + + private void checkNotUsed() { + if ((mBuilderFieldsSet & 0x4) != 0) { + throw new IllegalStateException( + "This Builder should not be reused. Use a new Builder instance instead"); + } + } + } + + @DataClass.Generated( + time = 1574406255024L, + codegenVersion = "1.0.14", + sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java", + inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.view.inline.InlinePresentationSpec> mPresentationSpecs\nprivate void onConstructed()\nprivate static int defaultMaxSuggestionCount()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setPresentationSpecs(java.util.List<android.view.inline.InlinePresentationSpec>)\nclass BaseBuilder extends java.lang.Object implements []") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/view/inputmethod/InlineSuggestionsResponse.aidl b/core/java/android/view/inputmethod/InlineSuggestionsResponse.aidl new file mode 100644 index 000000000000..9343fe934db2 --- /dev/null +++ b/core/java/android/view/inputmethod/InlineSuggestionsResponse.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 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.view.inputmethod; + +parcelable InlineSuggestionsResponse; diff --git a/core/java/android/view/inputmethod/InlineSuggestionsResponse.java b/core/java/android/view/inputmethod/InlineSuggestionsResponse.java new file mode 100644 index 000000000000..924a5eee784b --- /dev/null +++ b/core/java/android/view/inputmethod/InlineSuggestionsResponse.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2019 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.view.inputmethod; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcelable; + +import com.android.internal.util.DataClass; + +import java.util.ArrayList; +import java.util.List; + +/** + * This class represents an inline suggestion response. See {@link InlineSuggestion} for more + * information. + */ +@DataClass(genEqualsHashCode = true, genToString = true, genHiddenConstructor = true) +public final class InlineSuggestionsResponse implements Parcelable { + private final @NonNull List<InlineSuggestion> mInlineSuggestions; + + + + // Code below generated by codegen v1.0.14. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsResponse.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + /** + * Creates a new InlineSuggestionsResponse. + * + * @hide + */ + @DataClass.Generated.Member + public InlineSuggestionsResponse( + @NonNull List<InlineSuggestion> inlineSuggestions) { + this.mInlineSuggestions = inlineSuggestions; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mInlineSuggestions); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public @NonNull List<InlineSuggestion> getInlineSuggestions() { + return mInlineSuggestions; + } + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "InlineSuggestionsResponse { " + + "inlineSuggestions = " + mInlineSuggestions + + " }"; + } + + @Override + @DataClass.Generated.Member + public boolean equals(@Nullable Object o) { + // You can override field equality logic by defining either of the methods like: + // boolean fieldNameEquals(InlineSuggestionsResponse other) { ... } + // boolean fieldNameEquals(FieldType otherValue) { ... } + + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + @SuppressWarnings("unchecked") + InlineSuggestionsResponse that = (InlineSuggestionsResponse) o; + //noinspection PointlessBooleanExpression + return true + && java.util.Objects.equals(mInlineSuggestions, that.mInlineSuggestions); + } + + @Override + @DataClass.Generated.Member + public int hashCode() { + // You can override field hashCode logic by defining methods like: + // int fieldNameHashCode() { ... } + + int _hash = 1; + _hash = 31 * _hash + java.util.Objects.hashCode(mInlineSuggestions); + return _hash; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeParcelableList(mInlineSuggestions, flags); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ InlineSuggestionsResponse(@NonNull android.os.Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + List<InlineSuggestion> inlineSuggestions = new ArrayList<>(); + in.readParcelableList(inlineSuggestions, InlineSuggestion.class.getClassLoader()); + + this.mInlineSuggestions = inlineSuggestions; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mInlineSuggestions); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<InlineSuggestionsResponse> CREATOR + = new Parcelable.Creator<InlineSuggestionsResponse>() { + @Override + public InlineSuggestionsResponse[] newArray(int size) { + return new InlineSuggestionsResponse[size]; + } + + @Override + public InlineSuggestionsResponse createFromParcel(@NonNull android.os.Parcel in) { + return new InlineSuggestionsResponse(in); + } + }; + + @DataClass.Generated( + time = 1574406147911L, + codegenVersion = "1.0.14", + sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsResponse.java", + inputSignatures = "private final @android.annotation.NonNull java.util.List<android.view.inputmethod.InlineSuggestion> mInlineSuggestions\nclass InlineSuggestionsResponse extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstructor=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/java/android/widget/ArrayAdapter.java b/core/java/android/widget/ArrayAdapter.java index 2bf1ba5cf017..f7225d036e15 100644 --- a/core/java/android/widget/ArrayAdapter.java +++ b/core/java/android/widget/ArrayAdapter.java @@ -49,9 +49,6 @@ import java.util.List; * To customize what type of view is used for the data object, * override {@link #getView(int, View, ViewGroup)} * and inflate a view resource. - * For a code example, see - * the <a href="https://github.com/googlesamples/android-CustomChoiceList/#readme"> - * CustomChoiceList</a> sample. * </p> * <p> * For an example of using an array adapter with a ListView, see the diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 86cec5e0f0a2..c571737cec8f 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -202,6 +202,14 @@ public class RemoteViews implements Parcelable, Filter { public static final int FLAG_USE_LIGHT_BACKGROUND_LAYOUT = 4; /** + * Used to restrict the views which can be inflated + * + * @see android.view.LayoutInflater.Filter#onLoadClass(java.lang.Class) + */ + private static final LayoutInflater.Filter INFLATER_FILTER = + (clazz) -> clazz.isAnnotationPresent(RemoteViews.RemoteView.class); + + /** * Application that hosts the remote views. * * @hide @@ -3413,13 +3421,24 @@ public class RemoteViews implements Parcelable, Filter { // Clone inflater so we load resources from correct context and // we don't add a filter to the static version returned by getSystemService. inflater = inflater.cloneInContext(inflationContext); - inflater.setFilter(this); + inflater.setFilter(shouldUseStaticFilter() ? INFLATER_FILTER : this); View v = inflater.inflate(rv.getLayoutId(), parent, false); v.setTagInternal(R.id.widget_frame, rv.getLayoutId()); return v; } /** + * A static filter is much lighter than RemoteViews itself. It's optimized here only for + * RemoteVies class. Subclasses should always override this and return true if not overriding + * {@link this#onLoadClass(Class)}. + * + * @hide + */ + protected boolean shouldUseStaticFilter() { + return this.getClass().equals(RemoteViews.class); + } + + /** * Implement this interface to receive a callback when * {@link #applyAsync} or {@link #reapplyAsync} is finished. * @hide @@ -3686,11 +3705,15 @@ public class RemoteViews implements Parcelable, Filter { return (mActions == null) ? 0 : mActions.size(); } - /* (non-Javadoc) + /** * Used to restrict the views which can be inflated * * @see android.view.LayoutInflater.Filter#onLoadClass(java.lang.Class) + * @deprecated Used by system to enforce safe inflation of {@link RemoteViews}. Apps should not + * override this method. Changing of this method will NOT affect the process where RemoteViews + * is rendered. */ + @Deprecated public boolean onLoadClass(Class clazz) { return clazz.isAnnotationPresent(RemoteView.class); } diff --git a/core/java/com/android/internal/app/TEST_MAPPING b/core/java/com/android/internal/app/TEST_MAPPING new file mode 100644 index 000000000000..373a5d9413a5 --- /dev/null +++ b/core/java/com/android/internal/app/TEST_MAPPING @@ -0,0 +1,20 @@ +{ + "postsubmit": [ + { + "name": "FrameworksCoreTests", + "options": [ + { + "include-filter": "com.android.internal.app." + }, + + // Many tests failing - do not enable for continuous execution + { + "exclude-filter": "com.android.internal.app.IntentForwarderActivityTest" + }, + { + "exclude-filter": "com.android.internal.app.WindowDecorActionBarTest" + } + ] + } + ] +}
\ No newline at end of file diff --git a/core/java/com/android/internal/logging/UiEvent.java b/core/java/com/android/internal/logging/UiEvent.java new file mode 100644 index 000000000000..0407b0704e80 --- /dev/null +++ b/core/java/com/android/internal/logging/UiEvent.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.logging; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +@Retention(SOURCE) +@Target(FIELD) +public @interface UiEvent { + /** An explanation, suitable for Android analysts, of the UI event that this log represents. */ + String doc(); +} diff --git a/core/java/com/android/internal/logging/UiEventLogger.java b/core/java/com/android/internal/logging/UiEventLogger.java new file mode 100644 index 000000000000..cca97f689f4e --- /dev/null +++ b/core/java/com/android/internal/logging/UiEventLogger.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.logging; + +/** + * Logging interface for UI events. Normal implementation is UiEventLoggerImpl. + * For testing, use fake implementation UiEventLoggerFake. + * + * See go/sysui-event-logs and UiEventReported atom in atoms.proto. + */ +public interface UiEventLogger { + /** Put your Event IDs in enums that implement this interface, and document them using the + * UiEventEnum annotation. + * Event IDs must be globally unique. This will be enforced by tooling (forthcoming). + * OEMs should use event IDs above 100000. + */ + interface UiEventEnum { + int getId(); + } + /** + * Log a simple event, with no package or instance ID. + */ + void log(UiEventEnum eventID); +} diff --git a/core/java/com/android/internal/logging/UiEventLoggerImpl.java b/core/java/com/android/internal/logging/UiEventLoggerImpl.java new file mode 100644 index 000000000000..e64fba2d2a31 --- /dev/null +++ b/core/java/com/android/internal/logging/UiEventLoggerImpl.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.logging; + +import android.util.StatsLog; + +/** + * Standard implementation of UiEventLogger, writing to StatsLog. + * + * See UiEventReported atom in atoms.proto for more context. + */ +public class UiEventLoggerImpl implements UiEventLogger { + /** + * Log a simple event, with no package or instance ID. + */ + @Override + public void log(UiEventEnum event) { + final int eventID = event.getId(); + if (eventID > 0) { + StatsLog.write(StatsLog.UI_EVENT_REPORTED, eventID, 0, null); + } + } +} diff --git a/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java b/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java new file mode 100644 index 000000000000..92e9bbb77bd3 --- /dev/null +++ b/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.logging.testing; + +import com.android.internal.logging.UiEventLogger; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * Fake logger that queues up logged events for inspection. + * + * @hide. + */ +public class UiEventLoggerFake implements UiEventLogger { + /** + * Immutable data class used to record fake log events. + */ + public class FakeUiEvent { + public final int eventId; + public final int uid; + public final String packageName; + + public FakeUiEvent(int eventId, int uid, String packageName) { + this.eventId = eventId; + this.uid = uid; + this.packageName = packageName; + } + } + + private Queue<FakeUiEvent> mLogs = new LinkedList<FakeUiEvent>(); + + @Override + public void log(UiEventEnum event) { + final int eventId = event.getId(); + if (eventId > 0) { + mLogs.offer(new FakeUiEvent(eventId, 0, null)); + } + } + + public Queue<FakeUiEvent> getLogs() { + return mLogs; + } +} diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index f3de34be2e69..fbacdd73dabb 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -956,9 +956,9 @@ public final class Zygote { // This function is called from native code in com_android_internal_os_Zygote.cpp @SuppressWarnings("unused") - private static void callPostForkSystemServerHooks() { + private static void callPostForkSystemServerHooks(int runtimeFlags) { // SystemServer specific post fork hooks run before child post fork hooks. - ZygoteHooks.postForkSystemServer(); + ZygoteHooks.postForkSystemServer(runtimeFlags); } // This function is called from native code in com_android_internal_os_Zygote.cpp diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index 227ef28cd129..764d4a598bd5 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -3109,8 +3109,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // On TVs, if the app doesn't implement search, we want to launch assist. Bundle args = new Bundle(); args.putInt(Intent.EXTRA_ASSIST_INPUT_DEVICE_ID, event.getDeviceId()); - return ((SearchManager)getContext().getSystemService(Context.SEARCH_SERVICE)) - .launchLegacyAssist(null, getContext().getUserId(), args); + ((SearchManager) getContext().getSystemService(Context.SEARCH_SERVICE)) + .launchAssist(args); + return true; } return result; } diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambda.java b/core/java/com/android/internal/util/function/pooled/PooledLambda.java index d32ff060a8d7..a60cc0fb101f 100755 --- a/core/java/com/android/internal/util/function/pooled/PooledLambda.java +++ b/core/java/com/android/internal/util/function/pooled/PooledLambda.java @@ -383,7 +383,7 @@ public interface PooledLambda { QuadPredicate<? super A, ? super B, ? super C, ? super D> function, ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) { return acquire(PooledLambdaImpl.sPool, - function, 3, 1, ReturnType.BOOLEAN, arg1, arg2, arg3, arg4, null, null, null, null, + function, 4, 1, ReturnType.BOOLEAN, arg1, arg2, arg3, arg4, null, null, null, null, null, null, null); } @@ -404,7 +404,7 @@ public interface PooledLambda { QuintPredicate<? super A, ? super B, ? super C, ? super D, ? super E> function, ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4, E arg5) { return acquire(PooledLambdaImpl.sPool, - function, 3, 1, ReturnType.BOOLEAN, arg1, arg2, arg3, arg4, arg5, null, null, null, + function, 5, 1, ReturnType.BOOLEAN, arg1, arg2, arg3, arg4, arg5, null, null, null, null, null, null); } diff --git a/core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl b/core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl new file mode 100644 index 000000000000..6b5491013f00 --- /dev/null +++ b/core/java/com/android/internal/view/IInlineSuggestionsRequestCallback.aidl @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.view; + +import android.view.inputmethod.InlineSuggestionsRequest; + +import com.android.internal.view.IInlineSuggestionsResponseCallback; + +/** + * Binder interface for the IME service to send an inline suggestion request to the system. + * {@hide} + */ +oneway interface IInlineSuggestionsRequestCallback { + void onInlineSuggestionsUnsupported(); + void onInlineSuggestionsRequest(in InlineSuggestionsRequest request, + in IInlineSuggestionsResponseCallback callback); +} diff --git a/core/java/com/android/internal/view/IInlineSuggestionsResponseCallback.aidl b/core/java/com/android/internal/view/IInlineSuggestionsResponseCallback.aidl new file mode 100644 index 000000000000..0f93b8ebdb53 --- /dev/null +++ b/core/java/com/android/internal/view/IInlineSuggestionsResponseCallback.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.view; + +import android.view.inputmethod.InlineSuggestionsResponse; + +/** + * Binder interface for the IME service to receive an inline suggestion response from the system. + * {@hide} + */ +oneway interface IInlineSuggestionsResponseCallback { + void onInlineSuggestionsResponse(in InlineSuggestionsResponse response); +} diff --git a/core/java/com/android/internal/view/inline/IInlineContentCallback.aidl b/core/java/com/android/internal/view/inline/IInlineContentCallback.aidl new file mode 100644 index 000000000000..8cc49ca210be --- /dev/null +++ b/core/java/com/android/internal/view/inline/IInlineContentCallback.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.view.inline; + +import android.view.SurfaceControl; + +/** + * Binder interface to send the inline content from one process to the other. + * {@hide} + */ +oneway interface IInlineContentCallback { + void onContent(in SurfaceControl content); +} diff --git a/core/java/com/android/internal/view/inline/IInlineContentProvider.aidl b/core/java/com/android/internal/view/inline/IInlineContentProvider.aidl new file mode 100644 index 000000000000..08a349c21c8b --- /dev/null +++ b/core/java/com/android/internal/view/inline/IInlineContentProvider.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.view.inline; + +import com.android.internal.view.inline.IInlineContentCallback; + +/** + * Binder interface for a process to request the inline content from the other process. + * {@hide} + */ +oneway interface IInlineContentProvider { + void provideContent(int width, int height, in IInlineContentCallback callback); +} diff --git a/core/jni/Android.bp b/core/jni/Android.bp index ea1094913a26..51f8fcc264dc 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -125,6 +125,7 @@ cc_library_shared { "android_text_Hyphenator.cpp", "android_os_Debug.cpp", "android_os_GraphicsEnvironment.cpp", + "android_os_HidlMemory.cpp", "android_os_HidlSupport.cpp", "android_os_HwBinder.cpp", "android_os_HwBlob.cpp", diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 32d62fe2cdba..378e125a3a3e 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -147,6 +147,7 @@ extern int register_android_os_SystemClock(JNIEnv* env); extern int register_android_os_Trace(JNIEnv* env); extern int register_android_os_FileObserver(JNIEnv *env); extern int register_android_os_UEventObserver(JNIEnv* env); +extern int register_android_os_HidlMemory(JNIEnv* env); extern int register_android_os_MemoryFile(JNIEnv* env); extern int register_android_os_SharedMemory(JNIEnv* env); extern int register_android_net_LocalSocketImpl(JNIEnv* env); @@ -1432,6 +1433,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_os_SystemProperties), REG_JNI(register_android_os_Binder), REG_JNI(register_android_os_Parcel), + REG_JNI(register_android_os_HidlMemory), REG_JNI(register_android_os_HidlSupport), REG_JNI(register_android_os_HwBinder), REG_JNI(register_android_os_HwBlob), diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index 0487e139d264..2dec4b399e57 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -223,104 +223,39 @@ void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap) { bitmap->getSkBitmap(outBitmap); } -Bitmap& toBitmap(JNIEnv* env, jobject bitmap) { - SkASSERT(env); - SkASSERT(bitmap); - SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class)); - jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr); - LocalScopedBitmap localBitmap(bitmapHandle); - return localBitmap->bitmap(); -} - Bitmap& toBitmap(jlong bitmapHandle) { LocalScopedBitmap localBitmap(bitmapHandle); return localBitmap->bitmap(); } -void imageInfo(JNIEnv* env, jobject bitmap, AndroidBitmapInfo* info) { - jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr); - LocalScopedBitmap localBitmap(bitmapHandle); +} // namespace bitmap - const SkImageInfo& imageInfo = localBitmap->info(); - info->width = imageInfo.width(); - info->height = imageInfo.height(); - info->stride = localBitmap->rowBytes(); - info->flags = 0; - switch (imageInfo.colorType()) { - case kN32_SkColorType: - info->format = ANDROID_BITMAP_FORMAT_RGBA_8888; - break; - case kRGB_565_SkColorType: - info->format = ANDROID_BITMAP_FORMAT_RGB_565; - break; - case kARGB_4444_SkColorType: - info->format = ANDROID_BITMAP_FORMAT_RGBA_4444; - break; - case kAlpha_8_SkColorType: - info->format = ANDROID_BITMAP_FORMAT_A_8; - break; - case kRGBA_F16_SkColorType: - info->format = ANDROID_BITMAP_FORMAT_RGBA_F16; - break; - default: - info->format = ANDROID_BITMAP_FORMAT_NONE; - break; - } - switch (imageInfo.alphaType()) { - case kUnknown_SkAlphaType: - LOG_ALWAYS_FATAL("Bitmap has no alpha type"); - break; - case kOpaque_SkAlphaType: - info->flags |= ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE; - break; - case kPremul_SkAlphaType: - info->flags |= ANDROID_BITMAP_FLAGS_ALPHA_PREMUL; - break; - case kUnpremul_SkAlphaType: - info->flags |= ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL; - break; - } -} +} // namespace android -void* lockPixels(JNIEnv* env, jobject bitmap) { +using namespace android; +using namespace android::bitmap; + +Bitmap* GraphicsJNI::getNativeBitmap(JNIEnv* env, jobject bitmap) { SkASSERT(env); SkASSERT(bitmap); SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class)); jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr); - LocalScopedBitmap localBitmap(bitmapHandle); - if (!localBitmap->valid()) return nullptr; - - SkPixelRef& pixelRef = localBitmap->bitmap(); - if (!pixelRef.pixels()) { - return nullptr; - } - pixelRef.ref(); - return pixelRef.pixels(); + return localBitmap.valid() ? &localBitmap->bitmap() : nullptr; } -bool unlockPixels(JNIEnv* env, jobject bitmap) { +SkImageInfo GraphicsJNI::getBitmapInfo(JNIEnv* env, jobject bitmap, uint32_t* outRowBytes) { SkASSERT(env); SkASSERT(bitmap); SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class)); jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr); - LocalScopedBitmap localBitmap(bitmapHandle); - if (!localBitmap->valid()) return false; - - SkPixelRef& pixelRef = localBitmap->bitmap(); - pixelRef.notifyPixelsChanged(); - pixelRef.unref(); - return true; + if (outRowBytes) { + *outRowBytes = localBitmap->rowBytes(); + } + return localBitmap->info(); } -} // namespace bitmap - -} // namespace android - -using namespace android; -using namespace android::bitmap; - bool GraphicsJNI::SetPixels(JNIEnv* env, jintArray srcColors, int srcOffset, int srcStride, int x, int y, int width, int height, SkBitmap* dstBitmap) { const jint* array = env->GetIntArrayElements(srcColors, NULL); diff --git a/core/jni/android/graphics/Bitmap.h b/core/jni/android/graphics/Bitmap.h index 59adbb207a0c..73eca3aa8ef8 100644 --- a/core/jni/android/graphics/Bitmap.h +++ b/core/jni/android/graphics/Bitmap.h @@ -38,17 +38,8 @@ jobject createBitmap(JNIEnv* env, Bitmap* bitmap, int bitmapCreateFlags, jbyteArray ninePatchChunk = nullptr, jobject ninePatchInsets = nullptr, int density = -1); - -Bitmap& toBitmap(JNIEnv* env, jobject bitmap); Bitmap& toBitmap(jlong bitmapHandle); -// NDK access -void imageInfo(JNIEnv* env, jobject bitmap, AndroidBitmapInfo* info); -// Returns a pointer to the pixels or nullptr if the bitmap is not valid -void* lockPixels(JNIEnv* env, jobject bitmap); -// Returns true if unlocked, false if the bitmap is no longer valid (destroyed) -bool unlockPixels(JNIEnv* env, jobject bitmap); - /** Reinitialize a bitmap. bitmap must already have its SkAlphaType set in sync with isPremultiplied */ diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index bc1cc09506ad..aa209cb3899e 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -342,10 +342,6 @@ SkColorType GraphicsJNI::legacyBitmapConfigToColorType(jint legacyConfig) { return static_cast<SkColorType>(gConfig2ColorType[legacyConfig]); } -void GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap, SkBitmap* outBitmap) { - bitmap::toBitmap(env, bitmap).getSkBitmap(outBitmap); -} - AndroidBitmapFormat GraphicsJNI::getFormatFromConfig(JNIEnv* env, jobject jconfig) { ALOG_ASSERT(env); if (NULL == jconfig) { diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index 6e7d9e736c0a..99034edaadf7 100644 --- a/core/jni/android/graphics/GraphicsJNI.h +++ b/core/jni/android/graphics/GraphicsJNI.h @@ -61,7 +61,8 @@ public: static void point_to_jpointf(const SkPoint& point, JNIEnv*, jobject jpointf); static android::Canvas* getNativeCanvas(JNIEnv*, jobject canvas); - static void getSkBitmap(JNIEnv*, jobject bitmap, SkBitmap* outBitmap); + static android::Bitmap* getNativeBitmap(JNIEnv*, jobject bitmap); + static SkImageInfo getBitmapInfo(JNIEnv*, jobject bitmap, uint32_t* outRowBytes); static SkRegion* getNativeRegion(JNIEnv*, jobject region); /* diff --git a/core/jni/android/graphics/apex/android_bitmap.cpp b/core/jni/android/graphics/apex/android_bitmap.cpp index a328def87908..90cc98699827 100644 --- a/core/jni/android/graphics/apex/android_bitmap.cpp +++ b/core/jni/android/graphics/apex/android_bitmap.cpp @@ -14,19 +14,25 @@ * limitations under the License. */ +#define LOG_TAG "Bitmap" +#include <log/log.h> + #include "android/graphics/bitmap.h" -#include "Bitmap.h" #include "TypeCast.h" #include "GraphicsJNI.h" +#include <GraphicsJNI.h> #include <hwui/Bitmap.h> using namespace android; ABitmap* ABitmap_acquireBitmapFromJava(JNIEnv* env, jobject bitmapObj) { - Bitmap& bitmap = android::bitmap::toBitmap(env, bitmapObj); - bitmap.ref(); - return TypeCast::toABitmap(&bitmap); + Bitmap* bitmap = GraphicsJNI::getNativeBitmap(env, bitmapObj); + if (bitmap) { + bitmap->ref(); + return TypeCast::toABitmap(bitmap); + } + return nullptr; } void ABitmap_acquireRef(ABitmap* bitmap) { @@ -37,8 +43,8 @@ void ABitmap_releaseRef(ABitmap* bitmap) { SkSafeUnref(TypeCast::toBitmap(bitmap)); } -static AndroidBitmapFormat getFormat(Bitmap* bitmap) { - switch (bitmap->colorType()) { +static AndroidBitmapFormat getFormat(const SkImageInfo& info) { + switch (info.colorType()) { case kN32_SkColorType: return ANDROID_BITMAP_FORMAT_RGBA_8888; case kRGB_565_SkColorType: @@ -71,6 +77,20 @@ static SkColorType getColorType(AndroidBitmapFormat format) { } } +static uint32_t getInfoFlags(const SkImageInfo& info) { + switch (info.alphaType()) { + case kUnknown_SkAlphaType: + LOG_ALWAYS_FATAL("Bitmap has no alpha type"); + break; + case kOpaque_SkAlphaType: + return ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE; + case kPremul_SkAlphaType: + return ANDROID_BITMAP_FLAGS_ALPHA_PREMUL; + case kUnpremul_SkAlphaType: + return ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL; + } +} + ABitmap* ABitmap_copy(ABitmap* srcBitmapHandle, AndroidBitmapFormat dstFormat) { SkColorType dstColorType = getColorType(dstFormat); if (srcBitmapHandle && dstColorType != kUnknown_SkColorType) { @@ -87,15 +107,25 @@ ABitmap* ABitmap_copy(ABitmap* srcBitmapHandle, AndroidBitmapFormat dstFormat) { return nullptr; } +static AndroidBitmapInfo getInfo(const SkImageInfo& imageInfo, uint32_t rowBytes) { + AndroidBitmapInfo info; + info.width = imageInfo.width(); + info.height = imageInfo.height(); + info.stride = rowBytes; + info.format = getFormat(imageInfo); + info.flags = getInfoFlags(imageInfo); + return info; +} + AndroidBitmapInfo ABitmap_getInfo(ABitmap* bitmapHandle) { Bitmap* bitmap = TypeCast::toBitmap(bitmapHandle); + return getInfo(bitmap->info(), bitmap->rowBytes()); +} - AndroidBitmapInfo info; - info.width = bitmap->width(); - info.height = bitmap->height(); - info.stride = bitmap->rowBytes(); - info.format = getFormat(bitmap); - return info; +AndroidBitmapInfo ABitmap_getInfoFromJava(JNIEnv* env, jobject bitmapObj) { + uint32_t rowBytes = 0; + SkImageInfo imageInfo = GraphicsJNI::getBitmapInfo(env, bitmapObj, &rowBytes); + return getInfo(imageInfo, rowBytes); } void* ABitmap_getPixels(ABitmap* bitmapHandle) { @@ -107,9 +137,17 @@ void* ABitmap_getPixels(ABitmap* bitmapHandle) { } AndroidBitmapFormat ABitmapConfig_getFormatFromConfig(JNIEnv* env, jobject bitmapConfigObj) { - return GraphicsJNI::getFormatFromConfig(env, bitmapConfigObj); + return GraphicsJNI::getFormatFromConfig(env, bitmapConfigObj); } jobject ABitmapConfig_getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat format) { - return GraphicsJNI::getConfigFromFormat(env, format); + return GraphicsJNI::getConfigFromFormat(env, format); +} + +void ABitmap_notifyPixelsChanged(ABitmap* bitmapHandle) { + Bitmap* bitmap = TypeCast::toBitmap(bitmapHandle); + if (bitmap->isImmutable()) { + ALOGE("Attempting to modify an immutable Bitmap!"); + } + return bitmap->notifyPixelsChanged(); } diff --git a/core/jni/android/graphics/apex/include/android/graphics/bitmap.h b/core/jni/android/graphics/apex/include/android/graphics/bitmap.h index dea55172b3bb..f231eeddb7e2 100644 --- a/core/jni/android/graphics/apex/include/android/graphics/bitmap.h +++ b/core/jni/android/graphics/apex/include/android/graphics/bitmap.h @@ -27,6 +27,20 @@ __BEGIN_DECLS */ typedef struct ABitmap ABitmap; +/** + * Retrieve bitmapInfo for the provided java bitmap even if it has been recycled. In the case of a + * recycled bitmap the values contained in the bitmap before it was recycled are returned. + * + * NOTE: This API does not need to remain as an APEX API if/when we pull libjnigraphics into the + * UI module. + */ +AndroidBitmapInfo ABitmap_getInfoFromJava(JNIEnv* env, jobject bitmapObj); + +/** + * + * @return ptr to an opaque handle to the native bitmap or null if the java bitmap has been recycled + * or does not exist. + */ ABitmap* ABitmap_acquireBitmapFromJava(JNIEnv* env, jobject bitmapObj); ABitmap* ABitmap_copy(ABitmap* srcBitmap, AndroidBitmapFormat dstFormat); @@ -37,6 +51,7 @@ void ABitmap_releaseRef(ABitmap* bitmap); AndroidBitmapInfo ABitmap_getInfo(ABitmap* bitmap); void* ABitmap_getPixels(ABitmap* bitmap); +void ABitmap_notifyPixelsChanged(ABitmap* bitmap); AndroidBitmapFormat ABitmapConfig_getFormatFromConfig(JNIEnv* env, jobject bitmapConfigObj); jobject ABitmapConfig_getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat format); @@ -88,10 +103,12 @@ namespace graphics { mBitmap = nullptr; } - const ABitmap* get() const { return mBitmap; } + ABitmap* get() const { return mBitmap; } AndroidBitmapInfo getInfo() const { return ABitmap_getInfo(mBitmap); } void* getPixels() const { return ABitmap_getPixels(mBitmap); } + void notifyPixelsChanged() const { ABitmap_notifyPixelsChanged(mBitmap); } + private: // takes ownership of the provided ABitmap Bitmap(ABitmap* bitmap) : mBitmap(bitmap) {} diff --git a/core/jni/android_os_HidlMemory.cpp b/core/jni/android_os_HidlMemory.cpp new file mode 100644 index 000000000000..69e48184c0ad --- /dev/null +++ b/core/jni/android_os_HidlMemory.cpp @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2019 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. + */ + +#include "android_os_HidlMemory.h" +#include "core_jni_helpers.h" +#include "android_os_NativeHandle.h" + +#define PACKAGE_PATH "android/os" +#define CLASS_NAME "HidlMemory" +#define CLASS_PATH PACKAGE_PATH "/" CLASS_NAME + +namespace android { + +namespace { + +static struct { + jclass clazz; + jfieldID nativeContext; // long + jmethodID constructor; // HidlMemory(String, long, NativeHandle) + jmethodID getName; // String HidlMemory.getName() + jmethodID getSize; // int HidlMemory.getSize() + jmethodID getHandle; // NativeHandle HidlMemory.getHandle() +} gFields; + +std::string stringFromJava(JNIEnv* env, jstring jstr) { + ScopedUtfChars s(env, jstr); + return s.c_str(); +} + +jstring stringToJava(JNIEnv* env, const std::string& cstr) { + return env->NewStringUTF(cstr.c_str()); +} + +static void nativeFinalize(JNIEnv* env, jobject jobj) { + jlong jNativeContext = env->GetLongField(jobj, gFields.nativeContext); + JHidlMemory* native = reinterpret_cast<JHidlMemory*>(jNativeContext); + delete native; +} + +static JNINativeMethod gMethods[] = { + {"nativeFinalize", "()V", (void*) nativeFinalize}, +}; + +} // namespace + +JHidlMemory::~JHidlMemory() { + if (mObj) { + // Must manually delete the underlying handle - hidl_memory doesn't own + // it. + native_handle_delete(const_cast<native_handle_t*>(mObj->handle())); + } +} + +/* static */ const hardware::hidl_memory* JHidlMemory::fromJava(JNIEnv* env, + jobject jobj) { + // Try to get the result from cache. + env->MonitorEnter(jobj); + JHidlMemory* obj = getNativeContext(env, jobj); + if (!obj->mObj) { + // Create and cache. + obj->mObj = javaToNative(env, jobj); + } + env->MonitorExit(jobj); + return obj->mObj.get(); +} + +/* static */ jobject JHidlMemory::toJava(JNIEnv* env, + const hardware::hidl_memory& cobj) { + if (cobj.size() > std::numeric_limits<jlong>::max()) { + return nullptr; + } + jstring jname = stringToJava(env, cobj.name()); + jlong jsize = static_cast<jlong>(cobj.size()); + jobject jhandle = + JNativeHandle::MakeJavaNativeHandleObj(env, cobj.handle()); + + // We're sharing the handle of cobj, so the Java instance doesn't own it. + return env->NewObject(gFields.clazz, + gFields.constructor, + jname, + jsize, + jhandle, + false); +} + +/* static */ std::unique_ptr<hardware::hidl_memory> JHidlMemory::javaToNative( + JNIEnv* env, + jobject jobj) { + jstring jname = + static_cast<jstring>(env->CallObjectMethod(jobj, gFields.getName)); + jlong jsize = env->CallLongMethod(jobj, gFields.getSize); + jobject jhandle = env->CallObjectMethod(jobj, gFields.getHandle); + + if (jsize > std::numeric_limits<size_t>::max()) { + return nullptr; + } + + std::string cname = stringFromJava(env, jname); + size_t csize = jsize; + // We created the handle here, we're responsible to call + // native_handle_delete() on it. However, we don't assume ownership of the + // underlying fd, so we shouldn't call native_handle_close() on it. + native_handle_t* chandle = JNativeHandle::MakeCppNativeHandle(env, jhandle, + nullptr); + // hidl_memory doesn't take ownership of the handle here, so won't delete + // or close it. + return std::make_unique<hardware::hidl_memory>(cname, chandle, csize); +} + +/* static */ JHidlMemory* JHidlMemory::getNativeContext(JNIEnv* env, + jobject jobj) { + env->MonitorEnter(jobj); + jlong jNativeContext = env->GetLongField(jobj, gFields.nativeContext); + JHidlMemory* native = reinterpret_cast<JHidlMemory*>(jNativeContext); + if (!native) { + native = new JHidlMemory(); + env->SetLongField(jobj, + gFields.nativeContext, + reinterpret_cast<jlong>(native)); + } + env->MonitorExit(jobj); + return native; +} + +int register_android_os_HidlMemory(JNIEnv* env) { + jclass clazz = FindClassOrDie(env, CLASS_PATH); + gFields.clazz = MakeGlobalRefOrDie(env, clazz); + + gFields.nativeContext = GetFieldIDOrDie(env, clazz, "mNativeContext", "J"); + + gFields.constructor = GetMethodIDOrDie(env, + clazz, + "<init>", + "(Ljava/lang/String;JL" PACKAGE_PATH "/NativeHandle;)V"); + gFields.getName = + GetMethodIDOrDie(env, clazz, "getName", "()Ljava/lang/String;"); + gFields.getSize = GetMethodIDOrDie(env, clazz, "getSize", "()J"); + gFields.getHandle = GetMethodIDOrDie(env, + clazz, + "getHandle", + "()L" PACKAGE_PATH "/NativeHandle;"); + + RegisterMethodsOrDie(env, CLASS_PATH, gMethods, NELEM(gMethods)); + + return 0; +} + +} // namespace android + diff --git a/core/jni/android_os_HidlMemory.h b/core/jni/android_os_HidlMemory.h new file mode 100644 index 000000000000..993a1326f0d3 --- /dev/null +++ b/core/jni/android_os_HidlMemory.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2019 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. + */ + +#ifndef ANDROID_OS_HIDL_MEMORY_H +#define ANDROID_OS_HIDL_MEMORY_H + +#include <jni.h> +#include <hidl/HidlSupport.h> + +namespace android { + +// A utility class for handling the android.os.HidlMemory class from JNI code. +class JHidlMemory final { + public: + // Convert an android.os.HidlMemory object to its C++ counterpart, + // hardware::hidl_memory. + // No duplication of file descriptors is performed. + // The returned reference is owned by the underlying Java object. + // Returns nullptr if conversion cannot be done. + static const hardware::hidl_memory* fromJava(JNIEnv* env, + jobject jobj); + + // Convert a hardware::hidl_memory object to its Java counterpart, + // android.os.HidlMemory. + // No duplication of file descriptors is performed. + // Returns nullptr if conversion cannot be done. + static jobject toJava(JNIEnv* env, + const hardware::hidl_memory& cobj); + + ~JHidlMemory(); + + private: + // We store an instance of type JHidlMemory attached to every Java object + // of type HidlMemory, for holding any native context we need. This instance + // will get deleted when finalize() is called on the Java object. + // This method either extracts the native object from the Java object, or + // attached a new one if it doesn't yet exist. + static JHidlMemory* getNativeContext(JNIEnv* env, jobject obj); + + // Convert an android.os.HidlMemory object to its C++ counterpart, + // hardware::hidl_memory. + // No duplication of file descriptors is performed. + // IMPORTANT: caller is responsible to native_handle_delete() the handle of the + // returned object. This is due to an underlying limitation of the hidl_handle + // type, where ownership of the handle implies ownership of the fd and we don't + // want the latter. + // Returns nullptr if conversion cannot be done. + static std::unique_ptr<hardware::hidl_memory> javaToNative(JNIEnv* env, + jobject jobj); + + std::unique_ptr<hardware::hidl_memory> mObj; +}; + +int register_android_os_HidlMemory(JNIEnv* env); + +} // namespace android + +#endif //ANDROID_OS_HIDL_MEMORY_H diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp index e5b72caf2792..0fb29111d043 100644 --- a/core/jni/android_os_HwBlob.cpp +++ b/core/jni/android_os_HwBlob.cpp @@ -340,6 +340,14 @@ static jstring JHwBlob_native_getString( return env->NewStringUTF(s->c_str()); } +static jlong JHwBlob_native_getFieldHandle(JNIEnv* env, + jobject thiz, + jlong offset) { + sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz); + + return reinterpret_cast<jlong>(blob->data()) + offset; +} + #define DEFINE_BLOB_ARRAY_COPIER(Suffix,Type,NewType) \ static void JHwBlob_native_copyTo ## Suffix ## Array( \ JNIEnv *env, \ @@ -593,6 +601,7 @@ static JNINativeMethod gMethods[] = { { "getFloat", "(J)F", (void *)JHwBlob_native_getFloat }, { "getDouble", "(J)D", (void *)JHwBlob_native_getDouble }, { "getString", "(J)Ljava/lang/String;", (void *)JHwBlob_native_getString }, + { "getFieldHandle", "(J)J", (void*) JHwBlob_native_getFieldHandle}, { "copyToBoolArray", "(J[ZI)V", (void *)JHwBlob_native_copyToBoolArray }, { "copyToInt8Array", "(J[BI)V", (void *)JHwBlob_native_copyToInt8Array }, diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp index f437a78e35f8..151dbfce7af3 100644 --- a/core/jni/android_os_HwParcel.cpp +++ b/core/jni/android_os_HwParcel.cpp @@ -20,6 +20,7 @@ #include "android_os_HwParcel.h" +#include "android_os_HidlMemory.h" #include "android_os_HwBinder.h" #include "android_os_HwBlob.h" #include "android_os_NativeHandle.h" @@ -27,6 +28,8 @@ #include <nativehelper/JNIHelp.h> #include <android_runtime/AndroidRuntime.h> +#include <hidl/HidlBinderSupport.h> +#include <hidl/HidlSupport.h> #include <hidl/HidlTransportSupport.h> #include <hidl/Status.h> #include <nativehelper/ScopedLocalRef.h> @@ -650,6 +653,36 @@ static void JHwParcel_native_writeStrongBinder( signalExceptionForError(env, err); } +static void JHwParcel_native_writeHidlMemory( + JNIEnv *env, jobject thiz, jobject jmem) { + + if (jmem == nullptr) { + jniThrowException(env, "java/lang/NullPointerException", nullptr); + return; + } + + status_t err = OK; + + // Convert the Java object to its C++ counterpart. + const hardware::hidl_memory* cmem = JHidlMemory::fromJava(env, jmem); + if (cmem == nullptr) { + err = BAD_VALUE; + } + + if (err == OK) { + // Write it to the parcel. + hardware::Parcel* parcel = + JHwParcel::GetNativeContext(env, thiz)->getParcel(); + + size_t parentHandle; + err = parcel->writeBuffer(cmem, sizeof(*cmem), &parentHandle); + if (err == OK) { + err = hardware::writeEmbeddedToParcel(*cmem, parcel, parentHandle, 0); + } + } + signalExceptionForError(env, err); +} + static jstring MakeStringObjFromHidlString(JNIEnv *env, const hidl_string &s) { String16 utf16String(s.c_str(), s.size()); @@ -877,6 +910,74 @@ static jobjectArray JHwParcel_native_readNativeHandleVector( return objArray; } +static status_t readEmbeddedHidlMemory(JNIEnv* env, + hardware::Parcel* parcel, + const hardware::hidl_memory& mem, + size_t parentHandle, + size_t parentOffset, + jobject* result) { + status_t err = hardware::readEmbeddedFromParcel(mem, + *parcel, + parentHandle, + parentOffset); + if (err == OK) { + // Convert to Java. + *result = JHidlMemory::toJava(env, mem); + if (*result == nullptr) { + err = BAD_VALUE; + } + } + return err; +} + +static jobject JHwParcel_native_readHidlMemory( + JNIEnv* env, jobject thiz) { + hardware::Parcel* parcel = + JHwParcel::GetNativeContext(env, thiz)->getParcel(); + + jobject result = nullptr; + + const hardware::hidl_memory* mem; + size_t parentHandle; + + status_t err = parcel->readBuffer(sizeof(*mem), + &parentHandle, + reinterpret_cast<const void**>(&mem)); + if (err == OK) { + err = readEmbeddedHidlMemory(env, + parcel, + *mem, + parentHandle, + 0, + &result); + } + + signalExceptionForError(env, err); + return result; +} + +static jobject JHwParcel_native_readEmbeddedHidlMemory( + JNIEnv* env, + jobject thiz, + jlong fieldHandle, + jlong parentHandle, + jlong offset) { + hardware::Parcel* parcel = + JHwParcel::GetNativeContext(env, thiz)->getParcel(); + + jobject result = nullptr; + const hardware::hidl_memory* mem = + reinterpret_cast<const hardware::hidl_memory*>(fieldHandle); + status_t err = readEmbeddedHidlMemory(env, + parcel, + *mem, + parentHandle, + offset, + &result); + signalExceptionForError(env, err); + return result; +} + static jobject JHwParcel_native_readStrongBinder(JNIEnv *env, jobject thiz) { hardware::Parcel *parcel = JHwParcel::GetNativeContext(env, thiz)->getParcel(); @@ -1075,6 +1176,14 @@ static JNINativeMethod gMethods[] = { { "release", "()V", (void *)JHwParcel_native_release }, + {"writeHidlMemory", "(L" PACKAGE_PATH "/HidlMemory;)V", + (void*) JHwParcel_native_writeHidlMemory}, + + {"readHidlMemory", "()L" PACKAGE_PATH "/HidlMemory;", + (void*) JHwParcel_native_readHidlMemory}, + + {"readEmbeddedHidlMemory", "(JJJ)L" PACKAGE_PATH "/HidlMemory;", + (void*) JHwParcel_native_readEmbeddedHidlMemory}, }; namespace android { diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp index 7f8bec6ce507..7f3b32e1abed 100644 --- a/core/jni/android_os_SystemProperties.cpp +++ b/core/jni/android_os_SystemProperties.cpp @@ -123,7 +123,7 @@ static jboolean jbooleanFromParseBoolResult(ParseBoolResult parseResult, jboolea jboolean SystemProperties_get_boolean(JNIEnv *env, jclass, jstring keyJ, jboolean defJ) { - ParseBoolResult parseResult; + ParseBoolResult parseResult = ParseBoolResult::kError; ReadProperty(env, keyJ, [&](const char* value) { parseResult = android::base::ParseBool(value); }); @@ -168,7 +168,7 @@ T SystemProperties_get_integralH(CRITICAL_JNI_PARAMS_COMMA jlong propJ, T defJ) jboolean SystemProperties_get_booleanH(CRITICAL_JNI_PARAMS_COMMA jlong propJ, jboolean defJ) { - ParseBoolResult parseResult; + ParseBoolResult parseResult = ParseBoolResult::kError; auto prop = reinterpret_cast<const prop_info*>(propJ); ReadProperty(prop, [&](const char* value) { parseResult = android::base::ParseBool(value); diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 7350396537ee..170e467a72cd 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -180,10 +180,13 @@ static void android_view_ThreadedRenderer_setSurface(JNIEnv* env, jobject clazz, if (jsurface) { surface = android_view_Surface_getSurface(env, jsurface); } + bool enableTimeout = true; if (discardBuffer) { + // Currently only Surface#lockHardwareCanvas takes this path + enableTimeout = false; proxy->setSwapBehavior(SwapBehavior::kSwap_discardBuffer); } - proxy->setSurface(surface); + proxy->setSurface(surface, enableTimeout); } static jboolean android_view_ThreadedRenderer_pause(JNIEnv* env, jobject clazz, diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 3516dce5d5ed..f28c4221c637 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -1156,7 +1156,7 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, UnsetChldSignalHandler(); if (is_system_server) { - env->CallStaticVoidMethod(gZygoteClass, gCallPostForkSystemServerHooks); + env->CallStaticVoidMethod(gZygoteClass, gCallPostForkSystemServerHooks, runtime_flags); if (env->ExceptionCheck()) { fail_fn("Error calling post fork system server hooks."); } @@ -1802,7 +1802,7 @@ int register_com_android_internal_os_Zygote(JNIEnv* env) { gZygoteClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, kZygoteClassName)); gCallPostForkSystemServerHooks = GetStaticMethodIDOrDie(env, gZygoteClass, "callPostForkSystemServerHooks", - "()V"); + "(I)V"); gCallPostForkChildHooks = GetStaticMethodIDOrDie(env, gZygoteClass, "callPostForkChildHooks", "(IZZLjava/lang/String;)V"); diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index 3704ccdfb8ea..8fabb2367318 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -34,6 +34,7 @@ // Static whitelist of open paths that the zygote is allowed to keep open. static const char* kPathWhitelist[] = { "/apex/com.android.conscrypt/javalib/conscrypt.jar", + "/apex/com.android.ipsec/javalib/ike.jar", "/apex/com.android.media/javalib/updatable-media.jar", "/dev/null", "/dev/socket/zygote", diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto index 8f084abe71a7..ce2717bb2779 100644 --- a/core/proto/android/server/activitymanagerservice.proto +++ b/core/proto/android/server/activitymanagerservice.proto @@ -126,11 +126,12 @@ message ActivityRecordProto { optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1 [deprecated=true]; optional .com.android.server.wm.IdentifierProto identifier = 2; optional string state = 3; - optional bool visible = 4; + optional bool visible_requested = 4; optional bool front_of_task = 5; optional int32 proc_id = 6; optional bool translucent = 7; optional .com.android.server.wm.AppWindowTokenProto app_window_token = 8; + optional bool visible = 9; } message KeyguardControllerProto { diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index 1a4a7ce0f634..24456d80625d 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -236,7 +236,7 @@ message AppWindowTokenProto { optional bool fills_parent = 7; optional bool app_stopped = 8; optional bool visible_requested = 9; - optional bool client_hidden = 10; + optional bool client_visible = 10; optional bool defer_hiding_client = 11; optional bool reported_drawn = 12; optional bool reported_visible = 13; @@ -249,8 +249,9 @@ message AppWindowTokenProto { optional IdentifierProto starting_window = 19; optional bool starting_displayed = 20; optional bool starting_moved = 21; - optional bool hidden_set_from_transferred_starting_window = 22; + optional bool visible_set_from_transferred_starting_window = 22; repeated .android.graphics.RectProto frozen_bounds = 23; + optional bool visible = 24; } /* represents WindowToken */ @@ -260,7 +261,6 @@ message WindowTokenProto { optional WindowContainerProto window_container = 1; optional int32 hash_code = 2; repeated WindowStateProto windows = 3; - optional bool hidden = 4; optional bool waiting_to_show = 5; optional bool paused = 6; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 62001aabca76..220fdd2e889d 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -499,7 +499,6 @@ <protected-broadcast android:name="android.telephony.action.CARRIER_CONFIG_CHANGED" /> <protected-broadcast android:name="android.telephony.action.DEFAULT_SUBSCRIPTION_CHANGED" /> <protected-broadcast android:name="android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED" /> - <protected-broadcast android:name="android.telephony.action.OTA_EMERGENCY_NUMBER_DB_INSTALLED" /> <protected-broadcast android:name="android.telephony.action.SECRET_CODE" /> <protected-broadcast android:name="android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION" /> <protected-broadcast android:name="android.telephony.action.SUBSCRIPTION_PLANS_CHANGED" /> @@ -1599,7 +1598,7 @@ recommendations and scores from the NetworkScoreService. <p>Not for use by third-party applications. @hide --> <permission android:name="android.permission.REQUEST_NETWORK_SCORES" - android:protectionLevel="signature|setup|privileged" /> + android:protectionLevel="signature|setup" /> <!-- Allows network stack services (Connectivity and Wifi) to coordinate <p>Not for use by third-party or privileged applications. diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 642dc929e88a..234ffee3baa8 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -3702,8 +3702,6 @@ <flag name="flagRequestFingerprintGestures" value="0x00000200" /> <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK}. --> <flag name="flagRequestShortcutWarningDialogSpokenFeedback" value="0x00000400" /> - <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_HANDLE_SHORTCUT}. --> - <flag name="flagHandleShortcut" value="0x00000800" /> </attr> <!-- Component name of an activity that allows the user to modify the settings for this service. This setting cannot be changed at runtime. --> diff --git a/core/tests/coretests/src/android/provider/DeviceConfigTest.java b/core/tests/coretests/src/android/provider/DeviceConfigTest.java index 0c83390f9f1e..8c1c3b569303 100644 --- a/core/tests/coretests/src/android/provider/DeviceConfigTest.java +++ b/core/tests/coretests/src/android/provider/DeviceConfigTest.java @@ -33,6 +33,9 @@ import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.HashMap; +import java.util.Map; + /** Tests that ensure appropriate settings are backed up. */ @Presubmit @RunWith(AndroidJUnit4.class) @@ -484,12 +487,74 @@ public class DeviceConfigTest { assertThat(properties.getString(KEY3, DEFAULT_VALUE)).isEqualTo(DEFAULT_VALUE); } - // TODO(mpape): resolve b/142727848 and re-enable this test + @Test + public void setProperties() { + Map<String, String> keyValues = new HashMap<>(); + keyValues.put(KEY, VALUE); + keyValues.put(KEY2, VALUE2); + + DeviceConfig.setProperties(new Properties(NAMESPACE, keyValues)); + Properties properties = DeviceConfig.getProperties(NAMESPACE); + assertThat(properties.getKeyset()).containsExactly(KEY, KEY2); + assertThat(properties.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE); + assertThat(properties.getString(KEY2, DEFAULT_VALUE)).isEqualTo(VALUE2); + + Map<String, String> newKeyValues = new HashMap<>(); + newKeyValues.put(KEY, VALUE2); + newKeyValues.put(KEY3, VALUE3); + + DeviceConfig.setProperties(new Properties(NAMESPACE, newKeyValues)); + properties = DeviceConfig.getProperties(NAMESPACE); + assertThat(properties.getKeyset()).containsExactly(KEY, KEY3); + assertThat(properties.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE2); + assertThat(properties.getString(KEY3, DEFAULT_VALUE)).isEqualTo(VALUE3); + + assertThat(properties.getKeyset()).doesNotContain(KEY2); + assertThat(properties.getString(KEY2, DEFAULT_VALUE)).isEqualTo(DEFAULT_VALUE); + } + + @Test + public void setProperties_multipleNamespaces() { + Map<String, String> keyValues = new HashMap<>(); + keyValues.put(KEY, VALUE); + keyValues.put(KEY2, VALUE2); + + Map<String, String> keyValues2 = new HashMap<>(); + keyValues2.put(KEY2, VALUE); + keyValues2.put(KEY3, VALUE2); + + final String namespace2 = "namespace2"; + DeviceConfig.setProperties(new Properties(NAMESPACE, keyValues)); + DeviceConfig.setProperties(new Properties(namespace2, keyValues2)); + + Properties properties = DeviceConfig.getProperties(NAMESPACE); + assertThat(properties.getKeyset()).containsExactly(KEY, KEY2); + assertThat(properties.getString(KEY, DEFAULT_VALUE)).isEqualTo(VALUE); + assertThat(properties.getString(KEY2, DEFAULT_VALUE)).isEqualTo(VALUE2); + + assertThat(properties.getKeyset()).doesNotContain(KEY3); + assertThat(properties.getString(KEY3, DEFAULT_VALUE)).isEqualTo(DEFAULT_VALUE); + + properties = DeviceConfig.getProperties(namespace2); + assertThat(properties.getKeyset()).containsExactly(KEY2, KEY3); + assertThat(properties.getString(KEY2, DEFAULT_VALUE)).isEqualTo(VALUE); + assertThat(properties.getString(KEY3, DEFAULT_VALUE)).isEqualTo(VALUE2); + + assertThat(properties.getKeyset()).doesNotContain(KEY); + assertThat(properties.getString(KEY, DEFAULT_VALUE)).isEqualTo(DEFAULT_VALUE); + + // clean up + deleteViaContentProvider(namespace2, KEY); + deleteViaContentProvider(namespace2, KEY2); + deleteViaContentProvider(namespace2, KEY3); + } + + // TODO(mpape): resolve b/142727848 and re-enable listener tests // @Test -// public void testOnPropertiesChangedListener() throws InterruptedException { +// public void onPropertiesChangedListener_setPropertyCallback() throws InterruptedException { // final CountDownLatch countDownLatch = new CountDownLatch(1); // -// OnPropertiesChangedListener changeListener = (properties) -> { +// DeviceConfig.OnPropertiesChangedListener changeListener = (properties) -> { // assertThat(properties.getNamespace()).isEqualTo(NAMESPACE); // assertThat(properties.getKeyset()).contains(KEY); // assertThat(properties.getString(KEY, "default_value")).isEqualTo(VALUE); @@ -508,6 +573,42 @@ public class DeviceConfigTest { // DeviceConfig.removeOnPropertiesChangedListener(changeListener); // } // } +// +// @Test +// public void onPropertiesChangedListener_setPropertiesCallback() throws InterruptedException { +// final CountDownLatch countDownLatch = new CountDownLatch(1); +// DeviceConfig.setProperty(NAMESPACE, KEY, VALUE, false); +// DeviceConfig.setProperty(NAMESPACE, KEY2, VALUE2, false); +// +// Map<String, String> keyValues = new HashMap<>(2); +// keyValues.put(KEY, VALUE2); +// keyValues.put(KEY3, VALUE3); +// Properties setProperties = new Properties(NAMESPACE, keyValues); +// +// DeviceConfig.OnPropertiesChangedListener changeListener = (properties) -> { +// assertThat(properties.getNamespace()).isEqualTo(NAMESPACE); +// assertThat(properties.getKeyset()).containsExactly(KEY, KEY2, KEY3); +// // KEY updated from VALUE to VALUE2 +// assertThat(properties.getString(KEY, "default_value")).isEqualTo(VALUE2); +// // KEY2 deleted (returns default_value) +// assertThat(properties.getString(KEY2, "default_value")).isEqualTo("default_value"); +// //KEY3 added with VALUE3 +// assertThat(properties.getString(KEY3, "default_value")).isEqualTo(VALUE3); +// countDownLatch.countDown(); +// }; +// +// try { +// DeviceConfig.addOnPropertiesChangedListener(NAMESPACE, +// ActivityThread.currentApplication().getMainExecutor(), changeListener); +// DeviceConfig.setProperties(setProperties); +// assertThat(countDownLatch.await( +// WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue(); +// } catch (InterruptedException e) { +// Assert.fail(e.getMessage()); +// } finally { +// DeviceConfig.removeOnPropertiesChangedListener(changeListener); +// } +// } private static boolean deleteViaContentProvider(String namespace, String key) { ContentResolver resolver = InstrumentationRegistry.getContext().getContentResolver(); diff --git a/core/tests/coretests/src/android/util/StatsEventTest.java b/core/tests/coretests/src/android/util/StatsEventTest.java new file mode 100644 index 000000000000..93f11dbccf64 --- /dev/null +++ b/core/tests/coretests/src/android/util/StatsEventTest.java @@ -0,0 +1,466 @@ +/* + * Copyright (C) 2019 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.util; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import android.os.SystemClock; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.google.common.collect.Range; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * Internal tests for {@link StatsEvent}. + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class StatsEventTest { + + @Test + public void testNoFields() { + final long minTimestamp = SystemClock.elapsedRealtimeNanos(); + final StatsEvent statsEvent = StatsEvent.newBuilder().build(); + final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); + + final int expectedAtomId = 0; + assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); + + final ByteBuffer buffer = + ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); + + assertWithMessage("Root element in buffer is not TYPE_ERRORS") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_ERRORS); + + assertWithMessage("Incorrect number of elements in root object") + .that(buffer.get()).isEqualTo(3); + + assertWithMessage("First element is not timestamp") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect timestamp") + .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); + + assertWithMessage("Second element is not atom id") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect atom id") + .that(buffer.getInt()).isEqualTo(expectedAtomId); + + final int errorMask = buffer.getInt(); + + assertWithMessage("ERROR_NO_ATOM_ID should be the only error in the error mask") + .that(errorMask).isEqualTo(StatsEvent.ERROR_NO_ATOM_ID); + + assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); + + statsEvent.release(); + } + + @Test + public void testIntBooleanIntInt() { + final int expectedAtomId = 109; + final int field1 = 1; + final boolean field2 = true; + final int field3 = 3; + final int field4 = 4; + + final long minTimestamp = SystemClock.elapsedRealtimeNanos(); + final StatsEvent statsEvent = StatsEvent.newBuilder() + .setAtomId(expectedAtomId) + .writeInt(field1) + .writeBoolean(field2) + .writeInt(field3) + .writeInt(field4) + .build(); + final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); + + assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); + + final ByteBuffer buffer = + ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); + + assertWithMessage("Root element in buffer is not TYPE_OBJECT") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); + + assertWithMessage("Incorrect number of elements in root object") + .that(buffer.get()).isEqualTo(6); + + assertWithMessage("First element is not timestamp") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect timestamp") + .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); + + assertWithMessage("Second element is not atom id") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect atom id") + .that(buffer.getInt()).isEqualTo(expectedAtomId); + + assertWithMessage("First field is not Int") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect field 1") + .that(buffer.getInt()).isEqualTo(field1); + + assertWithMessage("Second field is not Boolean") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_BOOLEAN); + + assertWithMessage("Incorrect field 2") + .that(buffer.get()).isEqualTo(1); + + assertWithMessage("Third field is not Int") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect field 3") + .that(buffer.getInt()).isEqualTo(field3); + + assertWithMessage("Fourth field is not Int") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect field 4") + .that(buffer.getInt()).isEqualTo(field4); + + assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); + + statsEvent.release(); + } + + @Test + public void testStringFloatByteArray() { + final int expectedAtomId = 109; + final String field1 = "Str 1"; + final float field2 = 9.334f; + final byte[] field3 = new byte[] { 56, 23, 89, -120 }; + + final long minTimestamp = SystemClock.elapsedRealtimeNanos(); + final StatsEvent statsEvent = StatsEvent.newBuilder() + .setAtomId(expectedAtomId) + .writeString(field1) + .writeFloat(field2) + .writeByteArray(field3) + .build(); + final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); + + assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); + + final ByteBuffer buffer = + ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); + + assertWithMessage("Root element in buffer is not TYPE_OBJECT") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); + + assertWithMessage("Incorrect number of elements in root object") + .that(buffer.get()).isEqualTo(5); + + assertWithMessage("First element is not timestamp") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect timestamp") + .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); + + assertWithMessage("Second element is not atom id") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect atom id") + .that(buffer.getInt()).isEqualTo(expectedAtomId); + + assertWithMessage("First field is not String") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_STRING); + + final String field1Actual = getStringFromByteBuffer(buffer); + assertWithMessage("Incorrect field 1") + .that(field1Actual).isEqualTo(field1); + + assertWithMessage("Second field is not Float") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_FLOAT); + + assertWithMessage("Incorrect field 2") + .that(buffer.getFloat()).isEqualTo(field2); + + assertWithMessage("Third field is not byte array") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_BYTE_ARRAY); + + final byte[] field3Actual = getByteArrayFromByteBuffer(buffer); + assertWithMessage("Incorrect field 3") + .that(field3Actual).isEqualTo(field3); + + assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); + + statsEvent.release(); + } + + @Test + public void testAttributionChainLong() { + final int expectedAtomId = 109; + final int[] uids = new int[] { 1, 2, 3, 4, 5 }; + final String[] tags = new String[] { "1", "2", "3", "4", "5" }; + final long field2 = -230909823L; + + final long minTimestamp = SystemClock.elapsedRealtimeNanos(); + final StatsEvent statsEvent = StatsEvent.newBuilder() + .setAtomId(expectedAtomId) + .writeAttributionChain(uids, tags) + .writeLong(field2) + .build(); + final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); + + assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); + + final ByteBuffer buffer = + ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); + + assertWithMessage("Root element in buffer is not TYPE_OBJECT") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); + + assertWithMessage("Incorrect number of elements in root object") + .that(buffer.get()).isEqualTo(4); + + assertWithMessage("First element is not timestamp") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect timestamp") + .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); + + assertWithMessage("Second element is not atom id") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect atom id") + .that(buffer.getInt()).isEqualTo(expectedAtomId); + + assertWithMessage("First field is not Attribution Chain") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_ATTRIBUTION_CHAIN); + + assertWithMessage("Incorrect number of attribution nodes") + .that(buffer.get()).isEqualTo((byte) uids.length); + + for (int i = 0; i < tags.length; i++) { + assertWithMessage("Incorrect uid in Attribution Chain") + .that(buffer.getInt()).isEqualTo(uids[i]); + + final String tag = getStringFromByteBuffer(buffer); + assertWithMessage("Incorrect tag in Attribution Chain") + .that(tag).isEqualTo(tags[i]); + } + + assertWithMessage("Second field is not Long") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect field 2") + .that(buffer.getLong()).isEqualTo(field2); + + assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); + + statsEvent.release(); + } + + @Test + public void testKeyValuePairs() { + final int expectedAtomId = 109; + final SparseIntArray intMap = new SparseIntArray(); + final SparseLongArray longMap = new SparseLongArray(); + final SparseArray<String> stringMap = new SparseArray<>(); + final SparseArray<Float> floatMap = new SparseArray<>(); + intMap.put(1, -1); + intMap.put(2, -2); + stringMap.put(3, "abc"); + stringMap.put(4, "2h"); + floatMap.put(9, -234.344f); + + final long minTimestamp = SystemClock.elapsedRealtimeNanos(); + final StatsEvent statsEvent = StatsEvent.newBuilder() + .setAtomId(expectedAtomId) + .writeKeyValuePairs(intMap, longMap, stringMap, floatMap) + .build(); + final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); + + assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); + + final ByteBuffer buffer = + ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); + + assertWithMessage("Root element in buffer is not TYPE_OBJECT") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); + + assertWithMessage("Incorrect number of elements in root object") + .that(buffer.get()).isEqualTo(3); + + assertWithMessage("First element is not timestamp") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect timestamp") + .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); + + assertWithMessage("Second element is not atom id") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect atom id") + .that(buffer.getInt()).isEqualTo(expectedAtomId); + + assertWithMessage("First field is not KeyValuePairs") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_KEY_VALUE_PAIRS); + + assertWithMessage("Incorrect number of key value pairs") + .that(buffer.get()).isEqualTo( + (byte) (intMap.size() + longMap.size() + stringMap.size() + + floatMap.size())); + + for (int i = 0; i < intMap.size(); i++) { + assertWithMessage("Incorrect key in intMap") + .that(buffer.getInt()).isEqualTo(intMap.keyAt(i)); + assertWithMessage("The type id of the value should be TYPE_INT in intMap") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + assertWithMessage("Incorrect value in intMap") + .that(buffer.getInt()).isEqualTo(intMap.valueAt(i)); + } + + for (int i = 0; i < longMap.size(); i++) { + assertWithMessage("Incorrect key in longMap") + .that(buffer.getInt()).isEqualTo(longMap.keyAt(i)); + assertWithMessage("The type id of the value should be TYPE_LONG in longMap") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + assertWithMessage("Incorrect value in longMap") + .that(buffer.getLong()).isEqualTo(longMap.valueAt(i)); + } + + for (int i = 0; i < stringMap.size(); i++) { + assertWithMessage("Incorrect key in stringMap") + .that(buffer.getInt()).isEqualTo(stringMap.keyAt(i)); + assertWithMessage("The type id of the value should be TYPE_STRING in stringMap") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_STRING); + final String value = getStringFromByteBuffer(buffer); + assertWithMessage("Incorrect value in stringMap") + .that(value).isEqualTo(stringMap.valueAt(i)); + } + + for (int i = 0; i < floatMap.size(); i++) { + assertWithMessage("Incorrect key in floatMap") + .that(buffer.getInt()).isEqualTo(floatMap.keyAt(i)); + assertWithMessage("The type id of the value should be TYPE_FLOAT in floatMap") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_FLOAT); + assertWithMessage("Incorrect value in floatMap") + .that(buffer.getFloat()).isEqualTo(floatMap.valueAt(i)); + } + + assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); + + statsEvent.release(); + } + + @Test + public void testSingleAnnotations() { + final int expectedAtomId = 109; + final int field1 = 1; + final byte field1AnnotationId = 45; + final boolean field1AnnotationValue = false; + final boolean field2 = true; + final byte field2AnnotationId = 1; + final int field2AnnotationValue = 23; + + final long minTimestamp = SystemClock.elapsedRealtimeNanos(); + final StatsEvent statsEvent = StatsEvent.newBuilder() + .setAtomId(expectedAtomId) + .writeInt(field1) + .addBooleanAnnotation(field1AnnotationId, field1AnnotationValue) + .writeBoolean(field2) + .addIntAnnotation(field2AnnotationId, field2AnnotationValue) + .build(); + final long maxTimestamp = SystemClock.elapsedRealtimeNanos(); + + assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId); + + final ByteBuffer buffer = + ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN); + + assertWithMessage("Root element in buffer is not TYPE_OBJECT") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_OBJECT); + + assertWithMessage("Incorrect number of elements in root object") + .that(buffer.get()).isEqualTo(4); + + assertWithMessage("First element is not timestamp") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_LONG); + + assertWithMessage("Incorrect timestamp") + .that(buffer.getLong()).isIn(Range.closed(minTimestamp, maxTimestamp)); + + assertWithMessage("Second element is not atom id") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + + assertWithMessage("Incorrect atom id") + .that(buffer.getInt()).isEqualTo(expectedAtomId); + + final byte field1Header = buffer.get(); + final int field1AnnotationValueCount = field1Header >> 4; + final byte field1Type = (byte) (field1Header & 0x0F); + assertWithMessage("First field is not Int") + .that(field1Type).isEqualTo(StatsEvent.TYPE_INT); + assertWithMessage("First field annotation count is wrong") + .that(field1AnnotationValueCount).isEqualTo(1); + assertWithMessage("Incorrect field 1") + .that(buffer.getInt()).isEqualTo(field1); + assertWithMessage("First field's annotation id is wrong") + .that(buffer.get()).isEqualTo(field1AnnotationId); + assertWithMessage("First field's annotation type is wrong") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_BOOLEAN); + assertWithMessage("First field's annotation value is wrong") + .that(buffer.get()).isEqualTo(field1AnnotationValue ? 1 : 0); + + final byte field2Header = buffer.get(); + final int field2AnnotationValueCount = field2Header >> 4; + final byte field2Type = (byte) (field2Header & 0x0F); + assertWithMessage("Second field is not boolean") + .that(field2Type).isEqualTo(StatsEvent.TYPE_BOOLEAN); + assertWithMessage("Second field annotation count is wrong") + .that(field2AnnotationValueCount).isEqualTo(1); + assertWithMessage("Incorrect field 2") + .that(buffer.get()).isEqualTo(field2 ? 1 : 0); + assertWithMessage("Second field's annotation id is wrong") + .that(buffer.get()).isEqualTo(field2AnnotationId); + assertWithMessage("Second field's annotation type is wrong") + .that(buffer.get()).isEqualTo(StatsEvent.TYPE_INT); + assertWithMessage("Second field's annotation value is wrong") + .that(buffer.getInt()).isEqualTo(field2AnnotationValue); + + assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position()); + + statsEvent.release(); + } + + private static byte[] getByteArrayFromByteBuffer(final ByteBuffer buffer) { + final int numBytes = buffer.getInt(); + byte[] bytes = new byte[numBytes]; + buffer.get(bytes); + return bytes; + } + + private static String getStringFromByteBuffer(final ByteBuffer buffer) { + final byte[] bytes = getByteArrayFromByteBuffer(buffer); + return new String(bytes, UTF_8); + } +} diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java index a401e21df805..344c28679568 100644 --- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java +++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java @@ -50,6 +50,7 @@ import com.android.internal.app.ResolverListAdapter.ResolveInfoPresentationGette import com.android.internal.widget.ResolverDrawerLayout; import org.junit.Before; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -103,6 +104,7 @@ public class ResolverActivityTest { assertThat(chosen[0], is(toChoose)); } + @Ignore // Failing - b/144929805 @Test public void setMaxHeight() throws Exception { Intent sendIntent = createSendImageIntent(); @@ -146,6 +148,7 @@ public class ResolverActivityTest { resolverList.getHeight() == initialResolverHeight); } + @Ignore // Failing - b/144929805 @Test public void setShowAtTopToTrue() throws Exception { Intent sendIntent = createSendImageIntent(); diff --git a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java index b48ac3347093..9f70538191c2 100644 --- a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java +++ b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java @@ -26,6 +26,7 @@ import java.util.concurrent.TimeUnit; public class SystemPropertiesTest extends TestCase { private static final String KEY = "sys.testkey"; + private static final String UNSET_KEY = "Aiw7woh6ie4toh7W"; private static final String PERSIST_KEY = "persist.sys.testkey"; @SmallTest @@ -133,6 +134,15 @@ public class SystemPropertiesTest extends TestCase { } @SmallTest + public void testUnset() throws Exception { + assertEquals("abc", SystemProperties.get(UNSET_KEY, "abc")); + assertEquals(true, SystemProperties.getBoolean(UNSET_KEY, true)); + assertEquals(false, SystemProperties.getBoolean(UNSET_KEY, false)); + assertEquals(5, SystemProperties.getInt(UNSET_KEY, 5)); + assertEquals(-10, SystemProperties.getLong(UNSET_KEY, -10)); + } + + @SmallTest @SuppressWarnings("null") public void testNullKey() throws Exception { try { diff --git a/data/etc/com.android.settings.xml b/data/etc/com.android.settings.xml index 1882c3f8c4c8..ef1f77b7d967 100644 --- a/data/etc/com.android.settings.xml +++ b/data/etc/com.android.settings.xml @@ -42,7 +42,6 @@ <permission name="android.permission.PACKAGE_USAGE_STATS"/> <permission name="android.permission.READ_SEARCH_INDEXABLES"/> <permission name="android.permission.REBOOT"/> - <permission name="android.permission.REQUEST_NETWORK_SCORES"/> <permission name="android.permission.SET_TIME"/> <permission name="android.permission.STATUS_BAR"/> <permission name="android.permission.TETHER_PRIVILEGED"/> diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 5c48d9166303..440b885b4574 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -55,6 +55,12 @@ "group": "WM_DEBUG_REMOTE_ANIMATIONS", "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, + "-2006946193": { + "message": "setClientVisible: %s clientVisible=%b Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "-2002500255": { "message": "Defer removing snapshot surface in %dms", "level": "VERBOSE", @@ -73,10 +79,10 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "-1972506791": { - "message": "Set freezing of %s: hidden=%b freezing=%b visibleRequested=%b. %s", - "level": "INFO", - "group": "WM_DEBUG_ORIENTATION", + "-1976550065": { + "message": "commitVisibility: %s: visible=%b visibleRequested=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, "-1963461591": { @@ -85,12 +91,6 @@ "group": "WM_DEBUG_ADD_REMOVE", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "-1958209312": { - "message": "Clear freezing of %s: hidden=%b freezing=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_ORIENTATION", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, "-1953668890": { "message": "Can't start recents animation, nextAppTransition=%s", "level": "DEBUG", @@ -307,12 +307,6 @@ "group": "WM_DEBUG_ADD_REMOVE", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-1456549051": { - "message": "setClientHidden: %s clientHidden=%b Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, "-1455600136": { "message": "Attempted to add Dream window with unknown token %s. Aborting.", "level": "WARN", @@ -547,12 +541,6 @@ "group": "WM_DEBUG_STARTING_WINDOW", "at": "com\/android\/server\/wm\/WindowState.java" }, - "-931184679": { - "message": "Changing app %s hidden=%b performLayout=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, "-928291778": { "message": "applyAnimation: anim=%s nextAppTransition=%d transit=%s Callers=%s", "level": "VERBOSE", @@ -841,6 +829,12 @@ "group": "WM_DEBUG_APP_TRANSITIONS", "at": "com\/android\/server\/wm\/AppTransitionController.java" }, + "-374767836": { + "message": "setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "-371630969": { "message": "New wallpaper target=%s, oldWallpaper=%s, openingApps=%s, closingApps=%s", "level": "VERBOSE", @@ -883,12 +877,6 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, - "-229838822": { - "message": "setAppVisibility(%s, visible=%b): %s hidden=%b mVisibleRequested=%b Callers=%s", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, "-198463978": { "message": "updateRotationUnchecked: alwaysSendConfiguration=%b forceRelayout=%b", "level": "VERBOSE", @@ -1273,6 +1261,12 @@ "group": "WM_DEBUG_SCREEN_ON", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "466506262": { + "message": "Clear freezing of %s: visible=%b freezing=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "474000473": { "message": "No stack above target stack=%s", "level": "DEBUG", @@ -1483,6 +1477,12 @@ "group": "WM_DEBUG_REMOTE_ANIMATIONS", "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, + "841702299": { + "message": "Changing app %s visible=%b performLayout=%b", + "level": "VERBOSE", + "group": "WM_DEBUG_APP_TRANSITIONS", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "845234215": { "message": "App is requesting an orientation, return %d for display id=%d", "level": "VERBOSE", @@ -1891,6 +1891,12 @@ "group": "WM_DEBUG_STARTING_WINDOW", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "1746778201": { + "message": "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s", + "level": "INFO", + "group": "WM_DEBUG_ORIENTATION", + "at": "com\/android\/server\/wm\/ActivityRecord.java" + }, "1747941491": { "message": "SURFACE controller=%s alpha=%f matrix=[%f*%f,%f*%f][%f*%f,%f*%f]: %s", "level": "INFO", @@ -1987,12 +1993,6 @@ "group": "WM_DEBUG_REMOTE_ANIMATIONS", "at": "com\/android\/server\/wm\/RemoteAnimationController.java" }, - "1965198071": { - "message": "commitVisibility: %s: hidden=%b visibleRequested=%b", - "level": "VERBOSE", - "group": "WM_DEBUG_APP_TRANSITIONS", - "at": "com\/android\/server\/wm\/ActivityRecord.java" - }, "1984470582": { "message": "Creating TaskScreenshotAnimatable: task: %s width: %d height: %d", "level": "DEBUG", diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp index 41e9b4be6649..e53f3db08538 100644 --- a/libs/hwui/DeviceInfo.cpp +++ b/libs/hwui/DeviceInfo.cpp @@ -15,9 +15,8 @@ */ #include <DeviceInfo.h> -#include <gui/SurfaceComposerClient.h> #include <log/log.h> -#include <ui/GraphicTypes.h> +#include <utils/Errors.h> #include <mutex> #include <thread> @@ -32,44 +31,6 @@ DeviceInfo* DeviceInfo::get() { return &sDeviceInfo; } -static void queryWideColorGamutPreference(sk_sp<SkColorSpace>* colorSpace, SkColorType* colorType) { - if (Properties::isolatedProcess) { - *colorSpace = SkColorSpace::MakeSRGB(); - *colorType = SkColorType::kN32_SkColorType; - return; - } - ui::Dataspace defaultDataspace, wcgDataspace; - ui::PixelFormat defaultPixelFormat, wcgPixelFormat; - status_t status = - SurfaceComposerClient::getCompositionPreference(&defaultDataspace, &defaultPixelFormat, - &wcgDataspace, &wcgPixelFormat); - LOG_ALWAYS_FATAL_IF(status, "Failed to get composition preference, error %d", status); - switch (wcgDataspace) { - case ui::Dataspace::DISPLAY_P3: - *colorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3); - break; - case ui::Dataspace::V0_SCRGB: - *colorSpace = SkColorSpace::MakeSRGB(); - break; - case ui::Dataspace::V0_SRGB: - // when sRGB is returned, it means wide color gamut is not supported. - *colorSpace = SkColorSpace::MakeSRGB(); - break; - default: - LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space."); - } - switch (wcgPixelFormat) { - case ui::PixelFormat::RGBA_8888: - *colorType = SkColorType::kN32_SkColorType; - break; - case ui::PixelFormat::RGBA_FP16: - *colorType = SkColorType::kRGBA_F16_SkColorType; - break; - default: - LOG_ALWAYS_FATAL("Unreachable: unsupported pixel format."); - } -} - DeviceInfo::DeviceInfo() { #if HWUI_NULL_GPU mMaxTextureSize = NULL_GPU_MAX_TEXTURE_SIZE; @@ -77,7 +38,6 @@ DeviceInfo::DeviceInfo() { mMaxTextureSize = -1; #endif updateDisplayInfo(); - queryWideColorGamutPreference(&mWideColorSpace, &mWideColorType); } DeviceInfo::~DeviceInfo() { ADisplay_release(mDisplays); @@ -113,9 +73,45 @@ void DeviceInfo::updateDisplayInfo() { } } LOG_ALWAYS_FATAL_IF(mPhysicalDisplayIndex < 0, "Failed to find a connected physical display!"); - mMaxRefreshRate = ADisplay_getMaxSupportedFps(mDisplays[mPhysicalDisplayIndex]); + + + // Since we now just got the primary display for the first time, then + // store the primary display metadata here. + ADisplay* primaryDisplay = mDisplays[mPhysicalDisplayIndex]; + mMaxRefreshRate = ADisplay_getMaxSupportedFps(primaryDisplay); + ADataSpace dataspace; + AHardwareBuffer_Format format; + ADisplay_getPreferredWideColorFormat(primaryDisplay, &dataspace, &format); + switch (dataspace) { + case ADATASPACE_DISPLAY_P3: + mWideColorSpace = + SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3); + break; + case ADATASPACE_SCRGB: + mWideColorSpace = SkColorSpace::MakeSRGB(); + break; + case ADATASPACE_SRGB: + // when sRGB is returned, it means wide color gamut is not supported. + mWideColorSpace = SkColorSpace::MakeSRGB(); + break; + default: + LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space."); + } + switch (format) { + case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: + mWideColorType = SkColorType::kN32_SkColorType; + break; + case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT: + mWideColorType = SkColorType::kRGBA_F16_SkColorType; + break; + default: + LOG_ALWAYS_FATAL("Unreachable: unsupported pixel format."); + } } - status_t status = ADisplay_getCurrentConfig(mDisplays[mPhysicalDisplayIndex], &mCurrentConfig); + // This method may have been called when the display config changed, so + // sync with the current configuration. + ADisplay* primaryDisplay = mDisplays[mPhysicalDisplayIndex]; + status_t status = ADisplay_getCurrentConfig(primaryDisplay, &mCurrentConfig); LOG_ALWAYS_FATAL_IF(status, "Failed to get display config, error %d", status); mWidth = ADisplayConfig_getWidth(mCurrentConfig); mHeight = ADisplayConfig_getHeight(mCurrentConfig); diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h index 34315830ed97..a4207460883e 100644 --- a/libs/hwui/DeviceInfo.h +++ b/libs/hwui/DeviceInfo.h @@ -58,8 +58,8 @@ private: ~DeviceInfo(); int mMaxTextureSize; - sk_sp<SkColorSpace> mWideColorSpace; - SkColorType mWideColorType; + sk_sp<SkColorSpace> mWideColorSpace = SkColorSpace::MakeSRGB(); + SkColorType mWideColorType = SkColorType::kN32_SkColorType; ADisplayConfig* mCurrentConfig = nullptr; ADisplay** mDisplays = nullptr; int mDisplaysSize = 0; diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index f0867686c321..84902210a751 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -140,13 +140,15 @@ void CanvasContext::destroy() { mAnimationContext->destroy(); } -void CanvasContext::setSurface(sp<Surface>&& surface) { +void CanvasContext::setSurface(sp<Surface>&& surface, bool enableTimeout) { ATRACE_CALL(); if (surface) { mNativeSurface = new ReliableSurface{std::move(surface)}; - // TODO: Fix error handling & re-shorten timeout - ANativeWindow_setDequeueTimeout(mNativeSurface.get(), 4000_ms); + if (enableTimeout) { + // TODO: Fix error handling & re-shorten timeout + ANativeWindow_setDequeueTimeout(mNativeSurface.get(), 4000_ms); + } } else { mNativeSurface = nullptr; } diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index b192d461da9b..4490f80eb8af 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -111,7 +111,7 @@ public: // Won't take effect until next EGLSurface creation void setSwapBehavior(SwapBehavior swapBehavior); - void setSurface(sp<Surface>&& surface); + void setSurface(sp<Surface>&& surface, bool enableTimeout = true); bool pauseSurface(); void setStopped(bool stopped); bool hasSurface() const { return mNativeSurface.get(); } diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 4f7ad7b69f57..f9e401a2e93b 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -78,9 +78,10 @@ void RenderProxy::setName(const char* name) { mRenderThread.queue().runSync([this, name]() { mContext->setName(std::string(name)); }); } -void RenderProxy::setSurface(const sp<Surface>& surface) { - mRenderThread.queue().post( - [this, surf = surface]() mutable { mContext->setSurface(std::move(surf)); }); +void RenderProxy::setSurface(const sp<Surface>& surface, bool enableTimeout) { + mRenderThread.queue().post([this, surf = surface, enableTimeout]() mutable { + mContext->setSurface(std::move(surf), enableTimeout); + }); } void RenderProxy::allocateBuffers() { diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index e6fe1d4864da..4683e1d69019 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -69,7 +69,7 @@ public: ANDROID_API bool loadSystemProperties(); ANDROID_API void setName(const char* name); - ANDROID_API void setSurface(const sp<Surface>& surface); + ANDROID_API void setSurface(const sp<Surface>& surface, bool enableTimeout = true); ANDROID_API void allocateBuffers(); ANDROID_API bool pause(); ANDROID_API void setStopped(bool stopped); diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp index 92efb4ea86ff..b36406d6a703 100644 --- a/libs/input/tests/PointerController_test.cpp +++ b/libs/input/tests/PointerController_test.cpp @@ -32,8 +32,8 @@ enum TestCursorType { CURSOR_TYPE_HOVER, CURSOR_TYPE_TOUCH, CURSOR_TYPE_ANCHOR, - CURSOR_TYPE_ADDITIONAL_1, - CURSOR_TYPE_ADDITIONAL_2, + CURSOR_TYPE_ADDITIONAL, + CURSOR_TYPE_ADDITIONAL_ANIM, CURSOR_TYPE_CUSTOM = -1, }; @@ -79,13 +79,18 @@ void MockPointerControllerPolicyInterface::loadAdditionalMouseResources( SpriteIcon icon; PointerAnimation anim; - for (int32_t cursorType : {CURSOR_TYPE_ADDITIONAL_1, CURSOR_TYPE_ADDITIONAL_2}) { - loadPointerIconForType(&icon, cursorType); - anim.animationFrames.push_back(icon); - anim.durationPerFrame = 10; - (*outResources)[cursorType] = icon; - (*outAnimationResources)[cursorType] = anim; - } + // CURSOR_TYPE_ADDITIONAL doesn't have animation resource. + int32_t cursorType = CURSOR_TYPE_ADDITIONAL; + loadPointerIconForType(&icon, cursorType); + (*outResources)[cursorType] = icon; + + // CURSOR_TYPE_ADDITIONAL_ANIM has animation resource. + cursorType = CURSOR_TYPE_ADDITIONAL_ANIM; + loadPointerIconForType(&icon, cursorType); + anim.animationFrames.push_back(icon); + anim.durationPerFrame = 10; + (*outResources)[cursorType] = icon; + (*outAnimationResources)[cursorType] = anim; } int32_t MockPointerControllerPolicyInterface::getDefaultPointerIconId() { @@ -178,7 +183,7 @@ TEST_F(PointerControllerTest, useDefaultCursorTypeByDefault) { TEST_F(PointerControllerTest, updatePointerIcon) { mPointerController->unfade(PointerController::TRANSITION_IMMEDIATE); - int32_t type = CURSOR_TYPE_ADDITIONAL_1; + int32_t type = CURSOR_TYPE_ADDITIONAL; std::pair<float, float> hotspot = getHotSpotCoordinatesForType(type); EXPECT_CALL(*mPointerSprite, setVisible(true)); EXPECT_CALL(*mPointerSprite, setAlpha(1.0f)); diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java index 27274d12b1de..db48ee7f2cf9 100644 --- a/location/java/android/location/Location.java +++ b/location/java/android/location/Location.java @@ -161,7 +161,10 @@ public class Location implements Parcelable { * <p>By default time, latitude and longitude are 0, and the location * has no bearing, altitude, speed, accuracy or extras. * - * @param provider the name of the provider that generated this location + * @param provider the source that provides the location. It can be of type + * {@link LocationManager#GPS_PROVIDER}, {@link LocationManager#NETWORK_PROVIDER}, + * or {@link LocationManager#PASSIVE_PROVIDER}. You can also define your own + * provider string, in which case an empty string is a valid provider. */ public Location(String provider) { mProvider = provider; diff --git a/location/java/android/location/OnNmeaMessageListener.java b/location/java/android/location/OnNmeaMessageListener.java index ccf6ce854317..05647bc5237b 100644 --- a/location/java/android/location/OnNmeaMessageListener.java +++ b/location/java/android/location/OnNmeaMessageListener.java @@ -28,7 +28,9 @@ public interface OnNmeaMessageListener { /** * Called when an NMEA message is received. * @param message NMEA message - * @param timestamp milliseconds since January 1, 1970. + * @param timestamp Date and time of the location fix, as reported by the GNSS + * chipset. The value is specified in milliseconds since 0:00 + * UTC 1 January 1970. */ void onNmeaMessage(String message, long timestamp); } diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java index e0bff74fd588..c20dc615529b 100644 --- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java +++ b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java @@ -114,6 +114,7 @@ public class GnssMetrics { * Logs the status of a location report received from the HAL */ public void logReceivedLocationStatus(boolean isSuccessful) { + StatsLog.write(StatsLog.GPS_LOCATION_STATUS_REPORTED, isSuccessful); if (!isSuccessful) { mLocationFailureStatistics.addItem(1.0); return; @@ -130,6 +131,7 @@ public class GnssMetrics { DEFAULT_TIME_BETWEEN_FIXES_MILLISECS, desiredTimeBetweenFixesMilliSeconds)) - 1; if (numReportMissed > 0) { for (int i = 0; i < numReportMissed; i++) { + StatsLog.write(StatsLog.GPS_LOCATION_STATUS_REPORTED, false); mLocationFailureStatistics.addItem(1.0); } } @@ -140,6 +142,7 @@ public class GnssMetrics { */ public void logTimeToFirstFixMilliSecs(int timeToFirstFixMilliSeconds) { mTimeToFirstFixSecStatistics.addItem((double) (timeToFirstFixMilliSeconds / 1000)); + StatsLog.write(StatsLog.GPS_TIME_TO_FIRST_FIX_REPORTED, timeToFirstFixMilliSeconds); } /** diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index a3a87774483b..d64e4ef00164 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -30,7 +30,9 @@ import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.HashSet; import java.util.Map; +import java.util.Set; /* IF YOU CHANGE ANY OF THE CONSTANTS IN THIS FILE, DO NOT FORGET * TO UPDATE THE CORRESPONDING NATIVE GLUE AND AudioManager.java. @@ -543,51 +545,75 @@ public class AudioSystem public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT; - public static final int DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE | - DEVICE_OUT_SPEAKER | - DEVICE_OUT_WIRED_HEADSET | - DEVICE_OUT_WIRED_HEADPHONE | - DEVICE_OUT_BLUETOOTH_SCO | - DEVICE_OUT_BLUETOOTH_SCO_HEADSET | - DEVICE_OUT_BLUETOOTH_SCO_CARKIT | - DEVICE_OUT_BLUETOOTH_A2DP | - DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | - DEVICE_OUT_HDMI | - DEVICE_OUT_ANLG_DOCK_HEADSET | - DEVICE_OUT_DGTL_DOCK_HEADSET | - DEVICE_OUT_USB_ACCESSORY | - DEVICE_OUT_USB_DEVICE | - DEVICE_OUT_REMOTE_SUBMIX | - DEVICE_OUT_TELEPHONY_TX | - DEVICE_OUT_LINE | - DEVICE_OUT_HDMI_ARC | - DEVICE_OUT_SPDIF | - DEVICE_OUT_FM | - DEVICE_OUT_AUX_LINE | - DEVICE_OUT_SPEAKER_SAFE | - DEVICE_OUT_IP | - DEVICE_OUT_BUS | - DEVICE_OUT_PROXY | - DEVICE_OUT_USB_HEADSET | - DEVICE_OUT_HEARING_AID | - DEVICE_OUT_DEFAULT); - public static final int DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP | - DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER); - public static final int DEVICE_OUT_ALL_SCO = (DEVICE_OUT_BLUETOOTH_SCO | - DEVICE_OUT_BLUETOOTH_SCO_HEADSET | - DEVICE_OUT_BLUETOOTH_SCO_CARKIT); + // Deprecated in R because multiple device types are no longer accessed as a bit mask. + // Removing this will get lint warning about changing hidden apis. @UnsupportedAppUsage public static final int DEVICE_OUT_ALL_USB = (DEVICE_OUT_USB_ACCESSORY | DEVICE_OUT_USB_DEVICE | DEVICE_OUT_USB_HEADSET); - public static final int DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO = (DEVICE_OUT_AUX_LINE | - DEVICE_OUT_HDMI_ARC | - DEVICE_OUT_SPDIF); - public static final int DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER = - (DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO | - DEVICE_OUT_SPEAKER); + + public static final Set<Integer> DEVICE_OUT_ALL_SET; + public static final Set<Integer> DEVICE_OUT_ALL_A2DP_SET; + public static final Set<Integer> DEVICE_OUT_ALL_SCO_SET; + public static final Set<Integer> DEVICE_OUT_ALL_USB_SET; + public static final Set<Integer> DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET; + public static final Set<Integer> DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET; + static { + DEVICE_OUT_ALL_SET = new HashSet<>(); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_EARPIECE); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_SPEAKER); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_WIRED_HEADSET); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_WIRED_HEADPHONE); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_SCO); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_SCO_HEADSET); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_SCO_CARKIT); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_A2DP); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_HDMI); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_ANLG_DOCK_HEADSET); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_DGTL_DOCK_HEADSET); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_USB_ACCESSORY); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_USB_DEVICE); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_REMOTE_SUBMIX); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_TELEPHONY_TX); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_LINE); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_HDMI_ARC); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_SPDIF); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_FM); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_AUX_LINE); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_SPEAKER_SAFE); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_IP); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_BUS); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_PROXY); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_USB_HEADSET); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_HEARING_AID); + DEVICE_OUT_ALL_SET.add(DEVICE_OUT_DEFAULT); + + DEVICE_OUT_ALL_A2DP_SET = new HashSet<>(); + DEVICE_OUT_ALL_A2DP_SET.add(DEVICE_OUT_BLUETOOTH_A2DP); + DEVICE_OUT_ALL_A2DP_SET.add(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES); + DEVICE_OUT_ALL_A2DP_SET.add(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER); + + DEVICE_OUT_ALL_SCO_SET = new HashSet<>(); + DEVICE_OUT_ALL_SCO_SET.add(DEVICE_OUT_BLUETOOTH_SCO); + DEVICE_OUT_ALL_SCO_SET.add(DEVICE_OUT_BLUETOOTH_SCO_HEADSET); + DEVICE_OUT_ALL_SCO_SET.add(DEVICE_OUT_BLUETOOTH_SCO_CARKIT); + + DEVICE_OUT_ALL_USB_SET = new HashSet<>(); + DEVICE_OUT_ALL_USB_SET.add(DEVICE_OUT_USB_ACCESSORY); + DEVICE_OUT_ALL_USB_SET.add(DEVICE_OUT_USB_DEVICE); + DEVICE_OUT_ALL_USB_SET.add(DEVICE_OUT_USB_HEADSET); + + DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET = new HashSet<>(); + DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET.add(DEVICE_OUT_AUX_LINE); + DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET.add(DEVICE_OUT_HDMI_ARC); + DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET.add(DEVICE_OUT_SPDIF); + + DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET = new HashSet<>(); + DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET.addAll(DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET); + DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET.add(DEVICE_OUT_SPEAKER); + } // input devices @UnsupportedAppUsage @@ -635,37 +661,47 @@ public class AudioSystem @UnsupportedAppUsage public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT; - public static final int DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION | - DEVICE_IN_AMBIENT | - DEVICE_IN_BUILTIN_MIC | - DEVICE_IN_BLUETOOTH_SCO_HEADSET | - DEVICE_IN_WIRED_HEADSET | - DEVICE_IN_HDMI | - DEVICE_IN_TELEPHONY_RX | - DEVICE_IN_BACK_MIC | - DEVICE_IN_REMOTE_SUBMIX | - DEVICE_IN_ANLG_DOCK_HEADSET | - DEVICE_IN_DGTL_DOCK_HEADSET | - DEVICE_IN_USB_ACCESSORY | - DEVICE_IN_USB_DEVICE | - DEVICE_IN_FM_TUNER | - DEVICE_IN_TV_TUNER | - DEVICE_IN_LINE | - DEVICE_IN_SPDIF | - DEVICE_IN_BLUETOOTH_A2DP | - DEVICE_IN_LOOPBACK | - DEVICE_IN_IP | - DEVICE_IN_BUS | - DEVICE_IN_PROXY | - DEVICE_IN_USB_HEADSET | - DEVICE_IN_BLUETOOTH_BLE | - DEVICE_IN_HDMI_ARC | - DEVICE_IN_ECHO_REFERENCE | - DEVICE_IN_DEFAULT); - public static final int DEVICE_IN_ALL_SCO = DEVICE_IN_BLUETOOTH_SCO_HEADSET; - public static final int DEVICE_IN_ALL_USB = (DEVICE_IN_USB_ACCESSORY | - DEVICE_IN_USB_DEVICE | - DEVICE_IN_USB_HEADSET); + public static final Set<Integer> DEVICE_IN_ALL_SET; + public static final Set<Integer> DEVICE_IN_ALL_SCO_SET; + public static final Set<Integer> DEVICE_IN_ALL_USB_SET; + static { + DEVICE_IN_ALL_SET = new HashSet<>(); + DEVICE_IN_ALL_SET.add(DEVICE_IN_COMMUNICATION); + DEVICE_IN_ALL_SET.add(DEVICE_IN_AMBIENT); + DEVICE_IN_ALL_SET.add(DEVICE_IN_BUILTIN_MIC); + DEVICE_IN_ALL_SET.add(DEVICE_IN_BLUETOOTH_SCO_HEADSET); + DEVICE_IN_ALL_SET.add(DEVICE_IN_WIRED_HEADSET); + DEVICE_IN_ALL_SET.add(DEVICE_IN_HDMI); + DEVICE_IN_ALL_SET.add(DEVICE_IN_TELEPHONY_RX); + DEVICE_IN_ALL_SET.add(DEVICE_IN_BACK_MIC); + DEVICE_IN_ALL_SET.add(DEVICE_IN_REMOTE_SUBMIX); + DEVICE_IN_ALL_SET.add(DEVICE_IN_ANLG_DOCK_HEADSET); + DEVICE_IN_ALL_SET.add(DEVICE_IN_DGTL_DOCK_HEADSET); + DEVICE_IN_ALL_SET.add(DEVICE_IN_USB_ACCESSORY); + DEVICE_IN_ALL_SET.add(DEVICE_IN_USB_DEVICE); + DEVICE_IN_ALL_SET.add(DEVICE_IN_FM_TUNER); + DEVICE_IN_ALL_SET.add(DEVICE_IN_TV_TUNER); + DEVICE_IN_ALL_SET.add(DEVICE_IN_LINE); + DEVICE_IN_ALL_SET.add(DEVICE_IN_SPDIF); + DEVICE_IN_ALL_SET.add(DEVICE_IN_BLUETOOTH_A2DP); + DEVICE_IN_ALL_SET.add(DEVICE_IN_LOOPBACK); + DEVICE_IN_ALL_SET.add(DEVICE_IN_IP); + DEVICE_IN_ALL_SET.add(DEVICE_IN_BUS); + DEVICE_IN_ALL_SET.add(DEVICE_IN_PROXY); + DEVICE_IN_ALL_SET.add(DEVICE_IN_USB_HEADSET); + DEVICE_IN_ALL_SET.add(DEVICE_IN_BLUETOOTH_BLE); + DEVICE_IN_ALL_SET.add(DEVICE_IN_HDMI_ARC); + DEVICE_IN_ALL_SET.add(DEVICE_IN_ECHO_REFERENCE); + DEVICE_IN_ALL_SET.add(DEVICE_IN_DEFAULT); + + DEVICE_IN_ALL_SCO_SET = new HashSet<>(); + DEVICE_IN_ALL_SCO_SET.add(DEVICE_IN_BLUETOOTH_SCO_HEADSET); + + DEVICE_IN_ALL_USB_SET = new HashSet<>(); + DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_ACCESSORY); + DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_DEVICE); + DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_HEADSET); + } // device states, must match AudioSystem::device_connection_state @UnsupportedAppUsage @@ -1229,6 +1265,40 @@ public class AudioSystem return getPlatformType(context) == PLATFORM_TELEVISION || forceSingleVolume; } + /** + * Return a set of audio device types from a bit mask audio device type, which may + * represent multiple audio device types. + * FIXME: Remove this when getting ride of bit mask usage of audio device types. + */ + public static Set<Integer> generateAudioDeviceTypesSet(int types) { + Set<Integer> deviceTypes = new HashSet<>(); + Set<Integer> allDeviceTypes = + (types & DEVICE_BIT_IN) == 0 ? DEVICE_OUT_ALL_SET : DEVICE_IN_ALL_SET; + for (int deviceType : allDeviceTypes) { + if ((types & deviceType) == deviceType) { + deviceTypes.add(deviceType); + } + } + return deviceTypes; + } + + /** + * Return the intersection of two audio device types collections. + */ + public static Set<Integer> intersectionAudioDeviceTypes( + @NonNull Set<Integer> a, @NonNull Set<Integer> b) { + Set<Integer> intersection = new HashSet<>(a); + intersection.retainAll(b); + return intersection; + } + + /** + * Return true if the audio device types collection only contains the given device type. + */ + public static boolean isSingleAudioDeviceType(@NonNull Set<Integer> types, int type) { + return types.size() == 1 && types.contains(type); + } + public static final int DEFAULT_MUTE_STREAMS_AFFECTED = (1 << STREAM_MUSIC) | (1 << STREAM_RING) | diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl index ced8615a3ee6..81a7ee28c425 100644 --- a/media/java/android/media/IMediaRouterService.aidl +++ b/media/java/android/media/IMediaRouterService.aidl @@ -43,6 +43,7 @@ interface IMediaRouterService { void setControlCategories(IMediaRouterClient client, in List<String> categories); // Methods for media router 2 + List<MediaRoute2Info> getSystemRoutes(); void registerClient2(IMediaRouter2Client client, String packageName); void unregisterClient2(IMediaRouter2Client client); void sendControlRequest(IMediaRouter2Client client, in MediaRoute2Info route, in Intent request); diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java index 74d26f030529..94ac77af3ac3 100644 --- a/media/java/android/media/MediaRouter2.java +++ b/media/java/android/media/MediaRouter2.java @@ -131,6 +131,25 @@ public class MediaRouter2 { mPackageName = mContext.getPackageName(); //TODO: read control categories from the manifest mHandler = new Handler(Looper.getMainLooper()); + + List<MediaRoute2Info> currentSystemRoutes = null; + try { + currentSystemRoutes = mMediaRouterService.getSystemRoutes(); + } catch (RemoteException ex) { + Log.e(TAG, "Unable to get current currentSystemRoutes", ex); + } + + if (currentSystemRoutes == null || currentSystemRoutes.isEmpty()) { + throw new RuntimeException("Null or empty currentSystemRoutes. Something is wrong."); + } + + for (MediaRoute2Info route : currentSystemRoutes) { + mRoutes.put(route.getId(), route); + } + // The first route is the currently selected system route. + // For example, if there are two system routes (BT and device speaker), + // BT will be the first route in the list. + mSelectedRoute = currentSystemRoutes.get(0); } /** @@ -409,6 +428,10 @@ public class MediaRouter2 { } void addRoutesOnHandler(List<MediaRoute2Info> routes) { + // TODO: When onRoutesAdded is first called, + // 1) clear mRoutes before adding the routes + // 2) Call onRouteSelected(system_route, reason_fallback) if previously selected route + // does not exist anymore. => We may need 'boolean MediaRoute2Info#isSystemRoute()'. List<MediaRoute2Info> addedRoutes = new ArrayList<>(); for (MediaRoute2Info route : routes) { mRoutes.put(route.getUniqueId(), route); diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java new file mode 100644 index 000000000000..2c60d6b3dec7 --- /dev/null +++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2Test.java @@ -0,0 +1,53 @@ +/* + * Copyright 2019 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.mediaroutertest; + +import static org.junit.Assert.assertNotNull; + +import android.content.Context; +import android.media.MediaRoute2Info; +import android.media.MediaRouter2; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class MediaRouter2Test { + Context mContext; + + @Before + public void setUp() throws Exception { + mContext = InstrumentationRegistry.getTargetContext(); + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void testGetSelectedRoute_afterCreation() throws Exception { + MediaRouter2 router = MediaRouter2.getInstance(mContext); + MediaRoute2Info initiallySelectedRoute = router.getSelectedRoute(); + assertNotNull(initiallySelectedRoute); + } +} diff --git a/native/graphics/jni/bitmap.cpp b/native/graphics/jni/bitmap.cpp index ff14832a2f0f..1aebeaf1e7e8 100644 --- a/native/graphics/jni/bitmap.cpp +++ b/native/graphics/jni/bitmap.cpp @@ -15,7 +15,7 @@ */ #include <android/bitmap.h> -#include <android/graphics/Bitmap.h> +#include <android/graphics/bitmap.h> int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, AndroidBitmapInfo* info) { @@ -24,7 +24,7 @@ int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap, } if (info) { - android::bitmap::imageInfo(env, jbitmap, info); + *info = ABitmap_getInfoFromJava(env, jbitmap); } return ANDROID_BITMAP_RESULT_SUCCESS; } @@ -34,11 +34,15 @@ int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr) { return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } - void* addr = android::bitmap::lockPixels(env, jbitmap); + android::graphics::Bitmap bitmap(env, jbitmap); + void* addr = bitmap.isValid() ? bitmap.getPixels() : nullptr; + if (!addr) { return ANDROID_BITMAP_RESULT_JNI_EXCEPTION; } + ABitmap_acquireRef(bitmap.get()); + if (addrPtr) { *addrPtr = addr; } @@ -50,9 +54,13 @@ int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap) { return ANDROID_BITMAP_RESULT_BAD_PARAMETER; } - bool unlocked = android::bitmap::unlockPixels(env, jbitmap); - if (!unlocked) { + android::graphics::Bitmap bitmap(env, jbitmap); + + if (!bitmap.isValid()) { return ANDROID_BITMAP_RESULT_JNI_EXCEPTION; } + + bitmap.notifyPixelsChanged(); + ABitmap_releaseRef(bitmap.get()); return ANDROID_BITMAP_RESULT_SUCCESS; } diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index bef769d7ba10..bcb76d7169ec 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -562,15 +562,7 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt mCarUxRestrictionManagerWrapper = new CarUxRestrictionManagerWrapper(); mNotificationDataManager = new NotificationDataManager(); - mNotificationDataManager.setOnUnseenCountUpdateListener( - () -> { - if (mNotificationDataManager != null) { - boolean hasUnseen = - mNotificationDataManager.getUnseenNotificationCount() > 0; - mCarNavigationBarController.toggleAllNotificationsUnseenIndicator( - mDeviceProvisionedController.isCurrentUserSetup(), hasUnseen); - } - }); + mNotificationDataManager.setOnUnseenCountUpdateListener(this::onUnseenCountUpdate); mEnableHeadsUpNotificationWhenNotificationShadeOpen = mContext.getResources().getBoolean( R.bool.config_enableHeadsUpNotificationWhenNotificationShadeOpen); @@ -692,6 +684,18 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt } /** + * This method is called whenever there is an update to the number of unseen notifications. + * This method can be extended by OEMs to customize the desired logic. + */ + protected void onUnseenCountUpdate() { + if (mNotificationDataManager != null) { + boolean hasUnseen = mNotificationDataManager.getUnseenNotificationCount() > 0; + mCarNavigationBarController.toggleAllNotificationsUnseenIndicator( + mDeviceProvisionedController.isCurrentUserSetup(), hasUnseen); + } + } + + /** * @return true if the notification panel is currently visible */ boolean isNotificationPanelOpen() { diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java index b188dc3949f2..45430197fdd8 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java @@ -50,9 +50,6 @@ import javax.inject.Singleton; @Singleton public class FullscreenUserSwitcher { private static final String TAG = FullscreenUserSwitcher.class.getSimpleName(); - // Because user 0 is headless, user count for single user is 2 - private static final int NUMBER_OF_BACKGROUND_USERS = 1; - private final Context mContext; private final Resources mResources; private final UserManager mUserManager; @@ -137,27 +134,18 @@ public class FullscreenUserSwitcher { /* isStartGuestSession= */ false, /* isAddUser= */ false, /* isForeground= */ true); - // For single user without trusted device, hide the user switcher. - if (!hasMultipleUsers() && !hasTrustedDevice(initialUser)) { - dismissUserSwitcher(); - return; - } - // Show unlock dialog for initial user + + // If the initial user has trusted device, display the unlock dialog on the keyguard. if (hasTrustedDevice(initialUser)) { mUnlockDialogHelper.showUnlockDialogAfterDelay(initialUser, mOnHideListener); + } else { + // If no trusted device, dismiss the keyguard. + dismissUserSwitcher(); } } /** - * Check if there is only one possible user to login in. - * In a Multi-User system there is always one background user (user 0) - */ - private boolean hasMultipleUsers() { - return mUserManager.getUserCount() > NUMBER_OF_BACKGROUND_USERS + 1; - } - - /** * Makes user grid visible. */ public void show() { diff --git a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java index 5d84d6450574..1928ad9add3e 100644 --- a/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java +++ b/packages/CarrierDefaultApp/tests/unit/src/com/android/carrierdefaultapp/CarrierDefaultReceiverTest.java @@ -21,7 +21,6 @@ import android.app.PendingIntent; import android.content.Intent; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; -import android.telephony.Rlog; import android.telephony.TelephonyManager; import android.test.InstrumentationTestCase; @@ -90,12 +89,10 @@ public class CarrierDefaultReceiverTest extends InstrumentationTestCase { Intent intent = new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED); intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); - Rlog.d(TAG, "OnReceive redirection intent"); mReceiver.onReceive(mContext, intent); mContext.waitForMs(100); - Rlog.d(TAG, "verify carrier action: showPortalNotification"); verify(mNotificationMgr, times(1)).notify(mString.capture(), mInt.capture(), mNotification.capture()); assertEquals(PORTAL_NOTIFICATION_ID, (int) mInt.getValue()); @@ -103,7 +100,6 @@ public class CarrierDefaultReceiverTest extends InstrumentationTestCase { PendingIntent pendingIntent = mNotification.getValue().contentIntent; assertNotNull(pendingIntent); - Rlog.d(TAG, "verify carrier action: disable all metered apns"); verify(mTelephonyMgr).setCarrierDataEnabled(eq(false)); } } diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ActivityTile.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ActivityTile.java index 8cd33a5b3f6c..b739ee62174d 100644 --- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ActivityTile.java +++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ActivityTile.java @@ -18,6 +18,7 @@ package com.android.settingslib.drawer; import android.content.Context; import android.content.Intent; +import android.content.pm.ActivityInfo; import android.content.pm.ComponentInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -33,7 +34,7 @@ import java.util.Objects; public class ActivityTile extends Tile { private static final String TAG = "ActivityTile"; - public ActivityTile(ComponentInfo info, String category) { + public ActivityTile(ActivityInfo info, String category) { super(info, category); setMetaData(info.metaData); } diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/MasterSwitchController.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/MasterSwitchController.java new file mode 100644 index 000000000000..a12aa83e9d4b --- /dev/null +++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/MasterSwitchController.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2019 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.settingslib.drawer; + +import android.os.Bundle; + +/** + * A controller that manages event for master switch. + */ +public abstract class MasterSwitchController extends SwitchController { + + @Override + protected final MetaData getMetaData() { + throw new UnsupportedOperationException(); + } + + @Override + final Bundle getBundle() { + throw new UnsupportedOperationException(); + } +} diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderTile.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderTile.java index b2ba5deee731..312d30e2f2ad 100644 --- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderTile.java +++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/ProviderTile.java @@ -42,10 +42,10 @@ public class ProviderTile extends Tile { private String mAuthority; private String mKey; - public ProviderTile(ComponentInfo info, String category, Bundle metaData) { + public ProviderTile(ProviderInfo info, String category, Bundle metaData) { super(info, category); setMetaData(metaData); - mAuthority = ((ProviderInfo) info).authority; + mAuthority = info.authority; mKey = metaData.getString(META_DATA_PREFERENCE_KEYHINT); } diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchController.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchController.java index e48da8608780..23669b2743ce 100644 --- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchController.java +++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchController.java @@ -108,7 +108,7 @@ public abstract class SwitchController { Bundle getBundle() { final MetaData metaData = getMetaData(); if (metaData == null) { - throw new IllegalArgumentException("Should not return null in getMetaData()"); + throw new NullPointerException("Should not return null in getMetaData()"); } final Bundle bundle = metaData.build(); diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java index a05c7d5d3b51..73f1a904b04b 100644 --- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java +++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java @@ -55,7 +55,7 @@ public abstract class SwitchesProvider extends ContentProvider { private String mAuthority; private final Map<String, SwitchController> mControllerMap = new LinkedHashMap<>(); - private final List<Bundle> mSwitchList = new ArrayList<>(); + private final List<Bundle> mSwitchDataList = new ArrayList<>(); /** * Get a list of {@link SwitchController} for this provider. @@ -88,7 +88,9 @@ public abstract class SwitchesProvider extends ContentProvider { controller.setAuthority(mAuthority); mControllerMap.put(key, controller); - mSwitchList.add(controller.getBundle()); + if (!(controller instanceof MasterSwitchController)) { + mSwitchDataList.add(controller.getBundle()); + } }); return true; } @@ -101,7 +103,7 @@ public abstract class SwitchesProvider extends ContentProvider { : null; if (TextUtils.isEmpty(key)) { if (METHOD_GET_SWITCH_DATA.equals(method)) { - bundle.putParcelableList(EXTRA_SWITCH_DATA, mSwitchList); + bundle.putParcelableList(EXTRA_SWITCH_DATA, mSwitchDataList); return bundle; } return null; @@ -114,7 +116,10 @@ public abstract class SwitchesProvider extends ContentProvider { switch (method) { case METHOD_GET_SWITCH_DATA: - return controller.getBundle(); + if (!(controller instanceof MasterSwitchController)) { + return controller.getBundle(); + } + break; case METHOD_GET_PROVIDER_ICON: if (controller instanceof ProviderIcon) { return ((ProviderIcon) controller).getProviderIcon(); diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java index 71ffff780b21..f93faeb0c7ae 100644 --- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java +++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java @@ -244,15 +244,15 @@ public class TileUtils { // TODO: Needs much optimization, too many PM queries going on here. if (user.getIdentifier() == ActivityManager.getCurrentUser()) { // Only add Settings for this user. - getTilesForAction(context, user, SETTINGS_ACTION, cache, null, tiles, true); - getTilesForAction(context, user, OPERATOR_SETTINGS, cache, + loadTilesForAction(context, user, SETTINGS_ACTION, cache, null, tiles, true); + loadTilesForAction(context, user, OPERATOR_SETTINGS, cache, OPERATOR_DEFAULT_CATEGORY, tiles, false); - getTilesForAction(context, user, MANUFACTURER_SETTINGS, cache, + loadTilesForAction(context, user, MANUFACTURER_SETTINGS, cache, MANUFACTURER_DEFAULT_CATEGORY, tiles, false); } if (setup) { - getTilesForAction(context, user, EXTRA_SETTINGS_ACTION, cache, null, tiles, false); - getTilesForAction(context, user, IA_SETTINGS_ACTION, cache, null, tiles, false); + loadTilesForAction(context, user, EXTRA_SETTINGS_ACTION, cache, null, tiles, false); + loadTilesForAction(context, user, IA_SETTINGS_ACTION, cache, null, tiles, false); } } @@ -284,18 +284,18 @@ public class TileUtils { } @VisibleForTesting - static void getTilesForAction(Context context, + static void loadTilesForAction(Context context, UserHandle user, String action, Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles, boolean requireSettings) { final Intent intent = new Intent(action); if (requireSettings) { intent.setPackage(SETTING_PKG); } - getActivityTiles(context, user, addedCache, defaultCategory, outTiles, intent); - getProviderTiles(context, user, addedCache, defaultCategory, outTiles, intent); + loadActivityTiles(context, user, addedCache, defaultCategory, outTiles, intent); + loadProviderTiles(context, user, addedCache, defaultCategory, outTiles, intent); } - private static void getActivityTiles(Context context, + private static void loadActivityTiles(Context context, UserHandle user, Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles, Intent intent) { final PackageManager pm = context.getPackageManager(); @@ -308,11 +308,11 @@ public class TileUtils { } final ActivityInfo activityInfo = resolved.activityInfo; final Bundle metaData = activityInfo.metaData; - getTile(user, addedCache, defaultCategory, outTiles, intent, metaData, activityInfo); + loadTile(user, addedCache, defaultCategory, outTiles, intent, metaData, activityInfo); } } - private static void getProviderTiles(Context context, + private static void loadProviderTiles(Context context, UserHandle user, Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles, Intent intent) { final PackageManager pm = context.getPackageManager(); @@ -330,13 +330,13 @@ public class TileUtils { continue; } for (Bundle metaData : switchData) { - getTile(user, addedCache, defaultCategory, outTiles, intent, metaData, + loadTile(user, addedCache, defaultCategory, outTiles, intent, metaData, providerInfo); } } } - private static void getTile(UserHandle user, Map<Pair<String, String>, Tile> addedCache, + private static void loadTile(UserHandle user, Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles, Intent intent, Bundle metaData, ComponentInfo componentInfo) { String categoryKey = defaultCategory; @@ -359,8 +359,8 @@ public class TileUtils { Tile tile = addedCache.get(key); if (tile == null) { tile = isProvider - ? new ProviderTile(componentInfo, categoryKey, metaData) - : new ActivityTile(componentInfo, categoryKey); + ? new ProviderTile((ProviderInfo) componentInfo, categoryKey, metaData) + : new ActivityTile((ActivityInfo) componentInfo, categoryKey); addedCache.put(key, tile); } else { tile.setMetaData(metaData); @@ -516,7 +516,7 @@ public class TileUtils { * @param value Boolean associated with the key * @return Bundle associated with the action, if returned by the content provider */ - public static Bundle putBooleanToUri(Context context, Uri uri, + public static Bundle putBooleanToUriAndGetResult(Context context, Uri uri, Map<String, IContentProvider> providerMap, String key, boolean value) { final Bundle bundle = new Bundle(); bundle.putBoolean(key, value); diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml index 3ff5cf490811..6289b8743f55 100644 --- a/packages/SettingsLib/res/values-af/strings.xml +++ b/packages/SettingsLib/res/values-af/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Gebruik Bluetooth-oudiokodek\nKeuse"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth-oudiovoorbeeldkoers"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Gebruik Bluetooth-oudiokodek\nKeuse: monsterkoers"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Dofgemaak beteken dit word nie deur foon of kopstuk gesteun nie"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth-oudiobisse per voorbeeld"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Gebruik Bluetooth-oudiokodek\nKeuse: bisse per monster"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth-oudiokanaalmodus"</string> diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml index 264d8de17872..45545a707eb6 100644 --- a/packages/SettingsLib/res/values-am/strings.xml +++ b/packages/SettingsLib/res/values-am/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"የብሉቱዝ ኦዲዮ ኮዴክ አስጀምር\nምርጫ"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"የብሉቱዝ ኦዲዮ ናሙና ፍጥነት"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"የብሉቱዝ ኦዲዮ ኮዴክን አስጀምር\nምርጫ፦ የናሙና ደረጃ አሰጣጥ"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"ግራጫ መልክ ሲታይ በስልክ ወይም በጆሮ ማዳመጫ አይደገፍም ማለት ነው"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"የብሉቱዝ ኦዲዮ ቢት በናሙና"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"የብሉቱዝ ኦዲዮ ኮዴክን አስጀምር\nምርጫ፦ ቢትስ በናሙና"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"የብሉቱዝ ኦዲዮ ሰርጥ ሁነታ"</string> diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml index c23023671c73..af06fc7e9d7d 100644 --- a/packages/SettingsLib/res/values-ar/strings.xml +++ b/packages/SettingsLib/res/values-ar/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"اختيار برنامج ترميز الصوت لمشغّل\nالبلوتوث"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"معدّل عيّنة صوت بلوتوث"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"اختيار برنامج ترميز الصوت لمشغّل\nالبلوتوث: معدّل العيّنة"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"\"غير متوفّر\" تعني أن الهاتف أو سماعة الرأس لا يدعمان برنامج الترميز"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"وحدات البت لكل عيّنة في صوت بلوتوث"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"اختيار برنامج ترميز الصوت لمشغّل\nالبلوتوث: عدد وحدات البت لكل عيّنة"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"وضع قناة صوت بلوتوث"</string> diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml index ab0ed2976508..49eabe1620eb 100644 --- a/packages/SettingsLib/res/values-as/strings.xml +++ b/packages/SettingsLib/res/values-as/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"ব্লুটুথ অডিঅ\' ক\'ডেকৰ বাছনি\nআৰম্ভ কৰক"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"ব্লুটুথ অডিঅ\' ছেম্পল ৰেইট"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"ব্লুটুথ অডিঅ\' LDAC বাছনি\nআৰম্ভ কৰক: নমুনাৰ হাৰ"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"ধোঁৱাবৰণীয়া হৈ থকা মানে এয়া ফ’ন অথবা হেডছেটটোৱে সমৰ্থন নকৰে"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"প্ৰতি ছেম্পলত ব্লুটুথ অডিঅ\' বিটসমূহ"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"ব্লুটুথ অডিঅ\' ক\'ডেকৰ বাছনি\nআৰম্ভ কৰক: প্ৰতি নমুনা ইমান বিট"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"ব্লুটুথ অডিঅ\' চ্চেনেল ম\'ড"</string> diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml index fe62d3139b40..158f13a14229 100644 --- a/packages/SettingsLib/res/values-az/strings.xml +++ b/packages/SettingsLib/res/values-az/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Bluetooth Audio KodeK\nSeçimini aktiv edin"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth Audio Nümunə Göstəricisi"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Bluetooth Audio Kodek\nSeçimini aktiv edin: Nümunə Göstəricisi"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Boz rəng telefon və ya qulaqlıq tərəfindən dəstəklənmədiyini bildirir"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Hər Nümunə Üçün Bluetooth Audio Bit"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Bluetooth Audio Kodek\nSeçimini aktiv edin: Hər Nümunə üçün Bit"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth Audio Kanal Rejimi"</string> diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml index 1619584883bd..2709df5a483e 100644 --- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Izaberite Bluetooth audio kodek\n"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Brzina uzorkovanja za Bluetooth audio"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Izaberite Bluetooth audio kodek:\n brzina uzorkovanja"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Ako je neka stavka zasivljena, to znači da je telefon ili slušalice ne podržavaju"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bitova po uzorku za Bluetooth audio"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Izaberite Bluetooth audio kodek:\n broj bitova po uzorku"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Režim kanala za Bluetooth audio"</string> diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml index 0f2df493696a..40295ea2e9e1 100644 --- a/packages/SettingsLib/res/values-be/strings.xml +++ b/packages/SettingsLib/res/values-be/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Уключыць кодэк Bluetooth Audio\nВыбар"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Частата дыскрэтызацыі Bluetooth Audio"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Уключыць кодэк Bluetooth Audio\nВыбар: частата дыскрэтызацыі"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Шэрым афарбаваны функцыі, якія не падтрымліваюцца тэлефонам або гарнітурай"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Біты на сэмпл для Bluetooth Audio"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Уключыць кодэк Bluetooth Audio\nВыбар: біты на дыскрэтызацыю"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Канальны рэжым Bluetooth Audio"</string> diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml index a3be2812ee2e..7b2537402077 100644 --- a/packages/SettingsLib/res/values-bg/strings.xml +++ b/packages/SettingsLib/res/values-bg/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Задействане на аудиокодек за Bluetooth\nИзбор"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Честота на дискретизация за звука през Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Задействане на аудиокодек за Bluetooth\nИзбор: Честота на дискретизация"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Неактивното състояние означава, че елементът не се поддържа от телефона или слушалките"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Битове на дискрет за звука през Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Задействане на аудиокодек за Bluetooth\nИзбор: Битове на дискрет"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Режим на канала на звука през Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml index 743de50fbb44..c41a3e590730 100644 --- a/packages/SettingsLib/res/values-bn/strings.xml +++ b/packages/SettingsLib/res/values-bn/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"ব্লুটুথ অডিও কোডেক ট্রিগার করুন\nএটি বেছে নেওয়া আছে"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"ব্লুটুথ অডিওর নমুনা হার"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"ব্লুটুথ অডিও কোডেক ট্রিগার করুন\nএটি বেছে নেওয়া আছে: স্যাম্পল রেট"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"গ্রে-আউট মানে যেখানে ফোন বা হেডসেট কাজ করে না"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"নমুনা প্রতি ব্লুটুথ অডিও বিট"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"ব্লুটুথ অডিও কোডেক ট্রিগার করুন\nএটি বেছে নেওয়া আছে: বিট্স পার স্যাম্পল"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"ব্লুটুথ অডিও চ্যানেল মোড"</string> diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml index 75a4047bedab..381fe4b41945 100644 --- a/packages/SettingsLib/res/values-bs/strings.xml +++ b/packages/SettingsLib/res/values-bs/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Aktivirajte Bluetooth Audio Codec\nOdabir"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Brzina uzorkovanja za Bluetooth audio"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Aktivirajte Bluetooth Audio Codec\nOdabir: Brzina uzorkovanja"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Ako je stavka nedostupna, to znači da je telefon ili slušalice ne podržavaju"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth audio bitovi po uzorku"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Aktivirajte Bluetooth Audio Codec\nOdabir: Bitovi po uzorku"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Način Bluetooth audio kanala"</string> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index 8627cf30f707..3257dc5a9383 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Activa el còdec d\'àudio per Bluetooth\nSelecció"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Freqüència de mostratge d’àudio per Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Activa el còdec d\'àudio per Bluetooth\nSelecció: freqüència de mostratge"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Si una opció està ombrejada, vol dir que el telèfon o els auriculars no l\'admeten"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bits per mostra de l\'àudio per Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Activa el còdec d\'àudio per Bluetooth\nSelecció: bits per mostra"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Mode de canal de l\'àudio per Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml index 6fef07a566f2..92ba7d16934e 100644 --- a/packages/SettingsLib/res/values-cs/strings.xml +++ b/packages/SettingsLib/res/values-cs/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Spustit zvukový kodek Bluetooth\nVýběr"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth Audio – vzorkovací frekvence"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Spustit zvukový kodek Bluetooth\nVýběr: vzorkovací frekvence"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Zašedlé možnosti nejsou telefonem nebo náhlavní soupravou podporovány"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth Audio – počet bitů na vzorek"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Spustit zvukový kodek Bluetooth\nVýběr: počet bitů na vzorek"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth Audio – režim kanálu"</string> diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml index 80ee95e40a28..d836b4a4057a 100644 --- a/packages/SettingsLib/res/values-da/strings.xml +++ b/packages/SettingsLib/res/values-da/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Udløs codec for Bluetooth-lyd\nValg"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Eksempelfrekvens for Bluetooth-lyd"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Udløs codec for Bluetooth-lyd\nValg: Samplingfrekvens"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Nedtonede funktioner understøttes ikke af telefonen eller headsettet."</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bit pr. eksempel for Bluetooth-lyd"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Udløs codec for Bluetooth-lyd\nValg: Bits pr. sampling"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Kanaltilstand for Bluetooth-lyd"</string> diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml index 1cd1e55f3d70..dff8247ac9a4 100644 --- a/packages/SettingsLib/res/values-de/strings.xml +++ b/packages/SettingsLib/res/values-de/strings.xml @@ -234,6 +234,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Bluetooth-Audio-Codec auslösen\nAuswahl"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth-Audio-Abtastrate"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Bluetooth-Audio-Codec auslösen\nAuswahl: Abtastrate"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Wenn etwas ausgegraut ist, wird es nicht vom Smartphone oder Headset unterstützt"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth-Audio/Bits pro Sample"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Bluetooth-Audio-Codec auslösen\nAuswahl: Bits pro Sample"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth-Audiokanal-Modus"</string> diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml index 7dee120826bd..a86d2594cd55 100644 --- a/packages/SettingsLib/res/values-el/strings.xml +++ b/packages/SettingsLib/res/values-el/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Ενεργοποίηση κωδικοποιητή ήχου Bluetooth\nΕπιλογή"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Ρυθμός δειγματοληψίας ήχου Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Ενεργοποίηση κωδικοποιητή ήχου Bluetooth\nΕπιλογή: Ρυθμός δειγματοληψίας"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Οι γκριζαρισμένες επιλογές δεν υποστηρίζονται από τηλέφωνο ή ακουστικά"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bit ανά δείγμα ήχου Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Ενεργοποίηση κωδικοποιητή ήχου Bluetooth\nΕπιλογή: Bit ανά δείγμα"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Λειτουργία καναλιού ήχου Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml index ba9beb62a709..cadafce21840 100644 --- a/packages/SettingsLib/res/values-en-rAU/strings.xml +++ b/packages/SettingsLib/res/values-en-rAU/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Trigger Bluetooth Audio Codec\nSelection"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth audio sample rate"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Trigger Bluetooth Audio Codec\nSelection: Sample Rate"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Grey-out means not supported by phone or headset"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth audio bits per sample"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Trigger Bluetooth Audio Codec\nSelection: Bits Per Sample"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth audio channel mode"</string> diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml index ba9beb62a709..cadafce21840 100644 --- a/packages/SettingsLib/res/values-en-rCA/strings.xml +++ b/packages/SettingsLib/res/values-en-rCA/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Trigger Bluetooth Audio Codec\nSelection"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth audio sample rate"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Trigger Bluetooth Audio Codec\nSelection: Sample Rate"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Grey-out means not supported by phone or headset"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth audio bits per sample"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Trigger Bluetooth Audio Codec\nSelection: Bits Per Sample"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth audio channel mode"</string> diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml index ba9beb62a709..cadafce21840 100644 --- a/packages/SettingsLib/res/values-en-rGB/strings.xml +++ b/packages/SettingsLib/res/values-en-rGB/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Trigger Bluetooth Audio Codec\nSelection"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth audio sample rate"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Trigger Bluetooth Audio Codec\nSelection: Sample Rate"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Grey-out means not supported by phone or headset"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth audio bits per sample"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Trigger Bluetooth Audio Codec\nSelection: Bits Per Sample"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth audio channel mode"</string> diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml index ba9beb62a709..cadafce21840 100644 --- a/packages/SettingsLib/res/values-en-rIN/strings.xml +++ b/packages/SettingsLib/res/values-en-rIN/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Trigger Bluetooth Audio Codec\nSelection"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth audio sample rate"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Trigger Bluetooth Audio Codec\nSelection: Sample Rate"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Grey-out means not supported by phone or headset"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth audio bits per sample"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Trigger Bluetooth Audio Codec\nSelection: Bits Per Sample"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth audio channel mode"</string> diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml index 0f117745063e..444dbcb98241 100644 --- a/packages/SettingsLib/res/values-en-rXC/strings.xml +++ b/packages/SettingsLib/res/values-en-rXC/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Trigger Bluetooth Audio Codec\nSelection"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth Audio Sample Rate"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Trigger Bluetooth Audio Codec\nSelection: Sample Rate"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Gray-out means not supported by phone or headset"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth Audio Bits Per Sample"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Trigger Bluetooth Audio Codec\nSelection: Bits Per Sample"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth Audio Channel Mode"</string> diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index 41c817e0f6db..6a6f800c4684 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Activar el códec de audio por Bluetooth\nSelección"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Frecuencia de muestreo del audio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Activar el códec de audio por Bluetooth\nSelección: porcentaje de la muestra"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Si la opción está inhabilitada, significa que el teléfono o los auriculares no la admiten"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bits por muestra del audio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Activar el códec de audio por Bluetooth\nSelección: bits por muestra"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Modo de canal del audio Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index 897eaa3ffb7f..e29773ab0218 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Activar el códec de audio por Bluetooth\nSelección"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Frecuencia de muestreo de audio de Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Activar el códec de audio por Bluetooth\nSelección: frecuencia de muestreo"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Si una opción aparece atenuada, no es compatible con el teléfono o los auriculares"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bits por muestra del audio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Activar el códec de audio por Bluetooth\nSelección: bits por muestra"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Modo de canal de audio de Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml index 9b94222a8fa5..f425e1e9fb89 100644 --- a/packages/SettingsLib/res/values-et/strings.xml +++ b/packages/SettingsLib/res/values-et/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Bluetoothi helikodeki käivitamine\nValik"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetoothi heli diskreetimissagedus"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Bluetoothi helikodeki käivitamine\nValik: diskreetimissagedus"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Hallilt kuvamine tähendab, et telefon või peakomplekt seda ei toeta"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetoothi heli bitte diskreedi kohta"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Bluetoothi helikodeki käivitamine\nValik: bittide arv diskreedi kohta"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetoothi heli kanalirežiim"</string> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index b0e4b2623a8c..e9810e502310 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Abiarazi Bluetooth bidezko audio-kodeka\nHautapena"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth bidezko audioaren lagin-abiadura"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Abiarazi Bluetooth bidezko audio-kodeka\nHautapena: lagin-abiadura"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Kolore apalagoz agertzen bada, esan nahi du telefonoak edo entzungailuak ez duela onartzen"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth bidezko audioaren lagin bakoitzeko bit kopurua"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Abiarazi Bluetooth bidezko audio-kodeka\nHautapena: lagin bakoitzeko bitak"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth bidezko audioaren kanalaren modua"</string> diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml index 7298826f2614..2f25ab2f66ce 100644 --- a/packages/SettingsLib/res/values-fa/strings.xml +++ b/packages/SettingsLib/res/values-fa/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"راهاندازی کدک صوتی بلوتوثی\nانتخاب"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"سرعت نمونه بلوتوث صوتی"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"راهاندازی کدک صوتی بلوتوثی\nانتخاب: سرعت نمونه"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"«خاکستری» به این معناست که تلفن یا هدست از آن پشتیبانی نمیکند"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"بیتهای بلوتوث صوتی در هر نمونه"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"راهاندازی کدک صوتی بلوتوثی\nانتخاب: تعداد بیت در نمونه"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"حالت کانال بلوتوث صوتی"</string> diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml index 6f58f0352a0a..a9904af047e8 100644 --- a/packages/SettingsLib/res/values-fi/strings.xml +++ b/packages/SettingsLib/res/values-fi/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Käynnistä Bluetooth-äänipakkaus\nValinta"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth-ääninäytteen siirtonopeus"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Käynnistä Bluetooth-äänipakkaus\nValinta: esimerkkinopeus"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Himmennys tarkoittaa, että puhelin tai kuulokemikrofoni ei tue tätä"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth-äänen bittiä/näyte-arvo"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Käynnistä Bluetooth-äänipakkaus\nValinta: bittiä/näyte"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth-äänen kanavatila"</string> diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml index a5526f3a41b7..0f1c213c1974 100644 --- a/packages/SettingsLib/res/values-fr-rCA/strings.xml +++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Déclencher le codec audio Bluetooth\nSélection"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Taux d\'échantillonnage pour l\'audio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Déclencher le codec audio Bluetooth\nSélection : taux d\'échantillonnage"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Une option grisée signifie qu\'elle n\'est pas prise en charge par le téléphone ou par les écouteurs"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bits par échantillon pour l\'audio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Déclencher le codec audio Bluetooth\nSélection : bits par échantillon"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Mode de canal pour l\'audio Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index 069825a266c6..0bfb3c7e8151 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -234,6 +234,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Critère pour déclencher la sélection du codec audio\nBluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Taux d\'échantillonnage audio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Critère de sélection du codec audio\nBluetooth : taux d\'échantillonnage"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Si le codec est grisé, c\'est qu\'il n\'est pas compatible avec le téléphone ou le casque"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bits par échantillon pour l\'audio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Critère de sélection du codec audio\nBluetooth : nombre de bits par échantillon"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Mode de chaîne de l\'audio Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml index eaab027a5659..213d33ae0cac 100644 --- a/packages/SettingsLib/res/values-gl/strings.xml +++ b/packages/SettingsLib/res/values-gl/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Activar códec de audio por Bluetooth\nSelección"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Taxa de mostra de audio por Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Activar códec de audio por Bluetooth\nSelección: taxa de mostra"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Os elementos deshabilitados non son compatibles co teléfono ou cos auriculares"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bits por mostra de audio por Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Activar códec de audio por Bluetooth\nSelección: bits por mostra"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Modo de canle de audio por Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml index 00fd024c1323..8192d47036a7 100644 --- a/packages/SettingsLib/res/values-gu/strings.xml +++ b/packages/SettingsLib/res/values-gu/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"બ્લૂટૂથ ઑડિઓ કોડેક\nપસંદગી ટ્રિગર કરો"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"બ્લૂટૂથ ઑડિઓ નમૂના દર"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"બ્લૂટૂથ ઑડિઓ કોડેક\nપસંદગી ટ્રિગર કરો: નમૂના રેટ"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"નિષ્ક્રિય હોવાનો અર્થ એ છે કે ફોન અથવા હૅડસેટ દ્વારા સપોર્ટ આપવામાં આવતો નથી"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"નમૂના દીઠ બ્લૂટૂથ ઑડિઓ બિટ"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"બ્લૂટૂથ ઑડિઓ કોડેક\nપસંદગી ટ્રિગર કરો: નમૂના દીઠ બિટ"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"બ્લૂટૂથ ઑડિઓ ચેનલ મોડ"</string> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index 96aec94808e3..207a479253ac 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"ब्लूटूथ ऑडियो कोडेक का\nविकल्प चालू करें"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"ब्लूटूथ ऑडियो नमूना दर"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"ब्लूटूथ ऑडियो कोडेक का\nयह विकल्प चालू करें: सैंपल की दर"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"धूसर किया गया का मतलब है कि फ़ोन या हेडसेट पर काम नहीं करता"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"ब्लूटूथ ऑडियो बिट प्रति नमूना"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"ब्लूटूथ ऑडियो कोडेक का\nयह विकल्प चालू करें: हर सैंपल के लिए बिट की संख्या"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"ब्लूटूथ ऑडियो चैनल मोड"</string> diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml index 6df46ca407c0..97a58625b3d5 100644 --- a/packages/SettingsLib/res/values-hr/strings.xml +++ b/packages/SettingsLib/res/values-hr/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Pokreni odabir kodeka za Bluetooth\nAudio"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Brzina uzorka za Bluetooth Audio"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Pokreni odabir kodeka za Bluetooth\nAudio: brzina uzorkovanja"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Ako je stavka siva, znači da je telefon ili slušalice ne podržavaju"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bitovi po uzorku za Bluetooth Audio"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Pokreni odabir kodeka za Bluetooth\nAudio: bitovi po uzorku"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Način kanala za Bluetooth Audio"</string> diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml index 6b5b05e6f00d..cba6c6554b8a 100644 --- a/packages/SettingsLib/res/values-hu/strings.xml +++ b/packages/SettingsLib/res/values-hu/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Bluetooth-hangkodek aktiválása\nKiválasztás"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth hang – mintavételezési gyakoriság"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Bluetooth-hangkodek aktiválása\nKiválasztás: Mintavételezési gyakoriság"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"A kiszürkítés azt jelenti, hogy nem támogatja telefon vagy headset"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth hang – bit/minta"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Bluetooth-hangkodek aktiválása\nKiválasztás: Bit/minta"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth hang – Csatornamód"</string> diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml index c4002b9a1446..a76c9609079e 100644 --- a/packages/SettingsLib/res/values-hy/strings.xml +++ b/packages/SettingsLib/res/values-hy/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Գործարկել Bluetooth աուդիո կոդեկը\nԸնտրություն"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth աուդիոյի ընդհատավորման հաճախականությունը"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Գործարկել Bluetooth աուդիո կոդեկը\nԸնտրություն՝ ընդհատավորման հաճախականություն"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Եթե տարրը մոխրագույն է, նշանակում է, որ չի աջակցվում հեռախոսի համ ականջակալի կողմից։"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth աուդիո, բիթ / նմուշ"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Գործարկել Bluetooth աուդիո կոդեկը\nԸնտրություն՝ բիթ/նմուշ"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth աուդիո կապուղու ռեժիմը"</string> diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml index 753f225491db..0feae4ee2266 100644 --- a/packages/SettingsLib/res/values-in/strings.xml +++ b/packages/SettingsLib/res/values-in/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Aktifkan Codec Audio Bluetooth\nPilihan"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Frekuensi Sampel Audio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Aktifkan Codec Audio Bluetooth\nPilihan: Frekuensi Sampel"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Berwarna abu-abu artinya tidak didukung oleh ponsel atau headset"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bit Per Sampel Audio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Aktifkan Codec Audio Bluetooth\nPilihan: Bit Per Sampel"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Mode Channel Audio Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml index b1d40bfbe923..d45f43318ea2 100644 --- a/packages/SettingsLib/res/values-is/strings.xml +++ b/packages/SettingsLib/res/values-is/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Virkja Bluetooth-hljóðkóðara\nVal"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth hljóðtökutíðni"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Virkja Bluetooth-hljóðkóðara\nVal: upptökutíðni"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Óvirkt þýðir að síminn eða höfuðtólin styðja þetta ekki"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth hljóðbitar í úrtaki"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Virkja Bluetooth-hljóðkóðara\nVal: bitar í úrtaki"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Hljóðrásarstilling Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml index 7f2bd3e9198b..fe111fc0fcd4 100644 --- a/packages/SettingsLib/res/values-it/strings.xml +++ b/packages/SettingsLib/res/values-it/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Attiva il codec audio Bluetooth\nSelezione"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Frequenza campionamento audio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Attiva il codec audio Bluetooth\nSelezione: Frequenza di campionamento"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Se il codec non è selezionabile significa che non è supportato dal telefono o dalle cuffie"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bit per campione dell\'audio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Attiva il codec audio Bluetooth\nSelezione: bit per campione"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Modalità canale audio Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml index bdd1babefa32..8b47c54e5b9e 100644 --- a/packages/SettingsLib/res/values-iw/strings.xml +++ b/packages/SettingsLib/res/values-iw/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"הפעלת Codec אודיו ל-Bluetooth\nבחירה"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"קצב דגימה של אודיו ל-Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"הפעלת Codec אודיו ל-Bluetooth\nבחירה: קצב דגימה"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"כשזה מופיע באפור, אין לזה תמיכה בטלפון או באוזניות"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"מספר סיביות לדגימה באודיו ל-Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"הפעלת Codec אודיו ל-Bluetooth\nבחירה: סיביות לדגימה"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"מצב של ערוץ אודיו ל-Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml index a6192a458ca8..c955a392ea73 100644 --- a/packages/SettingsLib/res/values-ja/strings.xml +++ b/packages/SettingsLib/res/values-ja/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Bluetooth オーディオ コーデックを起動\n選択"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth オーディオ サンプルレート"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Bluetooth オーディオ コーデックを起動\n選択: サンプルレート"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"グレー表示のコーデックは、スマートフォンまたはヘッドセットが対応していません"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"サンプルあたりの Bluetooth オーディオ ビット"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Bluetooth オーディオ コーデックを起動\n選択: サンプルあたりのビット数"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth オーディオ チャンネル モード"</string> diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml index a3633f64a9f8..d8fda4b34125 100644 --- a/packages/SettingsLib/res/values-ka/strings.xml +++ b/packages/SettingsLib/res/values-ka/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Bluetooth-ის აუდიო კოდეკის გაშვება\nარჩევანი"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth აუდიოს დისკრეტიზაციის სიხშირე"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Bluetooth-ის აუდიო კოდეკის გაშვება\nარჩევანი: ნიმუშთა მაჩვენებელი"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"არააქტიური ნიშნავს, რომ ტელეფონის ან ყურსასმენის მიერ მხარდაჭერილი არ არის"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth აუდიოს ბიტების რაოდენობა ნიმუშზე"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Bluetooth-ის აუდიო კოდეკის გაშვება\nარჩევანი: ბიტები ნიმუშზე"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth აუდიოს არხის რეჟიმი"</string> diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml index 0962e55e2dda..025532dbb349 100644 --- a/packages/SettingsLib/res/values-kk/strings.xml +++ b/packages/SettingsLib/res/values-kk/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Bluetooth аудиокодегін іске қосу\nТаңдау"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth арқылы дыбыс іріктеу жиілігі"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Bluetooth аудиокодегін іске қосу\nТаңдау: іріктеу жылдамдығы"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Сұр түсті болса, бұл оған телефонда не гарнитурада қолдау көрсетілмейтінін білдіреді."</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth арқылы дыбыстың разрядтылық мөлшері"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Bluetooth аудиокодегін іске қосу\nТаңдау: разрядтылық"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth дыбыстық арна режимі"</string> diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml index 45620e831f9c..e9f5ab0ff18d 100644 --- a/packages/SettingsLib/res/values-km/strings.xml +++ b/packages/SettingsLib/res/values-km/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"ជំរុញការជ្រើសរើសកូឌិកសំឡេង\nប៊្លូធូស"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"អត្រាគំរូសំឡេងប៊្លូធូស"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"ជំរុញការជ្រើសរើសកូឌិកសំឡេង\nប៊្លូធូស៖ អត្រាគំរូ"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"ការកំណត់ជាពណ៌ប្រផេះមានន័យថាទូរសព្ទ ឬកាសមិនស្គាល់ទេ"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"កម្រិតប៊ីតក្នុងមួយគំរូនៃសំឡេងប៊្លូធូស"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"ជំរុញការជ្រើសរើសកូឌិកសំឡេង\nប៊្លូធូស៖ កម្រិតប៊ីតក្នុងមួយគំរូ"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"មុខងាររលកសញ្ញាសំឡេងប៊្លូធូស"</string> diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml index 1fc2e4a91081..4feccaf2f1a0 100644 --- a/packages/SettingsLib/res/values-kn/strings.xml +++ b/packages/SettingsLib/res/values-kn/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"ಬ್ಲೂಟೂತ್ ಆಡಿಯೋ ಕೋಡೆಕ್ ಅನ್ನು ಟ್ರಿಗ್ಗರ್ ಮಾಡಿ\nಆಯ್ಕೆ"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"ಬ್ಲೂಟೂತ್ ಆಡಿಯೋ ಮಾದರಿ ದರ"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"ಬ್ಲೂಟೂತ್ ಆಡಿಯೋ ಕೋಡೆಕ್ ಅನ್ನು ಟ್ರಿಗ್ಗರ್ ಮಾಡಿ\nಆಯ್ಕೆ: ಮಾದರಿ ರೇಟ್"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"ಬೂದುಬಣ್ಣಕ್ಕೆ ತಿರುಗುವುದು ಎಂದರೆ ಫೋನ್ ಅಥವಾ ಹೆಡ್ಸೆಟ್ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ ಎಂದರ್ಥ"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"ಬ್ಲೂಟೂತ್ ಆಡಿಯೊ ಬಿಟ್ಸ್ನ ಪ್ರತಿ ಮಾದರಿ"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"ಬ್ಲೂಟೂತ್ ಆಡಿಯೋ ಕೋಡೆಕ್ ಅನ್ನು ಟ್ರಿಗ್ಗರ್ ಮಾಡಿ \nಆಯ್ಕೆ: ಬಿಟ್ಸ್ನ ಪ್ರತಿ ಮಾದರಿ"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"ಬ್ಲೂಟೂತ್ ಆಡಿಯೋ ಚಾನೆಲ್ ಮೋಡ್"</string> diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml index 8e7c6977245f..4707ef8e372f 100644 --- a/packages/SettingsLib/res/values-ko/strings.xml +++ b/packages/SettingsLib/res/values-ko/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"블루투스 오디오 코덱 실행\n선택"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"블루투스 오디오 샘플링 비율"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"블루투스 오디오 코덱 실행\n선택: 샘플링 비율"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"비활성화되어 있으면 스마트폰 또는 헤드셋에서 지원하지 않음을 의미함"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"블루투스 오디오 샘플당 비트"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"블루투스 오디오 코덱 실행\n선택: 샘플당 비트"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"블루투스 오디오 채널 모드"</string> diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml index 18a1468f2d75..2197a9f3750f 100644 --- a/packages/SettingsLib/res/values-ky/strings.xml +++ b/packages/SettingsLib/res/values-ky/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Bluetooth Audio кодегин иштетүү\nТандоо"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth аудио үлгүсүнүн ылдамдыгы"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Bluetooth Audio кодегин иштетүү\nТандоо: Үлгү жыштыгы"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Боз түс менен белгиленген кодек – бул телефондо же гарнитурада колдоого алынбайт дегенди билдирет"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Бир үлгүдөгү Bluetooth аудио биттери"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Bluetooth Audio кодегин иштетүү\nТандоо: Бир үлгүдөгү биттер"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth аудио каналынын режими"</string> diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml index 808d5a796a48..de3f644b8700 100644 --- a/packages/SettingsLib/res/values-lo/strings.xml +++ b/packages/SettingsLib/res/values-lo/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"ເປີດໃຊ້ Bluetooth Audio Codec\nການເລືອກ"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth Audio Sample Rate"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"ເປີດໃຊ້ Bluetooth Audio Codec\nການເລືອກ: Sample Rate"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"ສ່ວນທີ່ເປັນສີເທົາໝາຍຄວາມວ່າບໍ່ຮອງຮັບໂດຍໂທລະສັບ ຫຼື ຊຸດຫູຟັງ"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth Audio Bits Per Sample"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"ເປີດໃຊ້ Bluetooth Audio Codec\nການເລືອກ: Bits Per Sample"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"ໂໝດຊ່ອງສຽງ Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml index 78d1b1bf0c5c..6157a8700044 100644 --- a/packages/SettingsLib/res/values-lt/strings.xml +++ b/packages/SettingsLib/res/values-lt/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Suaktyvinti „Bluetooth“ garso kodeką\nPasirinkimas"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"„Bluetooth“ garso pavyzdžio dažnis"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Suaktyvinti „Bluetooth“ garso kodeką\nPasirinkimas: pavyzdžio dažnis"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Pilka spalva reiškia, kad telefonas arba ausinės nepalaiko tos funkcijos"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"„Bluetooth“ garso įrašo bitų skaičius pavyzdyje"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Suaktyvinti „Bluetooth“ garso kodeką\nPasirinkimas: bitų skaičius pavyzdyje"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"„Bluetooth“ garso kanalo režimas"</string> diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml index 0ae10aa6c43c..51b909c3bb53 100644 --- a/packages/SettingsLib/res/values-lv/strings.xml +++ b/packages/SettingsLib/res/values-lv/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Aktivizēt Bluetooth audio kodeku\nAtlase"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth audio iztveršanas ātrums"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Aktivizēt Bluetooth audio kodeku\nAtlase: iztveršanas ātrums"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Ja vienums ir pelēkots, tas netiek atbalstīts tālrunī vai austiņās."</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth audio bitu skaits iztvērumā"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Aktivizēt Bluetooth audio kodeku\nAtlase: bitu skaitu iztvērumā"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth audio kanāla režīms"</string> diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml index 9850ac5b4ed9..9a0d2da73642 100644 --- a/packages/SettingsLib/res/values-mk/strings.xml +++ b/packages/SettingsLib/res/values-mk/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Вклучете го аудио кодекот преку Bluetooth\nСелекција"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Стапка на семпл преку Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Вклучете го аудио кодекот преку Bluetooth\nСелекција: стапка на примерокот"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Ако е сиво, значи дека не е поддржано од телефонот или од слушалките"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Аудио бит-по-семпл преку Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Вклучете го аудио кодекот преку Bluetooth\nСелекција: бит-по-семпл"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Режим на канал за аудио преку Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml index 2692a30a85d2..e9558fcdaa0a 100644 --- a/packages/SettingsLib/res/values-ml/strings.xml +++ b/packages/SettingsLib/res/values-ml/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Bluetooth Audio Codec\nSelection ട്രിഗ്ഗര് ചെയ്യുക"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth ഓഡിയോ സാമ്പിൾ നിരക്ക്"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Bluetooth Audio Codec\nSelection ട്രിഗ്ഗര് ചെയ്യുക: സാമ്പിൾ റേറ്റ്"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"ചാരനിറത്തിലാക്കിയിട്ടുണ്ടെങ്കിൽ, ഫോണോ ഹെഡ്സെറ്റോ പിന്തുണയ്ക്കുന്നില്ലെന്നാണ് അർത്ഥം"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"പ്രതി സാമ്പിളിലെ Bluetooth ഓഡിയോ ബിറ്റ് നി"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Bluetooth Audio Codec\nSelection ട്രിഗ്ഗര് ചെയ്യുക: ഓരോ സാമ്പിളിനുള്ള ബിറ്റുകൾ"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth ഓഡിയോ ചാനൽ മോഡ്"</string> diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml index aa4ec769e0fd..4997f0b1528a 100644 --- a/packages/SettingsLib/res/values-mn/strings.xml +++ b/packages/SettingsLib/res/values-mn/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Bluetooth-н аудио кодлогчийг өдөөх\nСонголт"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth аудио жишээний үнэлгээ"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Bluetooth-н аудио кодлогчийг өдөөх\nСонголт: Жишээ үнэлгээ"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Идэвхгүй саарал байх нь утас эсвэл чихэвч дэмждэггүй болохыг илтгэнэ"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Жишээ тутмын Bluetooth аудионы бит"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Bluetooth-н аудио кодлогчийг өдөөх\nСонголт: Жишээ бүрийн бит"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth аудио сувгийн горим"</string> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index 966cdffe729b..1dbd59213932 100644 --- a/packages/SettingsLib/res/values-mr/strings.xml +++ b/packages/SettingsLib/res/values-mr/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"ब्लूटूथ ऑडिओ Codec ट्रिगर करा\nनिवड"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"ब्लूटूथ ऑडिओ पॅटर्न दर"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"ब्लूटूथ ऑडिओ Codec ट्रिगर करा\nनिवड: नमुना दर"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"फोन किंवा हेडसेटला सपोर्ट करत नाही म्हणजे ती निकामी झाली आहे"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"प्रति पॅटर्न ब्लूटूध ऑडिओ बिट"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"ब्लूटूथ ऑडिओ Codec ट्रिगर करा\nनिवड: बिट प्रति नमुना"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"ब्लूटूथ ऑडिओ चॅनेल मोड"</string> diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml index 88d7c7d6fd6f..790480d7ea04 100644 --- a/packages/SettingsLib/res/values-ms/strings.xml +++ b/packages/SettingsLib/res/values-ms/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Cetuskan Codec Audio Bluetooth\nPilihan"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Kadar Sampel Audio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Cetuskan Codec Audio Bluetooth\nPilihan: Kadar Sampel"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Bahagian yang dikelabukan bermaksud tidak disokong oleh telefon atau set kepala"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bit Per Sampel Audio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Cetuskan Codec Audio Bluetooth\nPilihan: Bit Per Sampel"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Mod Saluran Audio Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml index 6dfd2909efd5..dc81d056ac0f 100644 --- a/packages/SettingsLib/res/values-my/strings.xml +++ b/packages/SettingsLib/res/values-my/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"ဘလူးတုသ် အသံ LDAC ကိုးဒက်ခ် ဖွင့်ခြင်း\nရွေးချယ်မှု"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"ဘလူးတုသ်အသံနမူနာနှုန်း"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"ဘလူးတုသ် အသံ ကိုးဒက်ခ် ဖွင့်ခြင်း\nရွေးချယ်မှု- နမူနာနှုန်း"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"မီးခိုးရောင် ခြယ်ထားခြင်းသည် ဖုန်း သို့မဟုတ် မိုက်ခွက်ပါနားကြပ်မှ ပံ့ပိုးထားမှုမရှိခြင်းကို ဆိုလိုသည်။"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"နမူနာတစ်ခုစီတွင် ပါဝင်သော ဘလူးတုသ်အသံပမာဏ Bits"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"ဘလူးတုသ် အသံ ကိုးဒက်ခ် ဖွင့်ခြင်း\nရွေးချယ်မှု- နမူနာတစ်ခုစီအတွက် Bits"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"ဘလူးတုသ်အသံချန်နယ်မုဒ်"</string> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index 760c409c0048..d0e4966721cd 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Utløs kodek for Bluetooth-lyd\nValg"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Samplefrekvens for Bluetooth-lyd"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Utløs kodek for Bluetooth-lyd\nValg: samplefrekvens"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Hvis den er nedtonet, støttes den ikke av telefonen eller hodetelefonene"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bits per sample for Bluetooth-lyd"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Utløs kodek for Bluetooth-lyd\nValg: bits per sample"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Kanalmodus for Bluetooth-lyd"</string> diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml index 77f87ffc4ea8..d8ed4cbcf36f 100644 --- a/packages/SettingsLib/res/values-ne/strings.xml +++ b/packages/SettingsLib/res/values-ne/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"ब्लुटुथ अडियो कोडेक ट्रिगर गर्नुहोस्\nचयन"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"ब्लुटुथ अडियोको नमूना दर"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"ब्लुटुथ अडियो कोडेक ट्रिगर गर्नुहोस्\nचयन: नमुना दर"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"खरानी रङले भरिएको भन्नाले फोन वा हेडसेटले समर्थन नगरेको बुझाउँछ"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"प्रति नमूना ब्लुटुथ अडियोका बिटहरू"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"ब्लुटुथ अडियो कोडेक ट्रिगर गर्नुहोस्\nचयन: बिट प्रति नमुना"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"ब्लुटुथ अडियो च्यानलको मोड"</string> diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml index 55f56d98483b..d5ce54050aff 100644 --- a/packages/SettingsLib/res/values-nl/strings.xml +++ b/packages/SettingsLib/res/values-nl/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Codec voor Bluetooth-audio activeren\nSelectie"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Sample rate van Bluetooth-audio"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Codec voor Bluetooth-audio activeren\nSelectie: Bemonsteringsfrequentie"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Uitgegrijsd betekent niet ondersteund door telefoon of headset"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bits per sample voor Bluetooth-audio"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Codec voor Bluetooth-audio activeren\nSelectie: Bits per sample"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Kanaalmodus voor Bluetooth-audio"</string> diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml index 98c302db0c7d..024bd3c5deab 100644 --- a/packages/SettingsLib/res/values-or/strings.xml +++ b/packages/SettingsLib/res/values-or/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"ବ୍ଲୁଟୂଥ୍ ଅଡିଓ କୋଡେକ୍\nସିଲେକ୍ସନ୍କୁ ଗତିଶୀଳ କରନ୍ତୁ"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"ବ୍ଲୁଟୂଥ୍ ଅଡିଓ ସାମ୍ପଲ୍ ରେଟ୍"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"ବ୍ଲୁଟୂଥ୍ ଅଡିଓ କୋଡେକ୍\nସିଲେକ୍ସନ୍କୁ ଗତିଶୀଳ କରନ୍ତୁ: ସାମ୍ପଲ୍ ରେଟ୍"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"ଗ୍ରେ-ଆଉଟ୍ ଅର୍ଥ ଫୋନ୍ କିମ୍ବା ହେଡ୍ସେଟ୍ରେ ସମର୍ଥନ କରୁନାହିଁ"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"ନମୁନା ପିଛା ବ୍ଲୁଟୂଥ୍ ଅଡିଓ ବିଟ୍ସ"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"ବ୍ଲୁଟୂଥ୍ ଅଡିଓ କୋଡେକ୍\nସିଲେକ୍ସନ୍କୁ ଗତିଶୀଳ କରନ୍ତୁ: ନମୁନା ପିଛା ବିଟ୍ସ"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"ବ୍ଲୁଟୂଥ୍ ଅଡିଓ ଚ୍ୟାନେଲ୍ ମୋଡ୍"</string> diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml index 525ad2e9a8fb..042bbf7d3ba3 100644 --- a/packages/SettingsLib/res/values-pa/strings.xml +++ b/packages/SettingsLib/res/values-pa/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"ਬਲੂਟੁੱਥ ਆਡੀਓ ਕੋਡੇਕ\nਚੋਣ ਨੂੰ ਟ੍ਰਿਗਰ ਕਰੋ"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"ਬਲੂਟੁੱਥ ਆਡੀਓ ਸੈਂਪਲ ਰੇਟ"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"ਬਲੂਟੁੱਥ ਆਡੀਓ ਕੋਡੇਕ\nਚੋਣ ਨੂੰ ਟ੍ਰਿਗਰ ਕਰੋ: ਸੈਂਪਲ ਰੇਟ"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"ਅਯੋਗ ਦਾ ਮਤਲਬ ਹੈ ਫ਼ੋਨ ਜਾਂ ਹੈੱਡਸੈੱਟ ਵੱਲੋਂ ਸਮਰਥਿਤ ਨਹੀਂ ਹੈ"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"ਪ੍ਰਤੀ ਸੈਂਪਲ ਬਲੂਟੁੱਥ ਆਡੀਓ ਬਿਟਾਂ"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"ਬਲੂਟੁੱਥ ਆਡੀਓ ਕੋਡੇਕ\nਚੋਣ ਨੂੰ ਟ੍ਰਿਗਰ ਕਰੋ: ਪ੍ਰਤੀ ਸੈਂਪਲ ਬਿਟਾਂ"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"ਬਲੂਟੁੱਥ ਆਡੀਓ ਚੈਨਲ ਮੋਡ"</string> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index 69ebc595f9b6..78566790b3f8 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Uruchom kodek dźwięku Bluetooth\nWybór"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Dźwięk Bluetooth – współczynnik próbkowania"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Uruchom kodek dźwięku Bluetooth\nWybór: częstotliwość próbkowania"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Elementy wyszarzone nie są obsługiwane przez telefon lub zestaw słuchawkowy"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Dźwięk Bluetooth – liczba bitów na próbkę"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Uruchom kodek dźwięku Bluetooth\nWybór: liczba bitów na próbkę"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Dźwięk Bluetooth – tryb kanału"</string> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index 62017f103241..6a3220023e9f 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Acionar codec de áudio Bluetooth\nSeleção"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Taxa de amostra do áudio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Acionar codec de áudio Bluetooth\nSeleção: taxa de amostra"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Os itens esmaecidos não são compatíveis com o smartphone ou o fone de ouvido"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bits por amostra do áudio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Acionar codec de áudio Bluetooth\nSeleção: bits por amostra"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Modo de canal de áudio Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml index 8304768462f6..caf1ba4141e5 100644 --- a/packages/SettingsLib/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Acionar o codec de áudio Bluetooth\nSeleção"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Taxa de amostragem de áudio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Acionar o codec de áudio Bluetooth\nSeleção: frequência de amostragem"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Se estiver assinalado a cinzento, significa que não é suportado pelo telemóvel ou pelos auscultadores com microfone integrado"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bits por amostra de áudio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Acionar o codec de áudio Bluetooth\nSeleção: bits por amostra"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Modo de canal áudio Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index 62017f103241..6a3220023e9f 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Acionar codec de áudio Bluetooth\nSeleção"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Taxa de amostra do áudio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Acionar codec de áudio Bluetooth\nSeleção: taxa de amostra"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Os itens esmaecidos não são compatíveis com o smartphone ou o fone de ouvido"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bits por amostra do áudio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Acionar codec de áudio Bluetooth\nSeleção: bits por amostra"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Modo de canal de áudio Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index 50ea4a00e5cd..38cd60fc7d7d 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Declanșați codecul audio Bluetooth\nSelecție"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Rată de eșantionare audio Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Declanșați codecul audio Bluetooth\nSelecție: rată de eșantionare"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"O opțiune inactivă înseamnă incompatibilitate cu telefonul sau setul căști-microfon"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Biți audio Bluetooth per eșantion"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Declanșați codecul audio Bluetooth\nSelecție: biți per eșantion"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Modul canal audio Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index 0582a0cde4f7..124bf13a5357 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Запустить аудиокодек для Bluetooth\nВыбор"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Частота дискретизации аудио Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Запустить аудиокодек для Bluetooth\nВыбор: частота дискретизации"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Серым окрашены неподдерживаемые функции"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Бит на выборку аудио Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Запустить аудиокодек для Bluetooth\nВыбор: разрядность"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Режим аудиоканала Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml index 43a49781eeca..d5fbb6b6974d 100644 --- a/packages/SettingsLib/res/values-si/strings.xml +++ b/packages/SettingsLib/res/values-si/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"බ්ලූටූත් ශ්රව්ය කෝඩෙක් ක්රියාරම්භ කරන්න\nතෝරා ගැනීම"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"බ්ලූටූත් ශ්රව්ය නියැදි අනුපාතය"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"බ්ලූටූත් ශ්රව්ය කෝඩෙක් ක්රියාරම්භ කරන්න\nතෝරා ගැනීම: නියැදි අනුපාතය"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"අළු පැහැ ගැන්වී ඇත යන්නෙන් අදහස් කරන්නේ දුරකථනය හෝ හෙඩ්සෙට් එක මගින් සහාය නොදක්වන බවයි"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"නියැදියකට බ්ලූටූත් ශ්රව්ය බිටු"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"බ්ලූටූත් ශ්රව්ය කේතය ක්රියාරම්භ කරන්න\nතෝරා ගැනීම: නියැදි සඳහා බිටු"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"බ්ලූටූත් ශ්රව්ය නාලිකා ප්රකාරය"</string> diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml index 3a3958f3a441..ba13586ec3bb 100644 --- a/packages/SettingsLib/res/values-sk/strings.xml +++ b/packages/SettingsLib/res/values-sk/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Spustiť zvukový kodek Bluetooth\nVýber"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth Audio – vzorkovacia frekvencia"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Spustiť zvukový kodek Bluetooth\nVýber: vzorkovacia frekvencia"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Sivé možnosti nie sú podporované telefónom ani náhlavnou súpravou"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth Audio – počet bitov na vzorku"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Spustiť zvukový kodek Bluetooth\nVýber: počet bitov na vzorku"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth Audio – režim kanála"</string> diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml index 068f2214659c..90d7829ae3bb 100644 --- a/packages/SettingsLib/res/values-sl/strings.xml +++ b/packages/SettingsLib/res/values-sl/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Sproži zvočni kodek za Bluetooth\nIzbor"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Hitrost vzorčenja zvoka prek Bluetootha"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Sproži zvočni kodek za Bluetooth\nIzbor: hitrost vzorčenja"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Če je možnost zatemnjena, to pomeni, da je telefon ali slušalke z mikrofonom ne podpirajo"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bitov na vzorec za zvok prek Bluetootha"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Sproži zvočni kodek za Bluetooth\nIzbor: število bitov na vzorec"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Način zvočnega kanala prek Bluetootha"</string> diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml index 54d463775535..15b2ed36fcdb 100644 --- a/packages/SettingsLib/res/values-sq/strings.xml +++ b/packages/SettingsLib/res/values-sq/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Aktivizo kodekun e audios me Bluetooth\nZgjedhja"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Shpejtësia e shembullit të Bluetooth Audio"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Aktivizo kodekun e audios me Bluetooth\nZgjedhja: Shpejtësia e shembullit"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Çaktivizimi do të thotë se nuk mbështetet nga telefoni ose kufjet"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bite për shembull Bluetooth Audio"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Aktivizo kodekun e audios me Bluetooth\nZgjedhja: Bite për shembull"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Regjimi i kanalit Bluetooth Audio"</string> diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml index ab081ae21a9b..381edef5318e 100644 --- a/packages/SettingsLib/res/values-sr/strings.xml +++ b/packages/SettingsLib/res/values-sr/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Изаберите Bluetooth аудио кодек\n"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Брзина узорковања за Bluetooth аудио"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Изаберите Bluetooth аудио кодек:\n брзина узорковања"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Ако је нека ставка засивљена, то значи да је телефон или слушалице не подржавају"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Битова по узорку за Bluetooth аудио"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Изаберите Bluetooth аудио кодек:\n број битова по узорку"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Режим канала за Bluetooth аудио"</string> diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml index cab971f8ae1e..65fbe2036e0e 100644 --- a/packages/SettingsLib/res/values-sv/strings.xml +++ b/packages/SettingsLib/res/values-sv/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Aktivera ljudkodek för Bluetooth\nVal"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Samplingsfrekvens för Bluetooth-ljud"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Aktivera ljudkodek för Bluetooth\nVal: samplingsfrekvens"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"En nedtonad kodek stöds inte av telefonen eller headsetet"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Antar bitar per sampling för Bluetooth-ljud"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Aktivera ljudkodek för Bluetooth\nVal: bitar per sampling"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Kanalläge för Bluetooth-ljud"</string> diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml index df71b826f4b9..e6ccc6580dd7 100644 --- a/packages/SettingsLib/res/values-sw/strings.xml +++ b/packages/SettingsLib/res/values-sw/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Weka Kodeki ya Sauti ya Bluetooth\nUteuzi"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Kiwango cha Sampuli ya Sauti ya Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Weka Kodeki ya Sauti ya Bluetooth\nUteuzi: Kasi ya Sampuli"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Kipengele cha Haiwezi kutumiwa kina maana kuwa hakitumiki kwenye simu au vifaa vya sauti"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Biti za Sauti ya Bluetooth kwa Kila Sampuli"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Weka Kodeki ya Sauti ya Bluetooth\nUteuzi: Biti Kwa Kila Sampuli"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Hali ya Mkondo wa Sauti ya Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml index 084ec16ec05b..f0f4bef97fba 100644 --- a/packages/SettingsLib/res/values-ta/strings.xml +++ b/packages/SettingsLib/res/values-ta/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"புளூடூத் ஆடியோ கோடெக்கைத் தொடங்கு\nதேர்வு"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"புளூடூத் ஆடியோ சாம்பிள் ரேட்"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"புளூடூத் ஆடியோ கோடெக்கைத் தொடங்கு\nதேர்வு: சாம்பிள் ரேட்"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"கிரே-அவுட் என்றால் மொபைலாலோ ஹெட்செட்டாலோ ஆதரிக்கப்படவில்லை என்று அர்த்தம்"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"புளூடூத் ஆடியோ பிட்கள்/சாம்பிள்"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"புளூடூத் ஆடியோ கோடெக்கைத் தொடங்கு\nதேர்வு: பிட்கள் / சாம்பிள்"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"புளூடூத் ஆடியோ சேனல் பயன்முறை"</string> diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml index cbcaf1a8ddfc..cf5097eacc57 100644 --- a/packages/SettingsLib/res/values-te/strings.xml +++ b/packages/SettingsLib/res/values-te/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"బ్లూటూత్ ఆడియో కోడెక్ని సక్రియం చేయండి\nఎంపిక"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"బ్లూటూత్ ఆడియో నమూనా రేట్"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"బ్లూటూత్ ఆడియో కోడెక్ని సక్రియం చేయండి\nఎంపిక: నమూనా రేట్"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"గ్రే-అవుట్ అంటే ఫోన్ లేదా హెడ్సెట్ మద్దతు లేదు అని అర్ధం"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"ఒక్కో నమూనాకు బ్లూటూత్ ఆడియో బిట్లు"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"బ్లూటూత్ ఆడియో కోడెక్ని సక్రియం చేయండి\nఎంపిక: ఒక్కో నమూనాలో బిట్లు"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"బ్లూటూత్ ఆడియో ఛానెల్ మోడ్"</string> diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml index fa8caa17b824..145e1616601d 100644 --- a/packages/SettingsLib/res/values-th/strings.xml +++ b/packages/SettingsLib/res/values-th/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"ทริกเกอร์การเลือกตัวแปลงรหัส\nเสียงบลูทูธ"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"อัตราตัวอย่างเสียงบลูทูธ"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"ทริกเกอร์การเลือกตัวแปลงรหัส\nเสียงบลูทูธ: อัตราตัวอย่าง"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"เป็นสีเทาหมายความว่าโทรศัพท์หรือชุดหูฟังไม่รองรับ"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"บิตต่อตัวอย่างของเสียงบลูทูธ"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"ทริกเกอร์การเลือกตัวแปลงรหัส\nเสียงบลูทูธ: บิตต่อตัวอย่าง"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"โหมดช่องสัญญาณเสียงบลูทูธ"</string> diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml index 21fe58c2db28..e1907732c2e7 100644 --- a/packages/SettingsLib/res/values-tl/strings.xml +++ b/packages/SettingsLib/res/values-tl/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"I-trigger ang Pagpili sa Audio Codec ng\nBluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Sample na Rate ng Bluetooth Audio"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"I-trigger ang Pagpili sa Audio Codec ng\nBluetooth: Rate ng Sample"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Ang ibig sabihin ng na-gray out ay hindi sinusuportahan ng telepono o headset"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bits Per Sample ng Bluetooth Audio"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"I-trigger ang Pagpili sa Audio Codec ng\nBluetooth: Bits Per Sample"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Channel Mode ng Bluetooth Audio"</string> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index 4e7f38dca25b..dc11e80eba31 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Bluetooth Ses Codec\'i Tetikleme\nSeçimi"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth Ses Örnek Hızı"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Bluetooth Ses Codec\'i Tetikleme\nSeçimi: Örnek Hızı"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Devre dışı bırakılmış olması telefon veya mikrofonlu kulaklık tarafından desteklenmediği anlamına gelir."</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth Ses Örnek Başına Bit Sayısı"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Bluetooth Ses Codec\'i Tetikleme\nSeçimi: Örnek Başına Bit Sayısı"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth Ses Kanalı Modu"</string> diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml index 98074173f5c9..f8a88b834a2b 100644 --- a/packages/SettingsLib/res/values-uk/strings.xml +++ b/packages/SettingsLib/res/values-uk/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Активувати кодек для аудіо Bluetooth\nВибір"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Частота вибірки для аудіо Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Активувати кодек для аудіо Bluetooth\nВибір: частота зразка"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Затіненння означає, що телефон або гарнітура не підтримуються"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Кількість бітів на зразок для аудіо Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Активувати кодек для аудіо Bluetooth\nВибір: біти на зразок"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Режим каналу для аудіо Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml index e17b0b05838f..246b6a217f6b 100644 --- a/packages/SettingsLib/res/values-ur/strings.xml +++ b/packages/SettingsLib/res/values-ur/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"بلوٹوتھ آڈیو کوڈیک کو ٹریگر کریں\nانتخاب"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"بلوٹوتھ آڈیو کے نمونے کی شرح"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"بلوٹوتھ آڈیو کوڈیک کو ٹریگر کریں\nانتخاب: نمونے کی شرح"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"گرے آؤٹ کا مطلب ہے فون یا ہیڈ سیٹ کے ذریعہ تعاون یافتہ نہیں"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"بلوٹوتھ آڈیو بٹس فی نمونہ"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"بلوٹوتھ آڈیو کوڈیک کو ٹریگر کریں\nانتخاب: بِٹس فی نمونہ"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"بلوٹوتھ آڈیو چینل موڈ"</string> diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml index ea51eba747a3..87cc2a08337a 100644 --- a/packages/SettingsLib/res/values-uz/strings.xml +++ b/packages/SettingsLib/res/values-uz/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Bluetooth orqali uzatish uchun audiokodek\nTanlash"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Bluetooth audio namunasi chastotasi"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Bluetooth orqali uzatish uchun audiokodek\nTanlash: namuna chastotasi"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Parametr yoqilmasa, garnitura yoki telefonda ishlamaydi"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Bluetooth audio namunasidagi bitlar soni"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Bluetooth orqali uzatish uchun audiokodek\nTanlash: namunadagi bitlar soni"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Bluetooth audio kanali rejimi"</string> diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml index 0b71a8c6243a..0a9726a04aef 100644 --- a/packages/SettingsLib/res/values-vi/strings.xml +++ b/packages/SettingsLib/res/values-vi/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Kích hoạt chế độ chọn codec\nâm thanh Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Tốc độ lấy mẫu âm thanh Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Kích hoạt chế độ chọn codec\nâm thanh Bluetooth: Tần số lấy mẫu"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Trạng thái chuyển sang màu xám có nghĩa là điện thoại hoặc tai nghe không hỗ trợ"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Số bit âm thanh Bluetooth mỗi mẫu"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Kích hoạt chế độ chọn codec\nâm thanh Bluetooth: Số bit trên mỗi mẫu"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Chế độ kênh âm thanh Bluetooth"</string> diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml index 1805694c3b1f..514e67731922 100644 --- a/packages/SettingsLib/res/values-zh-rCN/strings.xml +++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"触发蓝牙音频编解码器\n选择"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"蓝牙音频采样率"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"触发蓝牙音频编解码器\n选择:采样率"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"灰显意味着手机或耳机不支持该功能"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"蓝牙音频每样本位数"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"触发蓝牙音频编解码器\n选择:每样本位数"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"蓝牙音频声道模式"</string> diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml index 1d217b500cc9..261e8d02e5c0 100644 --- a/packages/SettingsLib/res/values-zh-rHK/strings.xml +++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"觸發藍牙音訊編解碼器\n選項"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"藍牙音訊取樣率"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"觸發藍牙音訊編解碼器\n選項:取樣率"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"以灰色顯示代表手機或耳機不支援此音訊編解碼器"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"藍牙音訊每個樣本位元數"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"觸發藍牙音訊編解碼器\n選項:每個樣本位元數"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"藍牙音訊聲道模式"</string> diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml index ee6866505bdb..d0ba3d03d713 100644 --- a/packages/SettingsLib/res/values-zh-rTW/strings.xml +++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"觸發藍牙音訊轉碼器\n選項"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"藍牙音訊取樣率"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"觸發藍牙音訊轉碼器\n選項:取樣率"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"如果顯示為灰色,表示手機或耳機不支援這項功能"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"藍牙音訊每單位樣本位元數"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"觸發藍牙音訊轉碼器\n選項:每單位樣本位元數"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"藍牙音訊聲道模式"</string> diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml index 820aa772e7e6..f8cc50bc8335 100644 --- a/packages/SettingsLib/res/values-zu/strings.xml +++ b/packages/SettingsLib/res/values-zu/strings.xml @@ -233,6 +233,7 @@ <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Qalisa i-codec ye-bluetooth yomsindo\nUkukhethwa"</string> <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Isilinganiso sesampula yomsindo we-Bluetooth"</string> <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Qalisa i-codec ye-bluetooth yomsindo\nUkukhethwa: Isampuli yesilinganiso"</string> + <string name="bluetooth_select_a2dp_codec_type_help_info" msgid="8647200416514412338">"Okwenziwa mpunga ngokuphelele kusho ukuthi akusekelwe ifoni noma ihedisethi"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="6253965294594390806">"Ama-Bits omsindo we-Bluetooth ngesampula ngayinye"</string> <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="4898693684282596143">"Qalisa i-codec ye-bluetooth yomsindo\nUkukhethwa: Amabhithi ngesampuli ngayinye"</string> <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="364277285688014427">"Imodi yesiteshi somsindo we-Bluetooth"</string> diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index 0095692336e7..833c4ac07633 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -241,9 +241,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> public void disconnect() { synchronized (mProfileLock) { - for (LocalBluetoothProfile profile : mProfiles) { - disconnect(profile); - } + mLocalAdapter.disconnectAllEnabledProfiles(mDevice); } // Disconnect PBAP server in case its connected // This is to ensure all the profiles are disconnected as some CK/Hs do not diff --git a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java index 69487d508443..274696bfec0e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawable/UserIconDrawable.java @@ -39,7 +39,6 @@ import android.graphics.Shader; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.UserHandle; -import android.os.UserManager; import com.android.settingslib.R; @@ -177,8 +176,8 @@ public class UserIconDrawable extends Drawable implements Drawable.Callback { boolean isManaged = context.getSystemService(DevicePolicyManager.class) .getProfileOwnerAsUser(userId) != null; if (isManaged) { - badge = getDrawableForDisplayDensity(context, - context.getSystemService(UserManager.class).getUserBadgeResId(userId)); + badge = getDrawableForDisplayDensity( + context, com.android.internal.R.drawable.ic_corp_badge_case); } } return setBadge(badge); diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index d619300f2492..f2af40e3d93f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -748,7 +748,20 @@ public class AccessPoint implements Comparable<AccessPoint> { || (mConfig != null && mConfig.shared != config.shared)) { return false; } - return security == getSecurity(config); + + final int configSecurity = getSecurity(config); + final WifiManager wifiManager = getWifiManager(); + switch (security) { + case SECURITY_PSK_SAE_TRANSITION: + return configSecurity == SECURITY_PSK + || (wifiManager.isWpa3SaeSupported() && configSecurity == SECURITY_SAE); + case SECURITY_OWE_TRANSITION: + return configSecurity == SECURITY_NONE + || (wifiManager.isEnhancedOpenSupported() + && configSecurity == SECURITY_OWE); + default: + return security == configSecurity; + } } public WifiConfiguration getConfig() { @@ -1085,16 +1098,12 @@ public class AccessPoint implements Comparable<AccessPoint> { summary.append(mContext.getString(R.string.wifi_check_password_try_again)); break; case WifiConfiguration.NetworkSelectionStatus.DISABLED_DHCP_FAILURE: - case WifiConfiguration.NetworkSelectionStatus.DISABLED_DNS_FAILURE: summary.append(mContext.getString(R.string.wifi_disabled_network_failure)); break; case WifiConfiguration.NetworkSelectionStatus.DISABLED_ASSOCIATION_REJECTION: summary.append(mContext.getString(R.string.wifi_disabled_generic)); break; } - } else if (mConfig != null && mConfig.getNetworkSelectionStatus().isNotRecommended()) { - summary.append(mContext.getString( - R.string.wifi_disabled_by_recommendation_provider)); } else if (mIsCarrierAp) { summary.append(String.format(mContext.getString( R.string.available_via_carrier), mCarrierName)); @@ -1321,10 +1330,34 @@ public class AccessPoint implements Comparable<AccessPoint> { mAccessPointListener = listener; } + private static final String sPskSuffix = "," + String.valueOf(SECURITY_PSK); + private static final String sSaeSuffix = "," + String.valueOf(SECURITY_SAE); + private static final String sPskSaeSuffix = "," + String.valueOf(SECURITY_PSK_SAE_TRANSITION); + private static final String sOweSuffix = "," + String.valueOf(SECURITY_OWE); + private static final String sOpenSuffix = "," + String.valueOf(SECURITY_NONE); + private static final String sOweTransSuffix = "," + String.valueOf(SECURITY_OWE_TRANSITION); + private boolean isKeyEqual(String compareTo) { if (mKey == null) { return false; } + + if (compareTo.endsWith(sPskSuffix) || compareTo.endsWith(sSaeSuffix)) { + if (mKey.endsWith(sPskSaeSuffix)) { + // Special handling for PSK-SAE transition mode. If the AP has advertised both, + // we compare the key with both PSK and SAE for a match. + return TextUtils.equals(mKey.substring(0, mKey.lastIndexOf(',')), + compareTo.substring(0, compareTo.lastIndexOf(','))); + } + } + if (compareTo.endsWith(sOpenSuffix) || compareTo.endsWith(sOweSuffix)) { + if (mKey.endsWith(sOweTransSuffix)) { + // Special handling for OWE/Open networks. If AP advertises OWE in transition mode + // and we have an Open network saved, allow this connection to be established. + return TextUtils.equals(mKey.substring(0, mKey.lastIndexOf(',')), + compareTo.substring(0, compareTo.lastIndexOf(','))); + } + } return mKey.equals(compareTo); } @@ -1661,6 +1694,8 @@ public class AccessPoint implements Comparable<AccessPoint> { private static int getSecurity(ScanResult result) { if (result.capabilities.contains("WEP")) { return SECURITY_WEP; + } else if (result.capabilities.contains("PSK+SAE")) { + return SECURITY_PSK_SAE_TRANSITION; } else if (result.capabilities.contains("SAE")) { return SECURITY_SAE; } else if (result.capabilities.contains("PSK")) { @@ -1669,6 +1704,8 @@ public class AccessPoint implements Comparable<AccessPoint> { return SECURITY_EAP_SUITE_B; } else if (result.capabilities.contains("EAP")) { return SECURITY_EAP; + } else if (result.capabilities.contains("OWE_TRANSITION")) { + return SECURITY_OWE_TRANSITION; } else if (result.capabilities.contains("OWE")) { return SECURITY_OWE; } @@ -1715,6 +1752,10 @@ public class AccessPoint implements Comparable<AccessPoint> { return "SUITE_B"; } else if (security == SECURITY_OWE) { return "OWE"; + } else if (security == SECURITY_PSK_SAE_TRANSITION) { + return "PSK+SAE"; + } else if (security == SECURITY_OWE_TRANSITION) { + return "OWE_TRANSITION"; } return "NONE"; } @@ -1892,16 +1933,4 @@ public class AccessPoint implements Comparable<AccessPoint> { } } } - - /** - * Lets the caller know if the network was cloned from another network - * - * @return true if the network is cloned - */ - public boolean isCloned() { - if (mConfig == null) { - return false; - } - return mConfig.clonedNetworkConfigKey != null; - } } diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java index 51e37d1e0771..8591116fce0f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java @@ -142,7 +142,7 @@ public class WifiStatusTracker extends ConnectivityManager.NetworkCallback { private void updateRssi(int newRssi) { rssi = newRssi; - level = WifiManager.calculateSignalLevel(rssi, WifiManager.RSSI_LEVELS); + level = mWifiManager.calculateSignalLevel(rssi); } private void maybeRequestNetworkScore() { diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java index 97fddc0e3e79..23754c5c73f9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java @@ -518,8 +518,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro int networkId, final List<WifiConfiguration> configs) { if (configs != null) { for (WifiConfiguration config : configs) { - if (mLastInfo != null && networkId == config.networkId && - !(config.selfAdded && config.numAssociation == 0)) { + if (mLastInfo != null && networkId == config.networkId) { return config; } } diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java index ee8973841c73..b93b0001f5de 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java @@ -30,6 +30,8 @@ import java.util.Map; public class WifiUtils { + private static final int INVALID_RSSI = -127; + public static String buildLoggingSummary(AccessPoint accessPoint, WifiConfiguration config) { final StringBuilder summary = new StringBuilder(); final WifiInfo info = accessPoint.getInfo(); @@ -106,8 +108,8 @@ public class WifiUtils { visibility.append(String.format("rx=%.1f", info.getRxSuccessRate())); } - int maxRssi5 = WifiConfiguration.INVALID_RSSI; - int maxRssi24 = WifiConfiguration.INVALID_RSSI; + int maxRssi5 = INVALID_RSSI; + int maxRssi24 = INVALID_RSSI; final int maxDisplayedScans = 4; int num5 = 0; // number of scanned BSSID on 5GHz band int num24 = 0; // number of scanned BSSID on 2.4Ghz band diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java index 7139a4f2282e..7d06e6cc5735 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java @@ -459,10 +459,11 @@ public class AccessPointTest { @Test public void testSummaryString_showsWrongPasswordLabel() { - WifiConfiguration configuration = createWifiConfiguration(); - configuration.getNetworkSelectionStatus().setNetworkSelectionStatus( - WifiConfiguration.NetworkSelectionStatus.NETWORK_SELECTION_PERMANENTLY_DISABLED); - configuration.getNetworkSelectionStatus().setNetworkSelectionDisableReason( + WifiConfiguration configuration = spy(createWifiConfiguration()); + WifiConfiguration.NetworkSelectionStatus status = + mock(WifiConfiguration.NetworkSelectionStatus.class); + when(configuration.getNetworkSelectionStatus()).thenReturn(status); + when(status.getNetworkSelectionDisableReason()).thenReturn( WifiConfiguration.NetworkSelectionStatus.DISABLED_BY_WRONG_PASSWORD); AccessPoint ap = new AccessPoint(mContext, configuration); diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java index 37fdc340ab80..94fbc542c3e4 100644 --- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java @@ -494,7 +494,6 @@ public class WifiTrackerTest { WifiConfiguration selfAddedNoAssociation = new WifiConfiguration(); selfAddedNoAssociation.ephemeral = true; - selfAddedNoAssociation.selfAdded = true; selfAddedNoAssociation.numAssociation = 0; selfAddedNoAssociation.SSID = SSID_2; selfAddedNoAssociation.BSSID = BSSID_2; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/MasterSwitchControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/MasterSwitchControllerTest.java new file mode 100644 index 000000000000..69d0f2e71c17 --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/MasterSwitchControllerTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2019 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.settingslib.drawer; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class MasterSwitchControllerTest { + + @Rule + public final ExpectedException thrown = ExpectedException.none(); + + private MasterSwitchController mController; + + @Before + public void setUp() { + mController = new TestMasterSwitchController("123"); + } + + @Test + public void getMetaData_shouldThrowUnsupportedOperationException() { + thrown.expect(UnsupportedOperationException.class); + + mController.getMetaData(); + } + + @Test + public void getBundle_shouldThrowUnsupportedOperationException() { + thrown.expect(UnsupportedOperationException.class); + + mController.getBundle(); + } + + static class TestMasterSwitchController extends MasterSwitchController { + + private String mKey; + + TestMasterSwitchController(String key) { + mKey = key; + } + + @Override + public String getSwitchKey() { + return mKey; + } + + @Override + protected boolean isChecked() { + return true; + } + + @Override + protected boolean onCheckedChanged(boolean checked) { + return true; + } + + @Override + protected String getErrorMessage(boolean attemptedChecked) { + return null; + } + } +} diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java index 27b3697f54ea..a740e683642a 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java @@ -35,6 +35,7 @@ import android.content.Context; import android.content.pm.ProviderInfo; import android.os.Bundle; +import com.android.settingslib.drawer.MasterSwitchControllerTest.TestMasterSwitchController; import com.android.settingslib.drawer.SwitchController.MetaData; import org.junit.Before; @@ -84,8 +85,8 @@ public class SwitchesProviderTest { } @Test - public void attachInfo_NoMetaDataInController_shouldThrowIllegalArgumentException() { - thrown.expect(IllegalArgumentException.class); + public void attachInfo_NoMetaDataInController_shouldThrowNullPointerException() { + thrown.expect(NullPointerException.class); final TestSwitchController controller = new TestSwitchController(); controller.setKey("123"); mSwitchesProvider.addSwitchController(controller); @@ -123,6 +124,19 @@ public class SwitchesProviderTest { } @Test + public void getSwitchData_shouldNotReturnMasterSwitchData() { + final SwitchController controller = new TestMasterSwitchController("123"); + mSwitchesProvider.addSwitchController(controller); + mSwitchesProvider.attachInfo(mContext, mProviderInfo); + + final Bundle switchData = mSwitchesProvider.call(METHOD_GET_SWITCH_DATA, "uri" , + null /* extras*/); + + final ArrayList<Bundle> dataList = switchData.getParcelableArrayList(EXTRA_SWITCH_DATA); + assertThat(dataList).isEmpty(); + } + + @Test public void getSwitchData_shouldReturnDataList() { final TestSwitchController controller = new TestSwitchController(); controller.setKey("123"); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java index b36eb4950b11..9b4b97e7f55d 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/TileUtilsTest.java @@ -113,7 +113,7 @@ public class TileUtilsTest { when(mPackageManager.queryIntentContentProvidersAsUser(any(Intent.class), anyInt(), anyInt())).thenReturn(info); - TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, + TileUtils.loadTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */); assertThat(outTiles).hasSize(2); @@ -135,7 +135,7 @@ public class TileUtilsTest { when(mPackageManager.queryIntentContentProvidersAsUser(any(Intent.class), anyInt(), anyInt())).thenReturn(info); - TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, + TileUtils.loadTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, null /* defaultCategory */, outTiles, false /* requiresSettings */); assertThat(outTiles).hasSize(2); @@ -156,7 +156,7 @@ public class TileUtilsTest { when(mPackageManager.queryIntentContentProvidersAsUser(any(Intent.class), anyInt(), anyInt())).thenReturn(info); - TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, + TileUtils.loadTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, null /* defaultCategory */, outTiles, false /* requiresSettings */); assertThat(outTiles).isEmpty(); @@ -197,7 +197,7 @@ public class TileUtilsTest { when(mPackageManager.queryIntentContentProvidersAsUser(any(Intent.class), anyInt(), anyInt())).thenReturn(info); - TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, + TileUtils.loadTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */); assertThat(outTiles).hasSize(2); @@ -222,7 +222,7 @@ public class TileUtilsTest { when(mResources.getString(eq(123))) .thenReturn("my localized title"); - TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, + TileUtils.loadTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */); assertThat(outTiles).hasSize(2); assertThat(outTiles.get(0).getTitle(mContext)).isEqualTo("my localized title"); @@ -245,7 +245,7 @@ public class TileUtilsTest { when(mPackageManager.queryIntentContentProvidersAsUser(any(Intent.class), anyInt(), anyInt())).thenReturn(info); - TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, + TileUtils.loadTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */); assertThat(outTiles.get(0).isIconTintable(mContext)).isFalse(); @@ -266,7 +266,7 @@ public class TileUtilsTest { when(mPackageManager.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt())) .thenReturn(info); - TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, + TileUtils.loadTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */); assertThat(outTiles).hasSize(1); @@ -276,7 +276,7 @@ public class TileUtilsTest { resolveInfo.activityInfo.metaData.putInt(META_DATA_PREFERENCE_ICON, com.android.internal.R.drawable.ic_phone); outTiles.clear(); - TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, + TileUtils.loadTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */); assertThat(outTiles).hasSize(1); @@ -300,7 +300,7 @@ public class TileUtilsTest { when(mPackageManager.queryIntentContentProvidersAsUser(any(Intent.class), anyInt(), anyInt())).thenReturn(info); - TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, + TileUtils.loadTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */); assertThat(outTiles.get(0).isIconTintable(mContext)).isTrue(); @@ -321,7 +321,7 @@ public class TileUtilsTest { when(mPackageManager.queryIntentContentProvidersAsUser(any(Intent.class), anyInt(), anyInt())).thenReturn(info); - TileUtils.getTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, + TileUtils.loadTilesForAction(mContext, UserHandle.CURRENT, IA_SETTINGS_ACTION, addedCache, null /* defaultCategory */, outTiles, false /* usePriority */); assertThat(outTiles).hasSize(2); diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp index 681b4940a3c3..f40d3a160513 100644 --- a/packages/SettingsProvider/Android.bp +++ b/packages/SettingsProvider/Android.bp @@ -29,6 +29,7 @@ android_test { "src/com/android/providers/settings/SettingsBackupAgent.java", "src/com/android/providers/settings/SettingsState.java", "src/com/android/providers/settings/SettingsHelper.java", + "src/com/android/providers/settings/WifiSoftApBandChangedNotifier.java", ], static_libs: [ "androidx.test.rules", diff --git a/packages/SettingsProvider/res/drawable/ic_wifi_settings.xml b/packages/SettingsProvider/res/drawable/ic_wifi_settings.xml new file mode 100644 index 000000000000..cb426565ae82 --- /dev/null +++ b/packages/SettingsProvider/res/drawable/ic_wifi_settings.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2019 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + + <path + android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" /> + <path + android:fillColor="#000000" + android:pathData="M12.584,15.93c0.026-0.194,0.044-0.397,0.044-0.608c0-0.211-0.018-0.405-0.044-0.608l1.304-1.022 +c0.115-0.088,0.15-0.256,0.071-0.397l-1.234-2.133c-0.071-0.132-0.238-0.185-0.379-0.132l-1.533,0.617 +c-0.317-0.247-0.67-0.449-1.04-0.608L9.535,9.4c-0.018-0.132-0.141-0.247-0.3-0.247H6.768c-0.15,0-0.282,0.115-0.3,0.256 +L6.23,11.048c-0.379,0.159-0.723,0.361-1.04,0.608l-1.533-0.617c-0.141-0.053-0.3,0-0.379,0.132l-1.234,2.133 +c-0.079,0.132-0.044,0.3,0.07,0.397l1.304,1.022c-0.026,0.194-0.044,0.405-0.044,0.608s0.018,0.405,0.044,0.608l-1.304,1.022 +c-0.115,0.088-0.15,0.256-0.07,0.397l1.234,2.133c0.07,0.132,0.238,0.185,0.379,0.132l1.533-0.617 +c0.317,0.247,0.67,0.449,1.04,0.608l0.238,1.639c0.018,0.15,0.15,0.256,0.3,0.256h2.467c0.159,0,0.282-0.115,0.3-0.256 +l0.238-1.639c0.379-0.15,0.723-0.361,1.04-0.608l1.533,0.617c0.141,0.053,0.3,0,0.379-0.132l1.234-2.133 +c0.071-0.132,0.044-0.3-0.07-0.397L12.584,15.93z +M8.002,17.481c-1.19,0-2.159-0.969-2.159-2.159s0.969-2.159,2.159-2.159 +s2.159,0.969,2.159,2.159C10.161,16.512,9.191,17.481,8.002,17.481z" /> + <path + android:fillColor="#000000" + android:pathData="M16.003,12.026l5.995-7.474c-0.229-0.172-2.537-2.06-6-2.06s-5.771,1.889-6,2.06l5.995,7.469l0.005,0.01L16.003,12.026z" /> +</vector> diff --git a/packages/SettingsProvider/res/values-af/strings.xml b/packages/SettingsProvider/res/values-af/strings.xml index 79a7f2d86b74..2c454843e4d2 100644 --- a/packages/SettingsProvider/res/values-af/strings.xml +++ b/packages/SettingsProvider/res/values-af/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Instellingsberging"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-am/strings.xml b/packages/SettingsProvider/res/values-am/strings.xml index 6380b999e9f3..0630560e3e46 100644 --- a/packages/SettingsProvider/res/values-am/strings.xml +++ b/packages/SettingsProvider/res/values-am/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"የቅንብሮች ማከማቻ"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-ar/strings.xml b/packages/SettingsProvider/res/values-ar/strings.xml index ab1b808d312a..19306a604f40 100644 --- a/packages/SettingsProvider/res/values-ar/strings.xml +++ b/packages/SettingsProvider/res/values-ar/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"تخزين الإعدادات"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-as/strings.xml b/packages/SettingsProvider/res/values-as/strings.xml index 233253e539bd..13b90d699664 100644 --- a/packages/SettingsProvider/res/values-as/strings.xml +++ b/packages/SettingsProvider/res/values-as/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"ছেটিংছসমূহৰ সঞ্চয়াগাৰ"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-az/strings.xml b/packages/SettingsProvider/res/values-az/strings.xml index e99e99bc82ef..4737a1ee9323 100644 --- a/packages/SettingsProvider/res/values-az/strings.xml +++ b/packages/SettingsProvider/res/values-az/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Ayarlar Deposu"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-b+sr+Latn/strings.xml b/packages/SettingsProvider/res/values-b+sr+Latn/strings.xml index 337b18ef2f4a..032dbc577f73 100644 --- a/packages/SettingsProvider/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsProvider/res/values-b+sr+Latn/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Podešavanja skladišta"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-be/strings.xml b/packages/SettingsProvider/res/values-be/strings.xml index 3a8557ce9a32..60bdb2daa4a3 100644 --- a/packages/SettingsProvider/res/values-be/strings.xml +++ b/packages/SettingsProvider/res/values-be/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Сховішча налад"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-bg/strings.xml b/packages/SettingsProvider/res/values-bg/strings.xml index f3d21d82c700..c3a994b24252 100644 --- a/packages/SettingsProvider/res/values-bg/strings.xml +++ b/packages/SettingsProvider/res/values-bg/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Настройки за хранилище"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-bn/strings.xml b/packages/SettingsProvider/res/values-bn/strings.xml index 7e72dfb9a968..71ee99b9b06e 100644 --- a/packages/SettingsProvider/res/values-bn/strings.xml +++ b/packages/SettingsProvider/res/values-bn/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"সেটিংস স্টোরেজ"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-bs/strings.xml b/packages/SettingsProvider/res/values-bs/strings.xml index 464a29f17ad2..09d4c68ae541 100644 --- a/packages/SettingsProvider/res/values-bs/strings.xml +++ b/packages/SettingsProvider/res/values-bs/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Postavke za pohranu podataka"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-ca/strings.xml b/packages/SettingsProvider/res/values-ca/strings.xml index 9d6ac7ae4e6d..ee6b51e39dd0 100644 --- a/packages/SettingsProvider/res/values-ca/strings.xml +++ b/packages/SettingsProvider/res/values-ca/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Configuració de l\'emmagatzematge"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-cs/strings.xml b/packages/SettingsProvider/res/values-cs/strings.xml index a28ffa1e27a3..f134e0559667 100644 --- a/packages/SettingsProvider/res/values-cs/strings.xml +++ b/packages/SettingsProvider/res/values-cs/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Paměť pro nastavení"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-da/strings.xml b/packages/SettingsProvider/res/values-da/strings.xml index ed450d57e4e8..99988a58a041 100644 --- a/packages/SettingsProvider/res/values-da/strings.xml +++ b/packages/SettingsProvider/res/values-da/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Lagring af indstillinger"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-de/strings.xml b/packages/SettingsProvider/res/values-de/strings.xml index 6effbaee2196..ddcabaa23e3c 100644 --- a/packages/SettingsProvider/res/values-de/strings.xml +++ b/packages/SettingsProvider/res/values-de/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Einstellungsspeicher"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-el/strings.xml b/packages/SettingsProvider/res/values-el/strings.xml index 5bd1fa6af8e6..924fab5fb80b 100644 --- a/packages/SettingsProvider/res/values-el/strings.xml +++ b/packages/SettingsProvider/res/values-el/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Αποθηκευτικός χώρος ρυθμίσεων"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-en-rAU/strings.xml b/packages/SettingsProvider/res/values-en-rAU/strings.xml index c19fdd7aed7f..05cd54e7cee7 100644 --- a/packages/SettingsProvider/res/values-en-rAU/strings.xml +++ b/packages/SettingsProvider/res/values-en-rAU/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Settings Storage"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-en-rCA/strings.xml b/packages/SettingsProvider/res/values-en-rCA/strings.xml index c19fdd7aed7f..05cd54e7cee7 100644 --- a/packages/SettingsProvider/res/values-en-rCA/strings.xml +++ b/packages/SettingsProvider/res/values-en-rCA/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Settings Storage"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-en-rGB/strings.xml b/packages/SettingsProvider/res/values-en-rGB/strings.xml index c19fdd7aed7f..05cd54e7cee7 100644 --- a/packages/SettingsProvider/res/values-en-rGB/strings.xml +++ b/packages/SettingsProvider/res/values-en-rGB/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Settings Storage"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-en-rIN/strings.xml b/packages/SettingsProvider/res/values-en-rIN/strings.xml index c19fdd7aed7f..05cd54e7cee7 100644 --- a/packages/SettingsProvider/res/values-en-rIN/strings.xml +++ b/packages/SettingsProvider/res/values-en-rIN/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Settings Storage"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-en-rXC/strings.xml b/packages/SettingsProvider/res/values-en-rXC/strings.xml index 9b18e2b4028a..fbc348b5be84 100644 --- a/packages/SettingsProvider/res/values-en-rXC/strings.xml +++ b/packages/SettingsProvider/res/values-en-rXC/strings.xml @@ -20,4 +20,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Settings Storage"</string> + <string name="wifi_softap_config_change" msgid="5338670993556993667">"Changes to your hotspot settings"</string> + <string name="wifi_softap_config_change_summary" msgid="7600005249167787750">"Your hotspot band has changed."</string> + <string name="wifi_softap_config_change_detailed" msgid="2504664754843959730">"This device doesn’t support your preference for 5GHz only. Instead, this device will use the 5GHz band when available."</string> </resources> diff --git a/packages/SettingsProvider/res/values-es-rUS/strings.xml b/packages/SettingsProvider/res/values-es-rUS/strings.xml index 7a15d8bda8e1..d5e6da9affc0 100644 --- a/packages/SettingsProvider/res/values-es-rUS/strings.xml +++ b/packages/SettingsProvider/res/values-es-rUS/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Almacenamiento de configuración"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-es/strings.xml b/packages/SettingsProvider/res/values-es/strings.xml index 7a15d8bda8e1..d5e6da9affc0 100644 --- a/packages/SettingsProvider/res/values-es/strings.xml +++ b/packages/SettingsProvider/res/values-es/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Almacenamiento de configuración"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-et/strings.xml b/packages/SettingsProvider/res/values-et/strings.xml index 30b729365f15..a3e4db6c8898 100644 --- a/packages/SettingsProvider/res/values-et/strings.xml +++ b/packages/SettingsProvider/res/values-et/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Seadete talletusruum"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-eu/strings.xml b/packages/SettingsProvider/res/values-eu/strings.xml index 6780ae0f663c..8d410de1eb3c 100644 --- a/packages/SettingsProvider/res/values-eu/strings.xml +++ b/packages/SettingsProvider/res/values-eu/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Ezarpenen biltegia"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-fa/strings.xml b/packages/SettingsProvider/res/values-fa/strings.xml index 97fe0ab542cd..ed9d168bc54b 100644 --- a/packages/SettingsProvider/res/values-fa/strings.xml +++ b/packages/SettingsProvider/res/values-fa/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"تنظیم محل ذخیره"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-fi/strings.xml b/packages/SettingsProvider/res/values-fi/strings.xml index 83c7f66b7374..9ff2c41936d3 100644 --- a/packages/SettingsProvider/res/values-fi/strings.xml +++ b/packages/SettingsProvider/res/values-fi/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Asetuksien tallennus"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-fr-rCA/strings.xml b/packages/SettingsProvider/res/values-fr-rCA/strings.xml index c90eb0957e52..fdfdb1d01b2f 100644 --- a/packages/SettingsProvider/res/values-fr-rCA/strings.xml +++ b/packages/SettingsProvider/res/values-fr-rCA/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Stockage des paramètres"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-fr/strings.xml b/packages/SettingsProvider/res/values-fr/strings.xml index c90eb0957e52..fdfdb1d01b2f 100644 --- a/packages/SettingsProvider/res/values-fr/strings.xml +++ b/packages/SettingsProvider/res/values-fr/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Stockage des paramètres"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-gl/strings.xml b/packages/SettingsProvider/res/values-gl/strings.xml index 80ef3102ad62..7b1599e0e8cd 100644 --- a/packages/SettingsProvider/res/values-gl/strings.xml +++ b/packages/SettingsProvider/res/values-gl/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Almacenamento da configuración"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-gu/strings.xml b/packages/SettingsProvider/res/values-gu/strings.xml index 72419749c36a..00246f98ad52 100644 --- a/packages/SettingsProvider/res/values-gu/strings.xml +++ b/packages/SettingsProvider/res/values-gu/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"સેટિંગ્સ સંગ્રહ"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-hi/strings.xml b/packages/SettingsProvider/res/values-hi/strings.xml index da8193fa55b9..35ed78fba729 100644 --- a/packages/SettingsProvider/res/values-hi/strings.xml +++ b/packages/SettingsProvider/res/values-hi/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"सेटिंग मेमोरी"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-hr/strings.xml b/packages/SettingsProvider/res/values-hr/strings.xml index 87f1270bb139..070d0619f07d 100644 --- a/packages/SettingsProvider/res/values-hr/strings.xml +++ b/packages/SettingsProvider/res/values-hr/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Postavke pohrane"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-hu/strings.xml b/packages/SettingsProvider/res/values-hu/strings.xml index dab1b17758b0..97124ae390af 100644 --- a/packages/SettingsProvider/res/values-hu/strings.xml +++ b/packages/SettingsProvider/res/values-hu/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Beállítástároló"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-hy/strings.xml b/packages/SettingsProvider/res/values-hy/strings.xml index b1f1afbaf664..d4940124f20f 100644 --- a/packages/SettingsProvider/res/values-hy/strings.xml +++ b/packages/SettingsProvider/res/values-hy/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Կարգավորումների պահուստ"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-in/strings.xml b/packages/SettingsProvider/res/values-in/strings.xml index bed20eb8a327..4ec8f8464969 100644 --- a/packages/SettingsProvider/res/values-in/strings.xml +++ b/packages/SettingsProvider/res/values-in/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Setelan Penyimpanan"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-is/strings.xml b/packages/SettingsProvider/res/values-is/strings.xml index c4e2aa689702..d75abae3849c 100644 --- a/packages/SettingsProvider/res/values-is/strings.xml +++ b/packages/SettingsProvider/res/values-is/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Stillingageymsla"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-it/strings.xml b/packages/SettingsProvider/res/values-it/strings.xml index ba1431d821fa..a1e3901f1f7a 100644 --- a/packages/SettingsProvider/res/values-it/strings.xml +++ b/packages/SettingsProvider/res/values-it/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Memoria impostazioni"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-iw/strings.xml b/packages/SettingsProvider/res/values-iw/strings.xml index ad2eaf4a2215..c14f776d26c4 100644 --- a/packages/SettingsProvider/res/values-iw/strings.xml +++ b/packages/SettingsProvider/res/values-iw/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"אחסון הגדרות"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-ja/strings.xml b/packages/SettingsProvider/res/values-ja/strings.xml index d222ca93a0db..b11ec3b14d82 100644 --- a/packages/SettingsProvider/res/values-ja/strings.xml +++ b/packages/SettingsProvider/res/values-ja/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"ストレージの設定"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-ka/strings.xml b/packages/SettingsProvider/res/values-ka/strings.xml index 691a2e966b1a..d08e71ea592b 100644 --- a/packages/SettingsProvider/res/values-ka/strings.xml +++ b/packages/SettingsProvider/res/values-ka/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"პარამეტრების საცავი"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-kk/strings.xml b/packages/SettingsProvider/res/values-kk/strings.xml index 8cf8af2b2894..c07264cb6f11 100644 --- a/packages/SettingsProvider/res/values-kk/strings.xml +++ b/packages/SettingsProvider/res/values-kk/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Параметрлер жады"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-km/strings.xml b/packages/SettingsProvider/res/values-km/strings.xml index 7be624279c50..c880ead34f7d 100644 --- a/packages/SettingsProvider/res/values-km/strings.xml +++ b/packages/SettingsProvider/res/values-km/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"កំណត់ការផ្ទុក"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-kn/strings.xml b/packages/SettingsProvider/res/values-kn/strings.xml index ca427ec75038..d82332364c74 100644 --- a/packages/SettingsProvider/res/values-kn/strings.xml +++ b/packages/SettingsProvider/res/values-kn/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"ಸೆಟ್ಟಿಂಗ್ಗಳ ಸಂಗ್ರಹಣೆ"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-ko/strings.xml b/packages/SettingsProvider/res/values-ko/strings.xml index 8e0cc75de7e0..ab8fb2be95cd 100644 --- a/packages/SettingsProvider/res/values-ko/strings.xml +++ b/packages/SettingsProvider/res/values-ko/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"설정 저장소"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-ky/strings.xml b/packages/SettingsProvider/res/values-ky/strings.xml index 2b3cf616658b..566c48139506 100644 --- a/packages/SettingsProvider/res/values-ky/strings.xml +++ b/packages/SettingsProvider/res/values-ky/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Жөндөөлөрдү сактоо"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-lo/strings.xml b/packages/SettingsProvider/res/values-lo/strings.xml index 4e5793661740..1aa5fe9a330a 100644 --- a/packages/SettingsProvider/res/values-lo/strings.xml +++ b/packages/SettingsProvider/res/values-lo/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"ບ່ອນເກັບຂໍ້ມູນການຕັ້ງຄ່າ"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-lt/strings.xml b/packages/SettingsProvider/res/values-lt/strings.xml index 5b4432ff5f31..47cd6b4e6838 100644 --- a/packages/SettingsProvider/res/values-lt/strings.xml +++ b/packages/SettingsProvider/res/values-lt/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Nustatymų saugykla"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-lv/strings.xml b/packages/SettingsProvider/res/values-lv/strings.xml index c83580c7026e..d221d468c42c 100644 --- a/packages/SettingsProvider/res/values-lv/strings.xml +++ b/packages/SettingsProvider/res/values-lv/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Iestatījumu krātuve"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-mk/strings.xml b/packages/SettingsProvider/res/values-mk/strings.xml index f281baea384d..dc74c4aa732c 100644 --- a/packages/SettingsProvider/res/values-mk/strings.xml +++ b/packages/SettingsProvider/res/values-mk/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Поставки за меморија"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-ml/strings.xml b/packages/SettingsProvider/res/values-ml/strings.xml index 43a88e1dd5a9..a11e23604436 100644 --- a/packages/SettingsProvider/res/values-ml/strings.xml +++ b/packages/SettingsProvider/res/values-ml/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"സംഭരണ ക്രമീകരണം"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-mn/strings.xml b/packages/SettingsProvider/res/values-mn/strings.xml index 94521451bcee..f6437c7591f3 100644 --- a/packages/SettingsProvider/res/values-mn/strings.xml +++ b/packages/SettingsProvider/res/values-mn/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Тохиргооны Сан"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-mr/strings.xml b/packages/SettingsProvider/res/values-mr/strings.xml index 65a876f1a02a..78884882555f 100644 --- a/packages/SettingsProvider/res/values-mr/strings.xml +++ b/packages/SettingsProvider/res/values-mr/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"सेटिंग्ज संचयन"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-ms/strings.xml b/packages/SettingsProvider/res/values-ms/strings.xml index 9108b0706899..bcde71c7614b 100644 --- a/packages/SettingsProvider/res/values-ms/strings.xml +++ b/packages/SettingsProvider/res/values-ms/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Storan Tetapan"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-my/strings.xml b/packages/SettingsProvider/res/values-my/strings.xml index 0c5e8407758a..b2e670e07279 100644 --- a/packages/SettingsProvider/res/values-my/strings.xml +++ b/packages/SettingsProvider/res/values-my/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"သိုလှောင်မှုဆက်တင်များ"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-nb/strings.xml b/packages/SettingsProvider/res/values-nb/strings.xml index ad18f945d401..5c60ad708abf 100644 --- a/packages/SettingsProvider/res/values-nb/strings.xml +++ b/packages/SettingsProvider/res/values-nb/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Lagring av innstillinger"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-ne/strings.xml b/packages/SettingsProvider/res/values-ne/strings.xml index af6ef62a17eb..8c4f8c891b0f 100644 --- a/packages/SettingsProvider/res/values-ne/strings.xml +++ b/packages/SettingsProvider/res/values-ne/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"सेटिङहरू भण्डारण"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-nl/strings.xml b/packages/SettingsProvider/res/values-nl/strings.xml index 010fdb574eac..7ad4588c76f2 100644 --- a/packages/SettingsProvider/res/values-nl/strings.xml +++ b/packages/SettingsProvider/res/values-nl/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Opslagruimte voor instellingen"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-or/strings.xml b/packages/SettingsProvider/res/values-or/strings.xml index 04f68c808886..183721954434 100644 --- a/packages/SettingsProvider/res/values-or/strings.xml +++ b/packages/SettingsProvider/res/values-or/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"ସେଟିଙ୍ଗ ଷ୍ଟୋରେଜ୍"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-pa/strings.xml b/packages/SettingsProvider/res/values-pa/strings.xml index 1813becf434a..2961435e6990 100644 --- a/packages/SettingsProvider/res/values-pa/strings.xml +++ b/packages/SettingsProvider/res/values-pa/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"ਸੈਟਿੰਗਾਂ ਸਟੋਰੇਜ"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-pl/strings.xml b/packages/SettingsProvider/res/values-pl/strings.xml index 9f81e632a504..9963aee683f9 100644 --- a/packages/SettingsProvider/res/values-pl/strings.xml +++ b/packages/SettingsProvider/res/values-pl/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Pamięć ustawień"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-pt-rBR/strings.xml b/packages/SettingsProvider/res/values-pt-rBR/strings.xml index ade17469292c..e25e82e46f87 100644 --- a/packages/SettingsProvider/res/values-pt-rBR/strings.xml +++ b/packages/SettingsProvider/res/values-pt-rBR/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Armazenamento de configurações"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-pt-rPT/strings.xml b/packages/SettingsProvider/res/values-pt-rPT/strings.xml index c7dc9e6dc6dd..3b95a31c6cf5 100644 --- a/packages/SettingsProvider/res/values-pt-rPT/strings.xml +++ b/packages/SettingsProvider/res/values-pt-rPT/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Armazenamento de definições"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-pt/strings.xml b/packages/SettingsProvider/res/values-pt/strings.xml index ade17469292c..e25e82e46f87 100644 --- a/packages/SettingsProvider/res/values-pt/strings.xml +++ b/packages/SettingsProvider/res/values-pt/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Armazenamento de configurações"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-ro/strings.xml b/packages/SettingsProvider/res/values-ro/strings.xml index 53e9429a49cd..5a5ac6de32c1 100644 --- a/packages/SettingsProvider/res/values-ro/strings.xml +++ b/packages/SettingsProvider/res/values-ro/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Stocare setări"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-ru/strings.xml b/packages/SettingsProvider/res/values-ru/strings.xml index 4c15984c7ceb..15ca313a1538 100644 --- a/packages/SettingsProvider/res/values-ru/strings.xml +++ b/packages/SettingsProvider/res/values-ru/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Хранилище настроек"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-si/strings.xml b/packages/SettingsProvider/res/values-si/strings.xml index 24ef79820220..feff43c5bc1b 100644 --- a/packages/SettingsProvider/res/values-si/strings.xml +++ b/packages/SettingsProvider/res/values-si/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"සැකසීම් ගබඩාව"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-sk/strings.xml b/packages/SettingsProvider/res/values-sk/strings.xml index 955c834754c2..1207a940eaec 100644 --- a/packages/SettingsProvider/res/values-sk/strings.xml +++ b/packages/SettingsProvider/res/values-sk/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Ukladací priestor nastavení"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-sl/strings.xml b/packages/SettingsProvider/res/values-sl/strings.xml index 3d7768dfa024..28a99375dc40 100644 --- a/packages/SettingsProvider/res/values-sl/strings.xml +++ b/packages/SettingsProvider/res/values-sl/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Shramba nastavitev"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-sq/strings.xml b/packages/SettingsProvider/res/values-sq/strings.xml index a8e66d5dae80..977fe02dbc7b 100644 --- a/packages/SettingsProvider/res/values-sq/strings.xml +++ b/packages/SettingsProvider/res/values-sq/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Hapësira ruajtëse e \"Cilësimeve\""</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-sr/strings.xml b/packages/SettingsProvider/res/values-sr/strings.xml index 7082761e1f71..74b9dde0a4f0 100644 --- a/packages/SettingsProvider/res/values-sr/strings.xml +++ b/packages/SettingsProvider/res/values-sr/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Подешавања складишта"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-sv/strings.xml b/packages/SettingsProvider/res/values-sv/strings.xml index b6de084cdeb9..1444626865c0 100644 --- a/packages/SettingsProvider/res/values-sv/strings.xml +++ b/packages/SettingsProvider/res/values-sv/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Lagring av inställningar"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-sw/strings.xml b/packages/SettingsProvider/res/values-sw/strings.xml index d17f60b92aea..c244d8849ba6 100644 --- a/packages/SettingsProvider/res/values-sw/strings.xml +++ b/packages/SettingsProvider/res/values-sw/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Hifadhi ya Mipangilio"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-ta/strings.xml b/packages/SettingsProvider/res/values-ta/strings.xml index 7a868785d952..b26c875747df 100644 --- a/packages/SettingsProvider/res/values-ta/strings.xml +++ b/packages/SettingsProvider/res/values-ta/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"அமைப்புகளின் சேமிப்பிடம்"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-te/strings.xml b/packages/SettingsProvider/res/values-te/strings.xml index e51ba88e7066..2a4971acd340 100644 --- a/packages/SettingsProvider/res/values-te/strings.xml +++ b/packages/SettingsProvider/res/values-te/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"సెట్టింగ్ల నిల్వ"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-th/strings.xml b/packages/SettingsProvider/res/values-th/strings.xml index ae8ba6a430b8..db47654cad86 100644 --- a/packages/SettingsProvider/res/values-th/strings.xml +++ b/packages/SettingsProvider/res/values-th/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"ที่เก็บข้อมูลการตั้งค่า"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-tl/strings.xml b/packages/SettingsProvider/res/values-tl/strings.xml index 0fe535eee8e3..71c6266b98ca 100644 --- a/packages/SettingsProvider/res/values-tl/strings.xml +++ b/packages/SettingsProvider/res/values-tl/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Storage ng Mga Setting"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-tr/strings.xml b/packages/SettingsProvider/res/values-tr/strings.xml index e99e99bc82ef..4737a1ee9323 100644 --- a/packages/SettingsProvider/res/values-tr/strings.xml +++ b/packages/SettingsProvider/res/values-tr/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Ayarlar Deposu"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-uk/strings.xml b/packages/SettingsProvider/res/values-uk/strings.xml index 900dd0710be5..2c77c6a61d77 100644 --- a/packages/SettingsProvider/res/values-uk/strings.xml +++ b/packages/SettingsProvider/res/values-uk/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Сховище налаштувань"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-ur/strings.xml b/packages/SettingsProvider/res/values-ur/strings.xml index e79249b00c18..31694e0ac3bc 100644 --- a/packages/SettingsProvider/res/values-ur/strings.xml +++ b/packages/SettingsProvider/res/values-ur/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"ترتیبات کا اسٹوریج"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-uz/strings.xml b/packages/SettingsProvider/res/values-uz/strings.xml index 38f0ce518bf6..86a980ece898 100644 --- a/packages/SettingsProvider/res/values-uz/strings.xml +++ b/packages/SettingsProvider/res/values-uz/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Sozlamalar xotirasi"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-vi/strings.xml b/packages/SettingsProvider/res/values-vi/strings.xml index 015fbfda9b82..6476927bf320 100644 --- a/packages/SettingsProvider/res/values-vi/strings.xml +++ b/packages/SettingsProvider/res/values-vi/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Lưu trữ bộ nhớ"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-zh-rCN/strings.xml b/packages/SettingsProvider/res/values-zh-rCN/strings.xml index 11c5d6c28889..13959127a772 100644 --- a/packages/SettingsProvider/res/values-zh-rCN/strings.xml +++ b/packages/SettingsProvider/res/values-zh-rCN/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"设置存储"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-zh-rHK/strings.xml b/packages/SettingsProvider/res/values-zh-rHK/strings.xml index 977c9b91d13d..284526402466 100644 --- a/packages/SettingsProvider/res/values-zh-rHK/strings.xml +++ b/packages/SettingsProvider/res/values-zh-rHK/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"設定儲存空間"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-zh-rTW/strings.xml b/packages/SettingsProvider/res/values-zh-rTW/strings.xml index 977c9b91d13d..284526402466 100644 --- a/packages/SettingsProvider/res/values-zh-rTW/strings.xml +++ b/packages/SettingsProvider/res/values-zh-rTW/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"設定儲存空間"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values-zu/strings.xml b/packages/SettingsProvider/res/values-zu/strings.xml index cb5a7818423b..8c1d9e024099 100644 --- a/packages/SettingsProvider/res/values-zu/strings.xml +++ b/packages/SettingsProvider/res/values-zu/strings.xml @@ -20,4 +20,10 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="app_label" msgid="4567566098528588863">"Izilungiselelo zesitoreji"</string> + <!-- no translation found for wifi_softap_config_change (5338670993556993667) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_summary (7600005249167787750) --> + <skip /> + <!-- no translation found for wifi_softap_config_change_detailed (2504664754843959730) --> + <skip /> </resources> diff --git a/packages/SettingsProvider/res/values/strings.xml b/packages/SettingsProvider/res/values/strings.xml index 9ca575e30ea9..378772750194 100644 --- a/packages/SettingsProvider/res/values/strings.xml +++ b/packages/SettingsProvider/res/values/strings.xml @@ -19,4 +19,19 @@ <resources> <!-- Name of the activity for Settings storage. --> <string name="app_label">Settings Storage</string> + + <!-- A notification is shown when the user's softap config has been changed due to underlying + hardware restrictions. This is the notifications's title. + [CHAR_LIMIT=NONE] --> + <string name="wifi_softap_config_change">Changes to your hotspot settings</string> + + <!-- A notification is shown when the user's softap config has been changed due to underlying + hardware restrictions. This is the notification's summary message. + [CHAR_LIMIT=NONE] --> + <string name="wifi_softap_config_change_summary">Your hotspot band has changed.</string> + + <!-- A notification is shown when the user's softap config has been changed due to underlying + hardware restrictions. This is the notification's full message. + [CHAR_LIMIT=NONE] --> + <string name="wifi_softap_config_change_detailed">This device doesn\u2019t support your preference for 5GHz only. Instead, this device will use the 5GHz band when available.</string> </resources> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index 7e60452411cb..443288cfe492 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -895,11 +895,9 @@ public class SettingsBackupAgent extends BackupAgentHelper { // the apBand preference boolean dualMode = mWifiManager.isDualModeSupported(); int storedApBand = mWifiManager.getWifiApConfiguration().apBand; - if (dualMode) { - if (storedApBand != originalApBand) { - Log.d(TAG, "restored ap configuration requires a conversion, notify the user"); - mWifiManager.notifyUserOfApBandConversion(); - } + if (dualMode && storedApBand != originalApBand) { + Log.d(TAG, "restored ap configuration requires a conversion, notify the user"); + WifiSoftApBandChangedNotifier.notifyUserOfApBandConversion(this); } } catch (IOException | BackupUtils.BadVersionException e) { Log.e(TAG, "Failed to unMarshal SoftAPConfiguration " + e.getMessage()); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 55a51dab3f28..33e0fd23783f 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -2248,12 +2248,6 @@ class SettingsProtoDumpUtil { SecureSettingsProto.Notification.IN_CALL_NOTIFICATION_ENABLED); p.end(notificationToken); - final long packageVerifierToken = p.start(SecureSettingsProto.PACKAGE_VERIFIER); - dumpSetting(s, p, - Settings.Secure.PACKAGE_VERIFIER_USER_CONSENT, - SecureSettingsProto.PackageVerifier.USER_CONSENT); - p.end(packageVerifierToken); - final long parentalControlToken = p.start(SecureSettingsProto.PARENTAL_CONTROL); dumpSetting(s, p, Settings.Secure.PARENTAL_CONTROL_ENABLED, diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index f5d1ccfe378b..0959de9238b5 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -101,6 +101,7 @@ import java.security.SecureRandom; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -383,6 +384,13 @@ public class SettingsProvider extends ContentProvider { break; } + case Settings.CALL_METHOD_SET_ALL_CONFIG: { + String prefix = getSettingPrefix(args); + Map<String, String> flags = getSettingFlags(args); + setAllConfigSettings(prefix, flags); + break; + } + case Settings.CALL_METHOD_RESET_CONFIG: { final int mode = getResetModeEnforcingPermission(args); String prefix = getSettingPrefix(args); @@ -1030,6 +1038,19 @@ public class SettingsProvider extends ContentProvider { MUTATION_OPERATION_INSERT, 0); } + private boolean setAllConfigSettings(String prefix, Map<String, String> keyValues) { + if (DEBUG) { + Slog.v(LOG_TAG, "setAllConfigSettings for prefix: " + prefix); + } + + enforceWritePermission(Manifest.permission.WRITE_DEVICE_CONFIG); + + synchronized (mLock) { + return mSettingsRegistry.setSettingsLocked(SETTINGS_TYPE_CONFIG, UserHandle.USER_SYSTEM, + prefix, keyValues, resolveCallingPackage()); + } + } + private boolean deleteConfigSetting(String name) { if (DEBUG) { Slog.v(LOG_TAG, "deleteConfigSetting(" + name + ")"); @@ -2117,6 +2138,11 @@ public class SettingsProvider extends ContentProvider { return (args != null) ? args.getString(Settings.CALL_METHOD_PREFIX_KEY) : null; } + private static Map<String, String> getSettingFlags(Bundle args) { + return (args != null) ? (HashMap) args.getSerializable(Settings.CALL_METHOD_FLAGS_KEY) + : Collections.emptyMap(); + } + private static boolean getSettingMakeDefault(Bundle args) { return (args != null) && args.getBoolean(Settings.CALL_METHOD_MAKE_DEFAULT_KEY); } @@ -2485,7 +2511,7 @@ public class SettingsProvider extends ContentProvider { final int key = makeKey(type, userId); SettingsState settingsState = peekSettingsStateLocked(key); if (settingsState == null) { - return new ArrayList<String>(); + return new ArrayList<>(); } return settingsState.getSettingNamesLocked(); } @@ -2645,6 +2671,22 @@ public class SettingsProvider extends ContentProvider { return success; } + public boolean setSettingsLocked(int type, int userId, String prefix, + Map<String, String> keyValues, String packageName) { + final int key = makeKey(type, userId); + + SettingsState settingsState = peekSettingsStateLocked(key); + if (settingsState != null) { + List<String> changedSettings = + settingsState.setSettingsLocked(prefix, keyValues, packageName); + if (!changedSettings.isEmpty()) { + notifyForConfigSettingsChangeLocked(key, prefix, changedSettings); + } + } + + return settingsState != null; + } + public boolean deleteSettingLocked(int type, int userId, String name, boolean forceNotify, Set<String> criticalSettings) { final int key = makeKey(type, userId); @@ -3043,6 +3085,28 @@ public class SettingsProvider extends ContentProvider { mHandler.obtainMessage(MyHandler.MSG_NOTIFY_DATA_CHANGED).sendToTarget(); } + private void notifyForConfigSettingsChangeLocked(int key, String prefix, + List<String> changedSettings) { + + // Increment the generation first, so observers always see the new value + mGenerationRegistry.incrementGeneration(key); + + StringBuilder stringBuilder = new StringBuilder(prefix); + for (int i = 0; i < changedSettings.size(); ++i) { + stringBuilder.append(changedSettings.get(i).split("/")[1]).append("/"); + } + + final long token = Binder.clearCallingIdentity(); + try { + notifySettingChangeForRunningUsers(key, stringBuilder.toString()); + } finally { + Binder.restoreCallingIdentity(token); + } + + // Always notify that our data changed + mHandler.obtainMessage(MyHandler.MSG_NOTIFY_DATA_CHANGED).sendToTarget(); + } + private void maybeNotifyProfiles(int type, int userId, Uri uri, String name, Collection<String> keysCloned) { if (keysCloned.contains(name)) { diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java index de6a3a8840a4..4731e6894baf 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java @@ -64,6 +64,7 @@ import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Objects; /** @@ -416,6 +417,57 @@ final class SettingsState { } // The settings provider must hold its lock when calling here. + // Returns the list of keys which changed (added, updated, or deleted). + @GuardedBy("mLock") + public List<String> setSettingsLocked(String prefix, Map<String, String> keyValues, + String packageName) { + List<String> changedKeys = new ArrayList<>(); + // Delete old keys with the prefix that are not part of the new set. + for (int i = 0; i < mSettings.keySet().size(); ++i) { + String key = mSettings.keyAt(i); + if (key.startsWith(prefix) && !keyValues.containsKey(key)) { + Setting oldState = mSettings.remove(key); + + StatsLog.write(StatsLog.SETTING_CHANGED, key, /* value= */ "", /* newValue= */ "", + oldState.value, /* tag */ "", false, getUserIdFromKey(mKey), + StatsLog.SETTING_CHANGED__REASON__DELETED); + addHistoricalOperationLocked(HISTORICAL_OPERATION_DELETE, oldState); + changedKeys.add(key); // key was removed + } + } + + // Update/add new keys + for (String key : keyValues.keySet()) { + String value = keyValues.get(key); + String oldValue = null; + Setting state = mSettings.get(key); + if (state == null) { + state = new Setting(key, value, false, packageName, null); + mSettings.put(key, state); + changedKeys.add(key); // key was added + } else if (state.value != value) { + oldValue = state.value; + state.update(value, false, packageName, null, true); + changedKeys.add(key); // key was updated + } else { + // this key/value already exists, no change and no logging necessary + continue; + } + + StatsLog.write(StatsLog.SETTING_CHANGED, key, value, state.value, oldValue, + /* tag */ null, /* make default */ false, + getUserIdFromKey(mKey), StatsLog.SETTING_CHANGED__REASON__UPDATED); + addHistoricalOperationLocked(HISTORICAL_OPERATION_UPDATE, state); + } + + if (!changedKeys.isEmpty()) { + scheduleWriteIfNeededLocked(); + } + + return changedKeys; + } + + // The settings provider must hold its lock when calling here. public void persistSyncLocked() { mHandler.removeMessages(MyHandler.MSG_PERSIST_SETTINGS); doWriteState(); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApBandChangedNotifier.java b/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApBandChangedNotifier.java new file mode 100644 index 000000000000..d0d4956725d4 --- /dev/null +++ b/packages/SettingsProvider/src/com/android/providers/settings/WifiSoftApBandChangedNotifier.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2019 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.providers.settings; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; + +import com.android.internal.messages.nano.SystemMessageProto; +import com.android.internal.notification.SystemNotificationChannels; + +/** + * Helper class for sending notifications when the user's Soft AP Band was changed upon restore. + */ +public class WifiSoftApBandChangedNotifier { + private WifiSoftApBandChangedNotifier() {} + + /** + * Send a notification informing the user that their' Soft AP Band was changed upon restore. + * When the user taps on the notification, they are taken to the Wifi Tethering page in + * Settings. + */ + public static void notifyUserOfApBandConversion(Context context) { + NotificationManager notificationManager = + context.getSystemService(NotificationManager.class); + + // create channel, or update it if it already exists + NotificationChannel channel = new NotificationChannel( + SystemNotificationChannels.NETWORK_STATUS, + context.getString(android.R.string.notification_channel_network_status), + NotificationManager.IMPORTANCE_LOW); + notificationManager.createNotificationChannel(channel); + + notificationManager.notify( + SystemMessageProto.SystemMessage.NOTE_SOFTAP_CONFIG_CHANGED, + createConversionNotification(context)); + } + + private static Notification createConversionNotification(Context context) { + Resources resources = context.getResources(); + CharSequence title = resources.getText(R.string.wifi_softap_config_change); + CharSequence contentSummary = resources.getText(R.string.wifi_softap_config_change_summary); + CharSequence content = resources.getText(R.string.wifi_softap_config_change_detailed); + int color = resources.getColor( + android.R.color.system_notification_accent_color, context.getTheme()); + + return new Notification.Builder(context, SystemNotificationChannels.NETWORK_STATUS) + .setSmallIcon(R.drawable.ic_wifi_settings) + .setPriority(Notification.PRIORITY_HIGH) + .setCategory(Notification.CATEGORY_SYSTEM) + .setContentTitle(title) + .setContentText(contentSummary) + .setContentIntent(getPendingActivity(context)) + .setTicker(title) + .setShowWhen(false) + .setLocalOnly(true) + .setColor(color) + .setStyle(new Notification.BigTextStyle() + .bigText(content) + .setBigContentTitle(title) + .setSummaryText(contentSummary)) + .setAutoCancel(true) + .build(); + } + + private static PendingIntent getPendingActivity(Context context) { + Intent intent = new Intent("com.android.settings.WIFI_TETHER_SETTINGS") + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); + } +} diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index 289ac802ccb0..7b022a268170 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -662,7 +662,6 @@ public class SettingsBackupTest { Settings.Secure.NIGHT_DISPLAY_LAST_ACTIVATED_TIME, Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED, Settings.Secure.ODI_CAPTIONS_ENABLED, - Settings.Secure.PACKAGE_VERIFIER_USER_CONSENT, Settings.Secure.PARENTAL_CONTROL_LAST_UPDATE, Settings.Secure.PAYMENT_SERVICE_SEARCH_URI, Settings.Secure.PRINT_SERVICE_SEARCH_URI, diff --git a/packages/SystemUI/res/layout/notif_half_shelf.xml b/packages/SystemUI/res/layout/notif_half_shelf.xml index 26c887231349..d36c1a8c961b 100644 --- a/packages/SystemUI/res/layout/notif_half_shelf.xml +++ b/packages/SystemUI/res/layout/notif_half_shelf.xml @@ -46,7 +46,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="8dp" - android:orientation="horizontal" > + android:orientation="horizontal" + android:clickable="true" + android:foreground="?android:attr/selectableItemBackground" > <ImageView android:id="@+id/icon" diff --git a/packages/SystemUI/res/layout/notif_half_shelf_row.xml b/packages/SystemUI/res/layout/notif_half_shelf_row.xml index b95d5e9a43f6..c863e02d5313 100644 --- a/packages/SystemUI/res/layout/notif_half_shelf_row.xml +++ b/packages/SystemUI/res/layout/notif_half_shelf_row.xml @@ -20,7 +20,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="8dp" - android:orientation="horizontal" > + android:clickable="true" + android:orientation="horizontal" + android:foreground="?android:attr/selectableItemBackground" > <!-- This is where an icon would go *if we wanted one* **wink** --> <Space diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index c3f410ea4e55..86ef0310b4eb 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -125,7 +125,7 @@ <!-- The tiles to display in QuickSettings in retail mode --> <string name="quick_settings_tiles_retail_mode" translatable="false"> - cell,battery,dnd,flashlight,rotation,location + night,dark,dnd,flashlight,rotation,location </string> <!-- Whether or not the RSSI tile is capitalized or not. --> diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt index d50666c1b3cf..b2942bb14c6b 100644 --- a/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt +++ b/packages/SystemUI/src/com/android/systemui/broadcast/UserBroadcastDispatcher.kt @@ -28,6 +28,7 @@ import android.util.ArrayMap import android.util.ArraySet import android.util.Log import androidx.annotation.MainThread +import androidx.annotation.VisibleForTesting import com.android.internal.util.Preconditions import com.android.systemui.Dumpable import java.io.FileDescriptor @@ -78,6 +79,14 @@ class UserBroadcastDispatcher( private val actionsToReceivers = ArrayMap<String, MutableSet<ReceiverData>>() private val receiverToReceiverData = ArrayMap<BroadcastReceiver, MutableSet<ReceiverData>>() + @VisibleForTesting + internal fun isReceiverReferenceHeld(receiver: BroadcastReceiver): Boolean { + return receiverToReceiverData.contains(receiver) || + actionsToReceivers.any { + it.value.any { it.receiver == receiver } + } + } + // Only call on BG thread as it reads from the maps private fun createFilter(): IntentFilter { Preconditions.checkState(bgHandler.looper.isCurrentThread, @@ -142,7 +151,7 @@ class UserBroadcastDispatcher( if (DEBUG) Log.w(TAG, "Unregister receiver: $receiver") val actions = receiverToReceiverData.getOrElse(receiver) { return } .flatMap { it.filter.actionsIterator().asSequence().asIterable() }.toSet() - receiverToReceiverData.get(receiver)?.clear() + receiverToReceiverData.remove(receiver)?.clear() var changed = false actions.forEach { action -> actionsToReceivers.get(action)?.removeIf { it.receiver == receiver } diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 51c2ddca869c..b58459470f3f 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -419,9 +419,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, new GlobalActionsPanelPlugin.Callbacks() { @Override public void dismissGlobalActionsMenu() { - if (mDialog != null) { - mDialog.dismiss(); - } + dismissDialog(); } @Override @@ -916,6 +914,9 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, /** {@inheritDoc} */ public void onDismiss(DialogInterface dialog) { + if (mDialog == dialog) { + mDialog = null; + } mWindowManagerFuncs.onGlobalActionsHidden(); if (mShowSilentToggle) { try { diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java index 7fb520766977..ff34be0415ca 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java @@ -90,7 +90,8 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene public QSCustomizer(Context context, AttributeSet attrs, LightBarController lightBarController, KeyguardStateController keyguardStateController, - ScreenLifecycle screenLifecycle) { + ScreenLifecycle screenLifecycle, + TileQueryHelper tileQueryHelper) { super(new ContextThemeWrapper(context, R.style.edit_theme), attrs); LayoutInflater.from(getContext()).inflate(R.layout.qs_customize_panel_content, this); @@ -113,7 +114,8 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene mRecyclerView = findViewById(android.R.id.list); mTransparentView = findViewById(R.id.customizer_transparent_view); mTileAdapter = new TileAdapter(getContext()); - mTileQueryHelper = new TileQueryHelper(context, mTileAdapter); + mTileQueryHelper = tileQueryHelper; + mTileQueryHelper.setListener(mTileAdapter); mRecyclerView.setAdapter(mTileAdapter); mTileAdapter.getItemTouchHelper().attachToRecyclerView(mRecyclerView); GridLayoutManager layout = new GridLayoutManager(getContext(), 3); diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java index 70062492c162..0a9100f6c7d5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java @@ -33,8 +33,9 @@ import android.text.TextUtils; import android.util.ArraySet; import android.widget.Button; -import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.BgHandler; +import com.android.systemui.dagger.qualifiers.MainHandler; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTile.State; import com.android.systemui.qs.QSTileHost; @@ -47,6 +48,8 @@ import java.util.Arrays; import java.util.Collection; import java.util.List; +import javax.inject.Inject; + public class TileQueryHelper { private static final String TAG = "TileQueryHelper"; @@ -55,15 +58,20 @@ public class TileQueryHelper { private final Handler mBgHandler; private final Handler mMainHandler; private final Context mContext; - private final TileStateListener mListener; + private TileStateListener mListener; private boolean mFinished; - public TileQueryHelper(Context context, TileStateListener listener) { + @Inject + public TileQueryHelper(Context context, + @MainHandler Handler mainHandler, @BgHandler Handler bgHandler) { mContext = context; + mMainHandler = mainHandler; + mBgHandler = bgHandler; + } + + public void setListener(TileStateListener listener) { mListener = listener; - mBgHandler = new Handler(Dependency.get(Dependency.BG_LOOPER)); - mMainHandler = Dependency.get(Dependency.MAIN_HANDLER); } public void queryTiles(QSTileHost host) { @@ -178,7 +186,9 @@ public class TileQueryHelper { private void notifyTilesChanged(final boolean finished) { final ArrayList<TileInfo> tilesToReturn = new ArrayList<>(mTiles); mMainHandler.post(() -> { - mListener.onTilesChanged(tilesToReturn); + if (mListener != null) { + mListener.onTilesChanged(tilesToReturn); + } mFinished = finished; }); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java index 8bbfd243bd42..f0140ba0f67c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java @@ -132,7 +132,7 @@ public class NfcTile extends QSTileImpl<BooleanState> { private NfcAdapter getAdapter() { if (mAdapter == null) { try { - mAdapter = NfcAdapter.getNfcAdapter(mContext); + mAdapter = NfcAdapter.getDefaultAdapter(mContext); } catch (UnsupportedOperationException e) { mAdapter = null; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt index 6faf77ec60c7..983315ed98e7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorListView.kt @@ -129,6 +129,8 @@ class AppControlView(c: Context, attrs: AttributeSet) : LinearLayout(c, attrs) { iconView = findViewById(R.id.icon) channelName = findViewById(R.id.app_name) switch = findViewById(R.id.toggle) + + setOnClickListener { switch.toggle() } } } @@ -156,6 +158,7 @@ class ChannelRow(c: Context, attrs: AttributeSet) : LinearLayout(c, attrs) { controller.proposeEditForChannel(it, if (b) it.importance else IMPORTANCE_NONE) } } + setOnClickListener { switch.toggle() } } private fun updateViews() { diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java index 47b56e097ec9..98b4209ede00 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java @@ -84,6 +84,7 @@ public class UsbPermissionActivity extends AlertActivity final AlertController.AlertParams ap = mAlertParams; ap.mTitle = appName; + boolean useRecordWarning = false; if (mDevice == null) { // Accessory Case @@ -97,13 +98,14 @@ public class UsbPermissionActivity extends AlertActivity mPackageName) == android.content.pm.PackageManager.PERMISSION_GRANTED; boolean isAudioCaptureDevice = mDevice.getHasAudioCapture(); - boolean useRecordWarning = isAudioCaptureDevice && !hasRecordPermission; + useRecordWarning = isAudioCaptureDevice && !hasRecordPermission; int strID = useRecordWarning ? R.string.usb_device_permission_prompt_warn : R.string.usb_device_permission_prompt; ap.mMessage = getString(strID, appName, mDevice.getProductName()); mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mDevice); + } ap.mPositiveButtonText = getString(android.R.string.ok); @@ -111,7 +113,8 @@ public class UsbPermissionActivity extends AlertActivity ap.mPositiveButtonListener = this; ap.mNegativeButtonListener = this; - if (canBeDefault && (mDevice != null || mAccessory != null)) { + // Don't show the "always use" checkbox if the USB/Record warning is in effect + if (!useRecordWarning && canBeDefault && (mDevice != null || mAccessory != null)) { // add "open when" checkbox LayoutInflater inflater = (LayoutInflater) getSystemService( Context.LAYOUT_INFLATER_SERVICE); diff --git a/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java b/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java index f3487fb5e2d2..19fff79671d4 100644 --- a/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java +++ b/packages/SystemUI/src/com/android/systemui/wm/DisplayWindowController.java @@ -16,8 +16,10 @@ package com.android.systemui.wm; +import android.content.res.Configuration; import android.os.Handler; import android.os.RemoteException; +import android.util.Slog; import android.util.SparseArray; import android.view.IDisplayWindowListener; import android.view.IDisplayWindowRotationCallback; @@ -40,6 +42,8 @@ import javax.inject.Singleton; */ @Singleton public class DisplayWindowController { + private static final String TAG = "DisplayWindowController"; + private final Handler mHandler; private final ArrayList<OnDisplayWindowRotationController> mRotationControllers = @@ -84,8 +88,26 @@ public class DisplayWindowController { DisplayRecord record = new DisplayRecord(); record.mDisplayId = displayId; mDisplays.put(displayId, record); - for (DisplayWindowListener l : mDisplayChangedListeners) { - l.onDisplayAdded(displayId); + for (int i = 0; i < mDisplayChangedListeners.size(); ++i) { + mDisplayChangedListeners.get(i).onDisplayAdded(displayId); + } + } + }); + } + + @Override + public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) { + mHandler.post(() -> { + synchronized (mDisplays) { + DisplayRecord dr = mDisplays.get(displayId); + if (dr == null) { + Slog.w(TAG, "Skipping Display Configuration change on non-added" + + " display."); + return; + } + for (int i = 0; i < mDisplayChangedListeners.size(); ++i) { + mDisplayChangedListeners.get(i).onDisplayConfigurationChanged( + displayId, newConfig); } } }); @@ -118,8 +140,8 @@ public class DisplayWindowController { } /** - * Add a display window-container listener. It will get notified when displays are - * added/removed from the WM hierarchy. + * Add a display window-container listener. It will get notified whenever a display's + * configuration changes or when displays are added/removed from the WM hierarchy. */ public void addDisplayWindowListener(DisplayWindowListener listener) { synchronized (mDisplays) { @@ -165,7 +187,8 @@ public class DisplayWindowController { } /** - * Gets notified when a display is added/removed to the WM hierarchy. + * Gets notified when a display is added/removed to the WM hierarchy and when a display's + * window-configuration changes. * * @see IDisplayWindowListener */ @@ -176,6 +199,11 @@ public class DisplayWindowController { void onDisplayAdded(int displayId); /** + * Called when a display's window-container configuration changes. + */ + void onDisplayConfigurationChanged(int displayId, Configuration newConfig); + + /** * Called when a display is removed. */ void onDisplayRemoved(int displayId); diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt index e838d9e94a31..21ed15517752 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/UserBroadcastDispatcherTest.kt @@ -77,7 +77,7 @@ class UserBroadcastDispatcherTest : SysuiTestCase() { private lateinit var argumentCaptor: ArgumentCaptor<IntentFilter> private lateinit var testableLooper: TestableLooper - private lateinit var universalBroadcastReceiver: UserBroadcastDispatcher + private lateinit var userBroadcastDispatcher: UserBroadcastDispatcher private lateinit var intentFilter: IntentFilter private lateinit var intentFilterOther: IntentFilter private lateinit var handler: Handler @@ -88,9 +88,9 @@ class UserBroadcastDispatcherTest : SysuiTestCase() { testableLooper = TestableLooper.get(this) handler = Handler(testableLooper.looper) - universalBroadcastReceiver = UserBroadcastDispatcher( + userBroadcastDispatcher = UserBroadcastDispatcher( mockContext, USER_ID, handler, testableLooper.looper) - universalBroadcastReceiver.pendingResult = mPendingResult + userBroadcastDispatcher.pendingResult = mPendingResult } @Test @@ -107,11 +107,11 @@ class UserBroadcastDispatcherTest : SysuiTestCase() { fun testSingleReceiverRegistered() { intentFilter = IntentFilter(ACTION_1) - universalBroadcastReceiver.registerReceiver( + userBroadcastDispatcher.registerReceiver( ReceiverData(broadcastReceiver, intentFilter, mockHandler, USER_HANDLE)) testableLooper.processAllMessages() - assertTrue(universalBroadcastReceiver.isRegistered()) + assertTrue(userBroadcastDispatcher.isRegistered()) verify(mockContext).registerReceiverAsUser( any(), eq(USER_HANDLE), @@ -127,19 +127,19 @@ class UserBroadcastDispatcherTest : SysuiTestCase() { fun testSingleReceiverUnregistered() { intentFilter = IntentFilter(ACTION_1) - universalBroadcastReceiver.registerReceiver( + userBroadcastDispatcher.registerReceiver( ReceiverData(broadcastReceiver, intentFilter, mockHandler, USER_HANDLE)) testableLooper.processAllMessages() reset(mockContext) - assertTrue(universalBroadcastReceiver.isRegistered()) + assertTrue(userBroadcastDispatcher.isRegistered()) - universalBroadcastReceiver.unregisterReceiver(broadcastReceiver) + userBroadcastDispatcher.unregisterReceiver(broadcastReceiver) testableLooper.processAllMessages() verify(mockContext, atLeastOnce()).unregisterReceiver(any()) verify(mockContext, never()).registerReceiverAsUser(any(), any(), any(), any(), any()) - assertFalse(universalBroadcastReceiver.isRegistered()) + assertFalse(userBroadcastDispatcher.isRegistered()) } @Test @@ -150,13 +150,13 @@ class UserBroadcastDispatcherTest : SysuiTestCase() { addCategory(CATEGORY_2) } - universalBroadcastReceiver.registerReceiver( + userBroadcastDispatcher.registerReceiver( ReceiverData(broadcastReceiver, intentFilter, mockHandler, USER_HANDLE)) - universalBroadcastReceiver.registerReceiver( + userBroadcastDispatcher.registerReceiver( ReceiverData(broadcastReceiverOther, intentFilterOther, mockHandler, USER_HANDLE)) testableLooper.processAllMessages() - assertTrue(universalBroadcastReceiver.isRegistered()) + assertTrue(userBroadcastDispatcher.isRegistered()) verify(mockContext, times(2)).registerReceiverAsUser( any(), @@ -178,14 +178,14 @@ class UserBroadcastDispatcherTest : SysuiTestCase() { intentFilter = IntentFilter(ACTION_1) intentFilterOther = IntentFilter(ACTION_2) - universalBroadcastReceiver.registerReceiver( + userBroadcastDispatcher.registerReceiver( ReceiverData(broadcastReceiver, intentFilter, handler, USER_HANDLE)) - universalBroadcastReceiver.registerReceiver( + userBroadcastDispatcher.registerReceiver( ReceiverData(broadcastReceiverOther, intentFilterOther, handler, USER_HANDLE)) val intent = Intent(ACTION_2) - universalBroadcastReceiver.onReceive(mockContext, intent) + userBroadcastDispatcher.onReceive(mockContext, intent) testableLooper.processAllMessages() verify(broadcastReceiver, never()).onReceive(any(), any()) @@ -197,14 +197,14 @@ class UserBroadcastDispatcherTest : SysuiTestCase() { intentFilter = IntentFilter(ACTION_1) intentFilterOther = IntentFilter(ACTION_2) - universalBroadcastReceiver.registerReceiver( + userBroadcastDispatcher.registerReceiver( ReceiverData(broadcastReceiver, intentFilter, handler, USER_HANDLE)) - universalBroadcastReceiver.registerReceiver( + userBroadcastDispatcher.registerReceiver( ReceiverData(broadcastReceiver, intentFilterOther, handler, USER_HANDLE)) val intent = Intent(ACTION_2) - universalBroadcastReceiver.onReceive(mockContext, intent) + userBroadcastDispatcher.onReceive(mockContext, intent) testableLooper.processAllMessages() verify(broadcastReceiver).onReceive(mockContext, intent) @@ -217,14 +217,14 @@ class UserBroadcastDispatcherTest : SysuiTestCase() { intentFilterOther = IntentFilter(ACTION_1) intentFilterOther.addCategory(CATEGORY_2) - universalBroadcastReceiver.registerReceiver( + userBroadcastDispatcher.registerReceiver( ReceiverData(broadcastReceiver, intentFilter, handler, USER_HANDLE)) - universalBroadcastReceiver.registerReceiver( + userBroadcastDispatcher.registerReceiver( ReceiverData(broadcastReceiverOther, intentFilterOther, handler, USER_HANDLE)) val intent = Intent(ACTION_1) - universalBroadcastReceiver.onReceive(mockContext, intent) + userBroadcastDispatcher.onReceive(mockContext, intent) testableLooper.processAllMessages() verify(broadcastReceiver).onReceive(mockContext, intent) @@ -234,15 +234,32 @@ class UserBroadcastDispatcherTest : SysuiTestCase() { @Test fun testPendingResult() { intentFilter = IntentFilter(ACTION_1) - universalBroadcastReceiver.registerReceiver( + userBroadcastDispatcher.registerReceiver( ReceiverData(broadcastReceiver, intentFilter, handler, USER_HANDLE)) val intent = Intent(ACTION_1) - universalBroadcastReceiver.onReceive(mockContext, intent) + userBroadcastDispatcher.onReceive(mockContext, intent) testableLooper.processAllMessages() verify(broadcastReceiver).onReceive(mockContext, intent) verify(broadcastReceiver).pendingResult = mPendingResult } + + @Test + fun testRemoveReceiverReferences() { + intentFilter = IntentFilter(ACTION_1) + userBroadcastDispatcher.registerReceiver( + ReceiverData(broadcastReceiver, intentFilter, handler, USER_HANDLE)) + + intentFilterOther = IntentFilter(ACTION_1) + intentFilterOther.addAction(ACTION_2) + userBroadcastDispatcher.registerReceiver( + ReceiverData(broadcastReceiverOther, intentFilterOther, handler, USER_HANDLE)) + + userBroadcastDispatcher.unregisterReceiver(broadcastReceiver) + testableLooper.processAllMessages() + + assertFalse(userBroadcastDispatcher.isReceiverReferenceHeld(broadcastReceiver)) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java index 9e226f693622..b41512c9a935 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/customize/TileQueryHelperTest.java @@ -36,6 +36,8 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.os.Handler; +import android.os.Looper; import android.provider.Settings; import android.service.quicksettings.Tile; import android.testing.AndroidTestingRunner; @@ -46,7 +48,6 @@ import android.util.ArraySet; import androidx.test.filters.SmallTest; -import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.qs.QSTile; @@ -99,12 +100,12 @@ public class TileQueryHelperTest extends SysuiTestCase { private QSTile.State mState; private TestableLooper mBGLooper; private TileQueryHelper mTileQueryHelper; + private Handler mMainHandler; @Before public void setup() { MockitoAnnotations.initMocks(this); mBGLooper = TestableLooper.get(this); - mDependency.injectTestDependency(Dependency.BG_LOOPER, mBGLooper.getLooper()); mContext.setMockPackageManager(mPackageManager); mState = new QSTile.State(); @@ -122,7 +123,10 @@ public class TileQueryHelperTest extends SysuiTestCase { } ).when(mQSTileHost).createTile(anyString()); - mTileQueryHelper = new TileQueryHelper(mContext, mListener); + mMainHandler = new Handler(Looper.getMainLooper()); + mTileQueryHelper = new TileQueryHelper(mContext, mMainHandler, + new Handler(mBGLooper.getLooper())); + mTileQueryHelper.setListener(mListener); } @Test @@ -135,7 +139,7 @@ public class TileQueryHelperTest extends SysuiTestCase { mTileQueryHelper.queryTiles(mQSTileHost); mBGLooper.processAllMessages(); - waitForIdleSync(Dependency.get(Dependency.MAIN_HANDLER)); + waitForIdleSync(mMainHandler); assertTrue(mTileQueryHelper.isFinished()); } @@ -145,7 +149,7 @@ public class TileQueryHelperTest extends SysuiTestCase { mTileQueryHelper.queryTiles(mQSTileHost); mBGLooper.processAllMessages(); - waitForIdleSync(Dependency.get(Dependency.MAIN_HANDLER)); + waitForIdleSync(mMainHandler); verify(mListener, times(2)).onTilesChanged(any()); } @@ -160,7 +164,7 @@ public class TileQueryHelperTest extends SysuiTestCase { mTileQueryHelper.queryTiles(mQSTileHost); mBGLooper.processAllMessages(); - waitForIdleSync(Dependency.get(Dependency.MAIN_HANDLER)); + waitForIdleSync(mMainHandler); assertTrue(mTileQueryHelper.isFinished()); } @@ -175,7 +179,7 @@ public class TileQueryHelperTest extends SysuiTestCase { mTileQueryHelper.queryTiles(mQSTileHost); mBGLooper.processAllMessages(); - waitForIdleSync(Dependency.get(Dependency.MAIN_HANDLER)); + waitForIdleSync(mMainHandler); verify(mListener, atLeastOnce()).onTilesChanged(mCaptor.capture()); List<String> specs = new ArrayList<>(); @@ -196,7 +200,7 @@ public class TileQueryHelperTest extends SysuiTestCase { mTileQueryHelper.queryTiles(mQSTileHost); mBGLooper.processAllMessages(); - waitForIdleSync(Dependency.get(Dependency.MAIN_HANDLER)); + waitForIdleSync(mMainHandler); verify(mListener, atLeastOnce()).onTilesChanged(mCaptor.capture()); List<String> specs = new ArrayList<>(); @@ -217,7 +221,7 @@ public class TileQueryHelperTest extends SysuiTestCase { mTileQueryHelper.queryTiles(mQSTileHost); mBGLooper.processAllMessages(); - waitForIdleSync(Dependency.get(Dependency.MAIN_HANDLER)); + waitForIdleSync(mMainHandler); verify(mListener, atLeastOnce()).onTilesChanged(mCaptor.capture()); List<String> specs = new ArrayList<>(); @@ -248,7 +252,7 @@ public class TileQueryHelperTest extends SysuiTestCase { mTileQueryHelper.queryTiles(mQSTileHost); mBGLooper.processAllMessages(); - waitForIdleSync(Dependency.get(Dependency.MAIN_HANDLER)); + waitForIdleSync(mMainHandler); verify(mListener, atLeastOnce()).onTilesChanged(mCaptor.capture()); List<TileQueryHelper.TileInfo> tileInfos = mCaptor.getValue(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java index 4d866136c915..61a7cc752c70 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java @@ -139,6 +139,14 @@ public class NetworkControllerBaseTest extends SysuiTestCase { when(mMockCm.getDefaultNetworkCapabilitiesForUser(0)).thenReturn( new NetworkCapabilities[] { mNetCapabilities }); when(mMockTm.createForSubscriptionId(anyInt())).thenReturn(mMockTm); + doAnswer(invocation -> { + int rssi = invocation.getArgument(0); + if (rssi < -88) return 0; + if (rssi < -77) return 1; + if (rssi < -66) return 2; + if (rssi < -55) return 3; + return 4; + }).when(mMockWm).calculateSignalLevel(anyInt()); mSignalStrength = mock(SignalStrength.class); mServiceState = mock(ServiceState.class); diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp index 61bfb92363bd..7b35f4d56a7a 100644 --- a/packages/Tethering/Android.bp +++ b/packages/Tethering/Android.bp @@ -20,12 +20,14 @@ java_defaults { srcs: [ "src/**/*.java", ":framework-tethering-shared-srcs", + ":net-module-utils-srcs", ":services-tethering-shared-srcs", ":servicescore-tethering-src", ], static_libs: [ "androidx.annotation_annotation", "netd_aidl_interface-java", + "netlink-client", "networkstack-aidl-interfaces-java", "android.hardware.tetheroffload.control-V1.0-java", "tethering-client", diff --git a/services/Android.bp b/services/Android.bp index 6953e862f68b..35dc44e0ac65 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -1,3 +1,38 @@ +filegroup { + name: "services-main-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//visibility:private"], +} + +filegroup { + name: "services-sources", + srcs: [ + ":services.core-sources", + ":services.accessibility-sources", + ":services.appprediction-sources", + ":services.appwidget-sources", + ":services.autofill-sources", + ":services.backup-sources", + ":services.companion-sources", + ":services.contentcapture-sources", + ":services.contentsuggestions-sources", + ":services.coverage-sources", + ":services.devicepolicy-sources", + ":services.midi-sources", + ":services.net-sources", + ":services.print-sources", + ":services.restrictions-sources", + ":services.startop.iorap-sources", + ":services.systemcaptions-sources", + ":services.usage-sources", + ":services.usb-sources", + ":services.voiceinteraction-sources", + ":services.wifi-sources", + ], + visibility: ["//visibility:private"], +} + // merge all required services into one jar // ============================================================ java_library { @@ -9,9 +44,7 @@ java_library { profile: "art-profile", }, - srcs: [ - "java/**/*.java", - ], + srcs: [":services-main-sources"], // The convention is to name each service module 'services.$(module_name)' static_libs: [ diff --git a/services/accessibility/Android.bp b/services/accessibility/Android.bp index f991d7b50fcb..284a2f2626a4 100644 --- a/services/accessibility/Android.bp +++ b/services/accessibility/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.accessibility-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.accessibility", - srcs: ["java/**/*.java"], + srcs: [":services.accessibility-sources"], libs: ["services.core"], } diff --git a/services/accessibility/TEST_MAPPING b/services/accessibility/TEST_MAPPING index d90c3bd9b4c2..2b8fee3b54c8 100644 --- a/services/accessibility/TEST_MAPPING +++ b/services/accessibility/TEST_MAPPING @@ -69,6 +69,9 @@ ], "postsubmit": [ { + "name": "CtsAccessibilityServiceSdk29TestCases" + }, + { "name": "CtsAccessibilityServiceTestCases" }, { diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java index cb858ac11b00..339fc963b427 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java @@ -1217,8 +1217,8 @@ public class AccessibilityWindowManager { if (mAccessibilityFocusedWindowId != windowId) { clearAccessibilityFocusLocked(mAccessibilityFocusedWindowId); setAccessibilityFocusedWindowLocked(windowId); - mAccessibilityFocusNodeId = nodeId; } + mAccessibilityFocusNodeId = nodeId; } } break; diff --git a/services/appprediction/Android.bp b/services/appprediction/Android.bp index a7be58783aab..e14e1df0b5c7 100644 --- a/services/appprediction/Android.bp +++ b/services/appprediction/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.appprediction-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.appprediction", - srcs: ["java/**/*.java"], + srcs: [":services.appprediction-sources"], libs: ["services.core"], } diff --git a/services/appwidget/Android.bp b/services/appwidget/Android.bp index aad2ad198bb7..54cf6cec78ea 100644 --- a/services/appwidget/Android.bp +++ b/services/appwidget/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.appwidget-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.appwidget", - srcs: ["java/**/*.java"], + srcs: [":services.appwidget-sources"], libs: ["services.core"], } diff --git a/services/autofill/Android.bp b/services/autofill/Android.bp index 2768c1851314..539eb1a5220e 100644 --- a/services/autofill/Android.bp +++ b/services/autofill/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.autofill-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.autofill", - srcs: ["java/**/*.java"], + srcs: [":services.autofill-sources"], libs: ["services.core"], } diff --git a/services/backup/Android.bp b/services/backup/Android.bp index a3b0c891d00a..f02da2076706 100644 --- a/services/backup/Android.bp +++ b/services/backup/Android.bp @@ -1,6 +1,13 @@ +filegroup { + name: "services.backup-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.backup", - srcs: ["java/**/*.java"], + srcs: [":services.backup-sources"], libs: ["services.core"], static_libs: ["backuplib"], } diff --git a/services/backup/backuplib/Android.bp b/services/backup/backuplib/Android.bp index 7b194a0923c2..00f51c960636 100644 --- a/services/backup/backuplib/Android.bp +++ b/services/backup/backuplib/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "backuplib-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library { name: "backuplib", - srcs: ["java/**/*.java"], + srcs: [":backuplib-sources"], libs: ["services.core"], } diff --git a/services/companion/Android.bp b/services/companion/Android.bp index d2dac357a227..9677a7d83bfb 100644 --- a/services/companion/Android.bp +++ b/services/companion/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.companion-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.companion", - srcs: ["java/**/*.java"], + srcs: [":services.companion-sources"], libs: ["services.core"], } diff --git a/services/contentcapture/Android.bp b/services/contentcapture/Android.bp index 57e859ebe121..96e20726fed3 100644 --- a/services/contentcapture/Android.bp +++ b/services/contentcapture/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.contentcapture-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.contentcapture", - srcs: ["java/**/*.java"], + srcs: [":services.contentcapture-sources"], libs: ["services.core"], } diff --git a/services/contentsuggestions/Android.bp b/services/contentsuggestions/Android.bp index fc09d2e5196a..d17f06f79e97 100644 --- a/services/contentsuggestions/Android.bp +++ b/services/contentsuggestions/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.contentsuggestions-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.contentsuggestions", - srcs: ["java/**/*.java"], + srcs: [":services.contentsuggestions-sources"], libs: ["services.core"], -}
\ No newline at end of file +} diff --git a/services/core/Android.bp b/services/core/Android.bp index b8caefd45135..594ac104ebd0 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -1,3 +1,10 @@ +filegroup { + name: "services.core-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library { name: "protolog-common", srcs: [ @@ -16,7 +23,10 @@ java_library { genrule { name: "services.core.protologsrc", - srcs: [":services.core.wm.protologgroups", "java/**/*.java"], + srcs: [ + ":services.core.wm.protologgroups", + ":services.core-sources", + ], tools: ["protologtool"], cmd: "$(location protologtool) transform-protolog-calls " + "--protolog-class com.android.server.protolog.common.ProtoLog " + @@ -25,20 +35,23 @@ genrule { "--loggroups-class com.android.server.wm.ProtoLogGroup " + "--loggroups-jar $(location :services.core.wm.protologgroups) " + "--output-srcjar $(out) " + - "$(locations java/**/*.java)", + "$(locations :services.core-sources)", out: ["services.core.protolog.srcjar"], } genrule { name: "generate-protolog.json", - srcs: [":services.core.wm.protologgroups", "java/**/*.java"], + srcs: [ + ":services.core.wm.protologgroups", + ":services.core-sources", + ], tools: ["protologtool"], cmd: "$(location protologtool) generate-viewer-config " + "--protolog-class com.android.server.protolog.common.ProtoLog " + "--loggroups-class com.android.server.wm.ProtoLogGroup " + "--loggroups-jar $(location :services.core.wm.protologgroups) " + "--viewer-conf $(out) " + - "$(locations java/**/*.java)", + "$(locations :services.core-sources)", out: ["services.core.protolog.json"], } @@ -60,25 +73,15 @@ genrule { java_library_static { name: "services.core.unboosted", - - aidl: { - include_dirs: [ - "frameworks/base/cmds/idmap2/idmap2d/aidl", - "frameworks/native/aidl/binder", - "frameworks/native/cmds/dumpstate/binder", - "system/core/storaged/binder", - "system/vold/binder", - "system/gsid/aidl", - ], - }, srcs: [ ":services.core.protologsrc", ":dumpstate_aidl", + ":framework_native_aidl", + ":gsiservice_aidl", ":idmap2_aidl", ":installd_aidl", ":storaged_aidl", ":vold_aidl", - ":gsiservice_aidl", ":platform-compat-config", ":tethering-servicescore-srcs", "java/com/android/server/EventLogTags.logtags", diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index dc24cffa54a4..e67d736796b9 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.ComponentName; +import android.content.ContentResolver; import android.content.Intent; import android.content.IntentSender; import android.content.pm.PackageManager.ApplicationInfoFlags; @@ -244,12 +245,16 @@ public abstract class PackageManagerInternal { /** * Retrieve all activities that can be performed for the given intent. + * @param resolvedType the resolved type of the intent, which should be resolved via + * {@link Intent#resolveTypeIfNeeded(ContentResolver)} before passing to {@link PackageManager} * @param filterCallingUid The results will be filtered in the context of this UID instead * of the calling UID. * @see PackageManager#queryIntentActivities(Intent, int) */ - public abstract List<ResolveInfo> queryIntentActivities(Intent intent, - @ResolveInfoFlags int flags, int filterCallingUid, int userId); + public abstract List<ResolveInfo> queryIntentActivities( + Intent intent, @Nullable String resolvedType, @ResolveInfoFlags int flags, + int filterCallingUid, int userId); + /** * Retrieve all services that can be performed for the given intent. diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index a75d5d696bd0..bb7406a56772 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2186,6 +2186,11 @@ public class ConnectivityService extends IConnectivityManager.Stub */ @VisibleForTesting public void systemReady() { + // Let PermissionMonitor#startMonitoring() running in the beginning of the systemReady + // before MultipathPolicyTracker.start(). Since mApps in PermissionMonitor needs to be + // populated first to ensure that listening network request which is sent by + // MultipathPolicyTracker won't be added NET_CAPABILITY_FOREGROUND capability. + mPermissionMonitor.startMonitoring(); mProxyTracker.loadGlobalProxy(); registerNetdEventCallback(); mTethering.systemReady(); @@ -2206,8 +2211,6 @@ public class ConnectivityService extends IConnectivityManager.Stub mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_ALWAYS_ON_NETWORKS)); mHandler.sendMessage(mHandler.obtainMessage(EVENT_SYSTEM_READY)); - - mPermissionMonitor.startMonitoring(); } /** @@ -3185,7 +3188,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (!nai.networkCapabilities.hasTransport(TRANSPORT_VPN)) { updateAllVpnsCapabilities(); } - rematchAllNetworksAndRequests(null, 0); + rematchAllNetworksAndRequests(); mLingerMonitor.noteDisconnect(nai); if (nai.created) { // Tell netd to clean up the configuration for this network @@ -3271,8 +3274,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } } } - rematchAllNetworksAndRequests(null, 0); - ensureRunningOnConnectivityServiceThread(); + rematchAllNetworksAndRequests(); if (nri.request.isRequest() && nri.mSatisfier == null) { sendUpdatedScoreToFactories(nri.request, null); } @@ -3515,13 +3517,12 @@ public class ConnectivityService extends IConnectivityManager.Stub } if (accept != nai.networkMisc.acceptUnvalidated) { - int oldScore = nai.getCurrentScore(); nai.networkMisc.acceptUnvalidated = accept; // If network becomes partial connectivity and user already accepted to use this // network, we should respect the user's option and don't need to popup the // PARTIAL_CONNECTIVITY notification to user again. nai.networkMisc.acceptPartialConnectivity = accept; - rematchAllNetworksAndRequests(nai, oldScore); + rematchAllNetworksAndRequests(); sendUpdatedScoreToFactories(nai); } @@ -3590,9 +3591,8 @@ public class ConnectivityService extends IConnectivityManager.Stub return; } if (!nai.avoidUnvalidated) { - int oldScore = nai.getCurrentScore(); nai.avoidUnvalidated = true; - rematchAllNetworksAndRequests(nai, oldScore); + rematchAllNetworksAndRequests(); sendUpdatedScoreToFactories(nai); } } @@ -3693,7 +3693,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private void rematchForAvoidBadWifiUpdate() { - rematchAllNetworksAndRequests(null, 0); + rematchAllNetworksAndRequests(); for (NetworkAgentInfo nai: mNetworkAgentInfos.values()) { if (nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { sendUpdatedScoreToFactories(nai); @@ -5965,7 +5965,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } else { // If the requestable capabilities have changed or the score changed, we can't have been // called by rematchNetworkAndRequests, so it's safe to start a rematch. - rematchAllNetworksAndRequests(nai, oldScore); + rematchAllNetworksAndRequests(); notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED); } @@ -6294,6 +6294,41 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + private ArrayMap<NetworkRequestInfo, NetworkAgentInfo> computeRequestReassignmentForNetwork( + @NonNull final NetworkAgentInfo newNetwork) { + final int score = newNetwork.getCurrentScore(); + final ArrayMap<NetworkRequestInfo, NetworkAgentInfo> reassignedRequests = new ArrayMap<>(); + for (NetworkRequestInfo nri : mNetworkRequests.values()) { + // Process requests in the first pass and listens in the second pass. This allows us to + // change a network's capabilities depending on which requests it has. This is only + // correct if the change in capabilities doesn't affect whether the network satisfies + // requests or not, and doesn't affect the network's score. + if (nri.request.isListen()) continue; + + final NetworkAgentInfo currentNetwork = nri.mSatisfier; + final boolean satisfies = newNetwork.satisfies(nri.request); + if (newNetwork == currentNetwork && satisfies) continue; + + // check if it satisfies the NetworkCapabilities + if (VDBG) log(" checking if request is satisfied: " + nri.request); + if (satisfies) { + // next check if it's better than any current network we're using for + // this request + if (VDBG || DDBG) { + log("currentScore = " + + (currentNetwork != null ? currentNetwork.getCurrentScore() : 0) + + ", newScore = " + score); + } + if (currentNetwork == null || currentNetwork.getCurrentScore() < score) { + reassignedRequests.put(nri, newNetwork); + } + } else if (newNetwork.isSatisfyingRequest(nri.request.requestId)) { + reassignedRequests.put(nri, null); + } + } + return reassignedRequests; + } + // Handles a network appearing or improving its score. // // - Evaluates all current NetworkRequests that can be @@ -6307,10 +6342,6 @@ public class ConnectivityService extends IConnectivityManager.Stub // - Tears down newNetwork if it just became validated // but turns out to be unneeded. // - // - If reapUnvalidatedNetworks==REAP, tears down unvalidated - // networks that have no chance (i.e. even if validated) - // of becoming the highest scoring network. - // // NOTE: This function only adds NetworkRequests that "newNetwork" could satisfy, // it does not remove NetworkRequests that other Networks could better satisfy. // If you need to handle decreases in score, use {@link rematchAllNetworksAndRequests}. @@ -6318,14 +6349,10 @@ public class ConnectivityService extends IConnectivityManager.Stub // as it performs better by a factor of the number of Networks. // // @param newNetwork is the network to be matched against NetworkRequests. - // @param reapUnvalidatedNetworks indicates if an additional pass over all networks should be - // performed to tear down unvalidated networks that have no chance (i.e. even if - // validated) of becoming the highest scoring network. - private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, - ReapUnvalidatedNetworks reapUnvalidatedNetworks, long now) { + // @param now the time the rematch starts, as returned by SystemClock.elapsedRealtime(); + private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, long now) { ensureRunningOnConnectivityServiceThread(); if (!newNetwork.everConnected) return; - boolean keep = newNetwork.isVPN(); boolean isNewDefault = false; NetworkAgentInfo oldDefaultNetwork = null; @@ -6334,39 +6361,11 @@ public class ConnectivityService extends IConnectivityManager.Stub if (VDBG || DDBG) log("rematching " + newNetwork.name()); - final ArrayMap<NetworkRequestInfo, NetworkAgentInfo> reassignedRequests = new ArrayMap<>(); + final ArrayMap<NetworkRequestInfo, NetworkAgentInfo> reassignedRequests = + computeRequestReassignmentForNetwork(newNetwork); NetworkCapabilities nc = newNetwork.networkCapabilities; if (VDBG) log(" network has: " + nc); - for (NetworkRequestInfo nri : mNetworkRequests.values()) { - // Process requests in the first pass and listens in the second pass. This allows us to - // change a network's capabilities depending on which requests it has. This is only - // correct if the change in capabilities doesn't affect whether the network satisfies - // requests or not, and doesn't affect the network's score. - if (nri.request.isListen()) continue; - - ensureRunningOnConnectivityServiceThread(); - final NetworkAgentInfo currentNetwork = nri.mSatisfier; - final boolean satisfies = newNetwork.satisfies(nri.request); - if (newNetwork == currentNetwork && satisfies) continue; - - // check if it satisfies the NetworkCapabilities - if (VDBG) log(" checking if request is satisfied: " + nri.request); - if (satisfies) { - // next check if it's better than any current network we're using for - // this request - if (VDBG || DDBG) { - log("currentScore = " + - (currentNetwork != null ? currentNetwork.getCurrentScore() : 0) + - ", newScore = " + score); - } - if (currentNetwork == null || currentNetwork.getCurrentScore() < score) { - reassignedRequests.put(nri, newNetwork); - } - } else if (newNetwork.isSatisfyingRequest(nri.request.requestId)) { - reassignedRequests.put(nri, null); - } - } // Find and migrate to this Network any NetworkRequests for // which this network is now the best. @@ -6395,7 +6394,6 @@ public class ConnectivityService extends IConnectivityManager.Stub Slog.wtf(TAG, "BUG: " + newSatisfier.name() + " already has " + nri.request); } addedRequests.add(nri); - keep = true; // Tell NetworkFactories about the new score, so they can stop // trying to connect if they know they cannot match it. // TODO - this could get expensive if we have a lot of requests for this @@ -6502,7 +6500,7 @@ public class ConnectivityService extends IConnectivityManager.Stub notifyLockdownVpn(newNetwork); } - if (keep) { + if (reassignedRequests.containsValue(newNetwork) || newNetwork.isVPN()) { // Notify battery stats service about this network, both the normal // interface and any stacked links. // TODO: Avoid redoing this; this must only be done once when a network comes online. @@ -6549,66 +6547,43 @@ public class ConnectivityService extends IConnectivityManager.Stub mLegacyTypeTracker.add(TYPE_VPN, newNetwork); } } - if (reapUnvalidatedNetworks == ReapUnvalidatedNetworks.REAP) { - for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { - if (unneeded(nai, UnneededFor.TEARDOWN)) { - if (nai.getLingerExpiry() > 0) { - // This network has active linger timers and no requests, but is not - // lingering. Linger it. - // - // One way (the only way?) this can happen if this network is unvalidated - // and became unneeded due to another network improving its score to the - // point where this network will no longer be able to satisfy any requests - // even if it validates. - updateLingerState(nai, now); - } else { - if (DBG) log("Reaping " + nai.name()); - teardownUnneededNetwork(nai); - } - } - } - } } /** * Attempt to rematch all Networks with NetworkRequests. This may result in Networks * being disconnected. - * @param changed If only one Network's score or capabilities have been modified since the last - * time this function was called, pass this Network in this argument, otherwise pass - * null. - * @param oldScore If only one Network has been changed but its NetworkCapabilities have not - * changed, pass in the Network's score (from getCurrentScore()) prior to the change via - * this argument, otherwise pass {@code changed.getCurrentScore()} or 0 if - * {@code changed} is {@code null}. This is because NetworkCapabilities influence a - * network's score. */ - private void rematchAllNetworksAndRequests(NetworkAgentInfo changed, int oldScore) { - // TODO: This may get slow. The "changed" parameter is provided for future optimization - // to avoid the slowness. It is not simply enough to process just "changed", for - // example in the case where "changed"'s score decreases and another network should begin - // satisfying a NetworkRequest that "changed" currently satisfies. - - // Optimization: Only reprocess "changed" if its score improved. This is safe because it - // can only add more NetworkRequests satisfied by "changed", and this is exactly what - // rematchNetworkAndRequests() handles. + private void rematchAllNetworksAndRequests() { + // TODO: This may be slow, and should be optimized. Unfortunately at this moment the + // processing is network-major instead of request-major (the code iterates through all + // networks, then for each it iterates for all requests), which is a problem for re-scoring + // requests. Once the code has switched to a request-major iteration style, this can + // be optimized to only do the processing needed. final long now = SystemClock.elapsedRealtime(); - if (changed != null && oldScore < changed.getCurrentScore()) { - rematchNetworkAndRequests(changed, ReapUnvalidatedNetworks.REAP, now); - } else { - final NetworkAgentInfo[] nais = mNetworkAgentInfos.values().toArray( - new NetworkAgentInfo[mNetworkAgentInfos.size()]); - // Rematch higher scoring networks first to prevent requests first matching a lower - // scoring network and then a higher scoring network, which could produce multiple - // callbacks and inadvertently unlinger networks. - Arrays.sort(nais); - for (NetworkAgentInfo nai : nais) { - rematchNetworkAndRequests(nai, - // Only reap the last time through the loop. Reaping before all rematching - // is complete could incorrectly teardown a network that hasn't yet been - // rematched. - (nai != nais[nais.length-1]) ? ReapUnvalidatedNetworks.DONT_REAP - : ReapUnvalidatedNetworks.REAP, - now); + final NetworkAgentInfo[] nais = mNetworkAgentInfos.values().toArray( + new NetworkAgentInfo[mNetworkAgentInfos.size()]); + // Rematch higher scoring networks first to prevent requests first matching a lower + // scoring network and then a higher scoring network, which could produce multiple + // callbacks and inadvertently unlinger networks. + Arrays.sort(nais); + for (NetworkAgentInfo nai : nais) { + rematchNetworkAndRequests(nai, now); + } + for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + if (unneeded(nai, UnneededFor.TEARDOWN)) { + if (nai.getLingerExpiry() > 0) { + // This network has active linger timers and no requests, but is not + // lingering. Linger it. + // + // One way (the only way?) this can happen if this network is unvalidated + // and became unneeded due to another network improving its score to the + // point where this network will no longer be able to satisfy any requests + // even if it validates. + updateLingerState(nai, now); + } else { + if (DBG) log("Reaping " + nai.name()); + teardownUnneededNetwork(nai); + } } } } @@ -6707,8 +6682,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } // Consider network even though it is not yet validated. - final long now = SystemClock.elapsedRealtime(); - rematchNetworkAndRequests(networkAgent, ReapUnvalidatedNetworks.REAP, now); + rematchAllNetworksAndRequests(); // This has to happen after matching the requests, because callbacks are just requests. notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK); @@ -6729,7 +6703,7 @@ public class ConnectivityService extends IConnectivityManager.Stub state == NetworkInfo.State.SUSPENDED)) { // going into or coming out of SUSPEND: re-score and notify if (networkAgent.getCurrentScore() != oldScore) { - rematchAllNetworksAndRequests(networkAgent, oldScore); + rematchAllNetworksAndRequests(); } updateCapabilities(networkAgent.getCurrentScore(), networkAgent, networkAgent.networkCapabilities); @@ -6743,19 +6717,9 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void updateNetworkScore(NetworkAgentInfo nai, NetworkScore ns) { - int score = ns.getIntExtension(NetworkScore.LEGACY_SCORE); - if (VDBG || DDBG) log("updateNetworkScore for " + nai.name() + " to " + score); - if (score < 0) { - loge("updateNetworkScore for " + nai.name() + " got a negative score (" + score + - "). Bumping score to min of 0"); - score = 0; - } - - final int oldScore = nai.getCurrentScore(); + if (VDBG || DDBG) log("updateNetworkScore for " + nai.name() + " to " + ns); nai.setNetworkScore(ns); - - rematchAllNetworksAndRequests(nai, oldScore); - + rematchAllNetworksAndRequests(); sendUpdatedScoreToFactories(nai); } diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 34c5842d9a2f..9ebe896e668b 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -3309,18 +3309,24 @@ public class LocationManagerService extends ILocationManager.Stub { ipw.decreaseIndent(); } - mSettingsStore.dump(fd, pw, args); + ipw.println("Location Settings:"); + ipw.increaseIndent(); + mSettingsStore.dump(fd, ipw, args); + ipw.decreaseIndent(); ipw.println("Location Providers:"); ipw.increaseIndent(); for (LocationProvider provider : mProviders) { provider.dumpLocked(fd, ipw, args); } + ipw.decreaseIndent(); } if (mGnssManagerService != null) { + ipw.println("GNSS:"); + ipw.increaseIndent(); + mGnssManagerService.dump(fd, ipw, args); ipw.decreaseIndent(); - mGnssManagerService.dump(fd, pw, args); } } } diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java index df5005eed66b..b26ef92557e1 100644 --- a/services/core/java/com/android/server/NetworkScoreService.java +++ b/services/core/java/com/android/server/NetworkScoreService.java @@ -58,12 +58,10 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.PackageMonitor; -import com.android.internal.os.TransferPipe; import com.android.internal.util.DumpUtils; import com.android.server.pm.permission.PermissionManagerServiceInternal; import java.io.FileDescriptor; -import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collection; @@ -903,17 +901,6 @@ public class NetworkScoreService extends INetworkScoreService.Stub { } writer.println("Current scorer: " + currentScorer); - sendCacheUpdateCallback(new BiConsumer<INetworkScoreCache, Object>() { - @Override - public void accept(INetworkScoreCache networkScoreCache, Object cookie) { - try { - TransferPipe.dumpAsync(networkScoreCache.asBinder(), fd, args); - } catch (IOException | RemoteException e) { - writer.println("Failed to dump score cache: " + e); - } - } - }, getScoreCacheLists()); - synchronized (mServiceConnectionLock) { if (mServiceConnection != null) { mServiceConnection.dump(fd, writer, args); diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index dcc690fa09b4..a4bc3bd9101c 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -80,6 +80,7 @@ import android.os.IBinder; import android.os.IStoraged; import android.os.IVold; import android.os.IVoldListener; +import android.os.IVoldMountCallback; import android.os.IVoldTaskListener; import android.os.Looper; import android.os.Message; @@ -348,10 +349,6 @@ class StorageManagerService extends IStorageManager.Stub @GuardedBy("mLock") private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>(); - /** Map from volume ID to latches */ - @GuardedBy("mLock") - private ArrayMap<String, CountDownLatch> mFuseVolumeReadyLatches = new ArrayMap<>(); - @GuardedBy("mLock") private IPackageMoveObserver mMoveCallback; @GuardedBy("mLock") @@ -464,17 +461,6 @@ class StorageManagerService extends IStorageManager.Stub } } - private CountDownLatch findOrCreateFuseVolumeReadyLatch(String volId) { - synchronized (mLock) { - CountDownLatch latch = mFuseVolumeReadyLatches.get(volId); - if (latch == null) { - latch = new CountDownLatch(1); - mFuseVolumeReadyLatches.put(volId, latch); - } - return latch; - } - } - /** List of crypto types. * These must match CRYPT_TYPE_XXX in cryptfs.h AND their * corresponding commands in CommandListener.cpp */ @@ -612,7 +598,6 @@ class StorageManagerService extends IStorageManager.Stub private static final int H_ABORT_IDLE_MAINT = 12; private static final int H_BOOT_COMPLETED = 13; private static final int H_COMPLETE_UNLOCK_USER = 14; - private static final int H_VOLUME_READY = 15; class StorageManagerServiceHandler extends Handler { public StorageManagerServiceHandler(Looper looper) { @@ -673,22 +658,6 @@ class StorageManagerService extends IStorageManager.Stub } break; } - case H_VOLUME_READY: { - final VolumeInfo vol = (VolumeInfo) msg.obj; - try { - mStorageSessionController.onVolumeReady(vol); - - synchronized (mLock) { - CountDownLatch latch = mFuseVolumeReadyLatches.remove(vol.id); - if (latch != null) { - latch.countDown(); - } - } - } catch (IllegalStateException | ExternalStorageServiceException e) { - Slog.i(TAG, "Failed to initialise volume " + vol, e); - } - break; - } case H_VOLUME_MOUNT: { final VolumeInfo vol = (VolumeInfo) msg.obj; if (isMountDisallowed(vol)) { @@ -1431,13 +1400,6 @@ class StorageManagerService extends IStorageManager.Stub writeSettingsLocked(); } - if (mIsFuseEnabled && newState == VolumeInfo.STATE_MOUNTED - && (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_EMULATED)) { - Slog.i(TAG, "Initialising volume " + vol + " ..."); - // TODO(b/144275217): Delay broadcasts till mount is really ready - mHandler.obtainMessage(H_VOLUME_READY, vol).sendToTarget(); - } - mCallbacks.notifyVolumeStateChanged(vol, oldState, newState); // Do not broadcast before boot has completed to avoid launching the @@ -1912,33 +1874,29 @@ class StorageManagerService extends IStorageManager.Stub throw new SecurityException("Mounting " + volId + " restricted by policy"); } - CountDownLatch latch = null; - if (mIsFuseEnabled && StorageSessionController.isEmulatedOrPublic(vol)) { - latch = findOrCreateFuseVolumeReadyLatch(volId); - } - mount(vol); - - if (latch != null) { - try { - waitForLatch(latch, "mount " + volId, 3 * DateUtils.MINUTE_IN_MILLIS); - } catch (TimeoutException e) { - Slog.wtf(TAG, e); - } finally { - synchronized (mLock) { - mFuseVolumeReadyLatches.remove(volId); - } - } - } } private void mount(VolumeInfo vol) { try { // TODO(b/135341433): Remove paranoid logging when FUSE is stable Slog.i(TAG, "Mounting volume " + vol); - FileDescriptor fd = mVold.mount(vol.id, vol.mountFlags, vol.mountUserId); + mVold.mount(vol.id, vol.mountFlags, vol.mountUserId, new IVoldMountCallback.Stub() { + @Override + public boolean onVolumeChecking(FileDescriptor deviceFd, String path, + String internalPath) { + vol.path = path; + vol.internalPath = internalPath; + try { + mStorageSessionController.onVolumeMount(deviceFd, vol); + return true; + } catch (ExternalStorageServiceException e) { + Slog.i(TAG, "Failed to mount volume " + vol, e); + return false; + } + } + }); Slog.i(TAG, "Mounted volume " + vol); - mStorageSessionController.onVolumeMount(fd, vol); } catch (Exception e) { Slog.wtf(TAG, e); } @@ -2771,11 +2729,6 @@ class StorageManagerService extends IStorageManager.Stub */ @Override public boolean supportsCheckpoint() throws RemoteException { - // Only the system process is permitted to start checkpoints - if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { - throw new SecurityException("no permission to check filesystem checkpoint support"); - } - return mVold.supportsCheckpoint(); } @@ -2926,12 +2879,6 @@ class StorageManagerService extends IStorageManager.Stub enforcePermission(android.Manifest.permission.STORAGE_INTERNAL); if (StorageManager.isFileEncryptedNativeOrEmulated()) { - // When a user has secure lock screen, require secret to actually unlock. - // This check is mostly in place for emulation mode. - if (mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(secret)) { - throw new IllegalStateException("Secret required to unlock secure user " + userId); - } - try { mVold.unlockUserKey(userId, serialNumber, encodeBytes(token), encodeBytes(secret)); @@ -3648,7 +3595,7 @@ class StorageManagerService extends IStorageManager.Stub try { mObbState.volId = mVold.createObb(mObbState.canonicalPath, binderKey, mObbState.ownerGid); - mVold.mount(mObbState.volId, 0, -1); + mVold.mount(mObbState.volId, 0, -1, null); if (DEBUG_OBB) Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 88d0e4b7344f..5b7a8148d694 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -568,6 +568,11 @@ public class ActivityManagerService extends IActivityManager.Stub private static final int NATIVE_DUMP_TIMEOUT_MS = 2000; // 2 seconds; private static final int JAVA_DUMP_MINIMUM_SIZE = 100; // 100 bytes. + /** + * How long between a process kill and we actually receive its death recipient + */ + private static final long PROC_KILL_TIMEOUT = 5000; // 5 seconds; + OomAdjuster mOomAdjuster; final LowMemDetector mLowMemDetector; @@ -3738,6 +3743,9 @@ public class ActivityManagerService extends IActivityManager.Stub "Dying app: " + app + ", pid: " + pid + ", thread: " + thread.asBinder()); handleAppDiedLocked(app, false, true); + // Execute the callback if there is any. + doAppDiedCallbackLocked(app); + if (doOomAdj) { updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_END); } @@ -3749,6 +3757,10 @@ public class ActivityManagerService extends IActivityManager.Stub reportUidInfoMessageLocked(TAG, "Process " + app.processName + " (pid " + pid + ") has died and restarted (pid " + app.pid + ").", app.info.uid); + + // Execute the callback if there is any. + doAppDiedCallbackLocked(app); + EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName); } else if (DEBUG_PROCESSES) { Slog.d(TAG_PROCESSES, "Received spurious death notification for thread " @@ -3762,6 +3774,39 @@ public class ActivityManagerService extends IActivityManager.Stub } } + @GuardedBy("this") + private void doAppDiedCallbackLocked(final ProcessRecord app) { + if (app.mAppDiedCallback != null) { + app.mAppDiedCallback.run(); + app.mAppDiedCallback = null; + } + } + + @GuardedBy("this") + private void waitForProcKillLocked(final ProcessRecord app, final String formatString, + final long startTime) { + app.mAppDiedCallback = () -> { + synchronized (ActivityManagerService.this) { + // called when this app receives appDiedLocked() + ActivityManagerService.this.notifyAll(); + } + }; + checkTime(startTime, String.format(formatString, "before appDied")); + long now = SystemClock.uptimeMillis(); + long timeout = PROC_KILL_TIMEOUT + now; + while (app.mAppDiedCallback != null && timeout > now) { + try { + wait(timeout - now); + } catch (InterruptedException e) { + } + now = SystemClock.uptimeMillis(); + } + checkTime(startTime, String.format(formatString, "after appDied")); + if (app.mAppDiedCallback != null) { + Slog.w(TAG, String.format(formatString, "waiting for app killing timed out")); + } + } + /** * If a stack trace dump file is configured, dump process stack traces. * @param firstPids of dalvik VM processes to dump stack traces for first @@ -6779,18 +6824,12 @@ public class ActivityManagerService extends IActivityManager.Stub // Note if killedByAm is also set, this means the provider process has just been // killed by AM (in ProcessRecord.kill()), but appDiedLocked() hasn't been called - // yet. So we need to call appDiedLocked() here and let it clean up. + // yet. So we need to wait for appDiedLocked() here and let it clean up. // (See the commit message on I2c4ba1e87c2d47f2013befff10c49b3dc337a9a7 to see // how to test this case.) if (cpr.proc.killed && cpr.proc.killedByAm) { - checkTime(startTime, "getContentProviderImpl: before appDied (killedByAm)"); - final long iden = Binder.clearCallingIdentity(); - try { - appDiedLocked(cpr.proc); - } finally { - Binder.restoreCallingIdentity(iden); - } - checkTime(startTime, "getContentProviderImpl: after appDied (killedByAm)"); + waitForProcKillLocked(cpr.proc, "getContentProviderImpl: %s (killedByAm)", + startTime); } } @@ -6894,9 +6933,7 @@ public class ActivityManagerService extends IActivityManager.Stub Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString() + " is crashing; detaching " + r); boolean lastRef = decProviderCountLocked(conn, cpr, token, stable); - checkTime(startTime, "getContentProviderImpl: before appDied"); - appDiedLocked(cpr.proc); - checkTime(startTime, "getContentProviderImpl: after appDied"); + waitForProcKillLocked(cpr.proc, "getContentProviderImpl: %s", startTime); if (!lastRef) { // This wasn't the last ref our process had on // the provider... we have now been killed, bail. diff --git a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java index c7de7b17b1c2..183e05979c5e 100644 --- a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java +++ b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java @@ -37,6 +37,7 @@ import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; import android.widget.TextView; + import com.android.internal.R; @@ -65,7 +66,9 @@ final class CarUserSwitchingDialog extends UserSwitchingDialog { setCancelable(false); Resources res = getContext().getResources(); // Custom view due to alignment and font size requirements - getContext().setTheme(R.style.Theme_DeviceDefault_Light_Dialog_Alert_UserSwitchingDialog); + // TODO (b/145021634): disabled because it's delaying user switch by 3 seconds + // getContext() + // .setTheme(R.style.Theme_DeviceDefault_Light_Dialog_Alert_UserSwitchingDialog); View view = LayoutInflater.from(getContext()).inflate( R.layout.car_user_switching_dialog, null); diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 30674db484d5..0591704a0502 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -306,7 +306,7 @@ public final class OomAdjuster { @GuardedBy("mService") void updateOomAdjLocked(String oomAdjReason) { final ProcessRecord topApp = mService.getTopAppLocked(); - updateOomAdjLockedInner(oomAdjReason, topApp , null, null, true); + updateOomAdjLockedInner(oomAdjReason, topApp , null, null, true, true); } /** @@ -361,8 +361,10 @@ public final class OomAdjuster { uids.clear(); queue.clear(); - // borrow the "containsCycle" flag to mark it being scanned - app.containsCycle = true; + // Track if any of them reachables could include a cycle + boolean containsCycle = false; + // Scan downstreams of the process record + app.mReachable = true; for (ProcessRecord pr = app; pr != null; pr = queue.poll()) { if (pr != app) { processes.add(pr); @@ -374,7 +376,7 @@ public final class OomAdjuster { ConnectionRecord cr = pr.connections.valueAt(i); ProcessRecord service = (cr.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0 ? cr.binding.service.isolatedProc : cr.binding.service.app; - if (service == null || service.containsCycle) { + if (service == null || service == pr || (containsCycle |= service.mReachable)) { continue; } if ((cr.flags & (Context.BIND_WAIVE_PRIORITY @@ -384,21 +386,21 @@ public final class OomAdjuster { continue; } queue.offer(service); - service.containsCycle = true; + service.mReachable = true; } for (int i = pr.conProviders.size() - 1; i >= 0; i--) { ContentProviderConnection cpc = pr.conProviders.get(i); ProcessRecord provider = cpc.provider.proc; - if (provider == null || provider.containsCycle) { + if (provider == null || provider == pr || (containsCycle |= provider.mReachable)) { continue; } queue.offer(provider); - provider.containsCycle = true; + provider.mReachable = true; } } // Reset the flag - app.containsCycle = false; + app.mReachable = false; int size = processes.size(); if (size > 0) { // Reverse the process list, since the updateOomAdjLockedInner scans from the end of it. @@ -409,7 +411,7 @@ public final class OomAdjuster { } mAdjSeq--; // Update these reachable processes - updateOomAdjLockedInner(oomAdjReason, topApp, processes, uids, false); + updateOomAdjLockedInner(oomAdjReason, topApp, processes, uids, containsCycle, false); } else if (app.getCurRawAdj() == ProcessList.UNKNOWN_ADJ) { // In case the app goes from non-cached to cached but it doesn't have other reachable // processes, its adj could be still unknown as of now, assign one. @@ -430,7 +432,8 @@ public final class OomAdjuster { */ @GuardedBy("mService") private void updateOomAdjLockedInner(String oomAdjReason, final ProcessRecord topApp, - ArrayList<ProcessRecord> processes, ActiveUids uids, boolean startProfiling) { + ArrayList<ProcessRecord> processes, ActiveUids uids, boolean potentialCycles, + boolean startProfiling) { if (startProfiling) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReason); mService.mOomAdjProfiler.oomAdjStarted(); @@ -474,11 +477,13 @@ public final class OomAdjuster { } boolean retryCycles = false; + boolean computeClients = fullUpdate || potentialCycles; // need to reset cycle state before calling computeOomAdjLocked because of service conns for (int i = numProc - 1; i >= 0; i--) { ProcessRecord app = activeProcesses.get(i); app.containsCycle = false; + app.mReachable = false; app.setCurRawProcState(PROCESS_STATE_CACHED_EMPTY); app.setCurRawAdj(ProcessList.UNKNOWN_ADJ); app.setCapability = PROCESS_CAPABILITY_NONE; @@ -489,7 +494,7 @@ public final class OomAdjuster { if (!app.killedByAm && app.thread != null) { app.procStateChanged = false; computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, topApp, fullUpdate, now, false, - fullUpdate); // It won't enter cycle if not computing clients. + computeClients); // It won't enter cycle if not computing clients. // if any app encountered a cycle, we need to perform an additional loop later retryCycles |= app.containsCycle; // Keep the completedAdjSeq to up to date. @@ -499,7 +504,7 @@ public final class OomAdjuster { assignCachedAdjIfNecessary(mProcessList.mLruProcesses); - if (fullUpdate) { // There won't be cycles if we didn't compute clients above. + if (computeClients) { // There won't be cycles if we didn't compute clients above. // Cycle strategy: // - Retry computing any process that has encountered a cycle. // - Continue retrying until no process was promoted. diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 1e0693f365e7..867571a33bc2 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -327,6 +327,11 @@ class ProcessRecord implements WindowProcessListener { int mCachedProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; int mCachedSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND; + boolean mReachable; // Whether or not this process is reachable from given process + + // A callback that should be executed on app died; after that it'll be set to null + Runnable mAppDiedCallback; + void setStartParams(int startUid, HostingRecord hostingRecord, String seInfo, long startTime) { this.startUid = startUid; diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index 90973a888a9d..a2b3574880c4 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -44,6 +44,8 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; +import java.util.HashSet; +import java.util.Set; /** * Class to manage the inventory of all connected devices. @@ -372,9 +374,14 @@ public class AudioDeviceInventory { mDeviceBroker.postObserveDevicesForAllStreams(); } - private static final int DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG = - AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE - | AudioSystem.DEVICE_OUT_LINE | AudioSystem.DEVICE_OUT_ALL_USB; + private static final Set<Integer> DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET; + static { + DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET = new HashSet<>(); + DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADSET); + DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE); + DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_LINE); + DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET); + } /*package*/ void onSetWiredDeviceConnectionState( AudioDeviceInventory.WiredDeviceConnectionState wdcs) { @@ -382,7 +389,7 @@ public class AudioDeviceInventory { synchronized (mConnectedDevices) { if ((wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED) - && ((wdcs.mType & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0)) { + && DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(wdcs.mType)) { mDeviceBroker.setBluetoothA2dpOnInt(true, "onSetWiredDeviceConnectionState state DISCONNECTED"); } @@ -393,7 +400,7 @@ public class AudioDeviceInventory { return; } if (wdcs.mState != AudioService.CONNECTION_STATE_DISCONNECTED) { - if ((wdcs.mType & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0) { + if (DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(wdcs.mType)) { mDeviceBroker.setBluetoothA2dpOnInt(false, "onSetWiredDeviceConnectionState state not DISCONNECTED"); } @@ -764,13 +771,19 @@ public class AudioDeviceInventory { // - none of these devices are connected anymore after one is disconnected AND // - the device being disconnected is actually used for music. // Access synchronized on mConnectedDevices - private int mBecomingNoisyIntentDevices = - AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE - | AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI - | AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET - | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET - | AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE - | AudioSystem.DEVICE_OUT_HEARING_AID; + private static final Set<Integer> BECOMING_NOISY_INTENT_DEVICES_SET; + static { + BECOMING_NOISY_INTENT_DEVICES_SET = new HashSet<>(); + BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADSET); + BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE); + BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_HDMI); + BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET); + BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET); + BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_LINE); + BECOMING_NOISY_INTENT_DEVICES_SET.add(AudioSystem.DEVICE_OUT_HEARING_AID); + BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_A2DP_SET); + BECOMING_NOISY_INTENT_DEVICES_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET); + } // must be called before removing the device from mConnectedDevices // musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying @@ -781,16 +794,16 @@ public class AudioDeviceInventory { if (state != AudioService.CONNECTION_STATE_DISCONNECTED) { return 0; } - if ((device & mBecomingNoisyIntentDevices) == 0) { + if (!BECOMING_NOISY_INTENT_DEVICES_SET.contains(device)) { return 0; } int delay = 0; - int devices = 0; + Set<Integer> devices = new HashSet<>(); for (int i = 0; i < mConnectedDevices.size(); i++) { int dev = mConnectedDevices.valueAt(i).mDeviceType; if (((dev & AudioSystem.DEVICE_BIT_IN) == 0) - && ((dev & mBecomingNoisyIntentDevices) != 0)) { - devices |= dev; + && BECOMING_NOISY_INTENT_DEVICES_SET.contains(dev)) { + devices.add(dev); } } if (musicDevice == AudioSystem.DEVICE_NONE) { @@ -801,8 +814,9 @@ public class AudioDeviceInventory { // because music routing is altered in this case. // also checks whether media routing if affected by a dynamic policy or mirroring if (((device == musicDevice) || mDeviceBroker.isInCommunication()) - && (device == devices) && !mDeviceBroker.hasMediaDynamicPolicy() - && ((musicDevice & AudioSystem.DEVICE_OUT_REMOTE_SUBMIX) == 0)) { + && AudioSystem.isSingleAudioDeviceType(devices, device) + && !mDeviceBroker.hasMediaDynamicPolicy() + && (musicDevice != AudioSystem.DEVICE_OUT_REMOTE_SUBMIX)) { if (!AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0 /*not looking in past*/) && !mDeviceBroker.hasAudioFocusUsers()) { // no media playback, not a "becoming noisy" situation, otherwise it could cause diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 9a927785bd5b..e426c6c44a07 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -147,6 +147,7 @@ import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -501,18 +502,20 @@ public class AudioService extends IAudioService.Stub private volatile IRingtonePlayer mRingtonePlayer; // Devices for which the volume is fixed (volume is either max or muted) - int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI | - AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET | - AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | - AudioSystem.DEVICE_OUT_HDMI_ARC | - AudioSystem.DEVICE_OUT_SPDIF | - AudioSystem.DEVICE_OUT_AUX_LINE; + Set<Integer> mFixedVolumeDevices = new HashSet<>(Arrays.asList( + AudioSystem.DEVICE_OUT_HDMI, + AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET, + AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET, + AudioSystem.DEVICE_OUT_HDMI_ARC, + AudioSystem.DEVICE_OUT_SPDIF, + AudioSystem.DEVICE_OUT_AUX_LINE)); // Devices for which the volume is always max, no volume panel - int mFullVolumeDevices = 0; + Set<Integer> mFullVolumeDevices = new HashSet<>(); // Devices for the which use the "absolute volume" concept (framework sends audio signal // full scale, and volume control separately) and can be used for multiple use cases reflected // by the audio mode (e.g. media playback in MODE_NORMAL, and phone calls in MODE_IN_CALL). - int mAbsVolumeMultiModeCaseDevices = AudioSystem.DEVICE_OUT_HEARING_AID; + Set<Integer> mAbsVolumeMultiModeCaseDevices = new HashSet<>( + Arrays.asList(AudioSystem.DEVICE_OUT_HEARING_AID)); private final boolean mMonitorRotation; @@ -866,13 +869,14 @@ public class AudioService extends IAudioService.Stub } mHdmiTvClient = mHdmiManager.getTvClient(); if (mHdmiTvClient != null) { - mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER; + mFixedVolumeDevices.removeAll( + AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET); } mHdmiPlaybackClient = mHdmiManager.getPlaybackClient(); if (mHdmiPlaybackClient != null) { // not a television: HDMI output will be always at max - mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI; - mFullVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI; + mFixedVolumeDevices.remove(AudioSystem.DEVICE_OUT_HDMI); + mFullVolumeDevices.add(AudioSystem.DEVICE_OUT_HDMI); } mHdmiAudioSystemClient = mHdmiManager.getAudioSystemClient(); } @@ -1131,7 +1135,7 @@ public class AudioService extends IAudioService.Stub @AudioService.ConnectionState int state, String caller) { if (state == AudioService.CONNECTION_STATE_CONNECTED) { // DEVICE_OUT_HDMI is now connected - if ((AudioSystem.DEVICE_OUT_HDMI & mSafeMediaVolumeDevices) != 0) { + if (mSafeMediaVolumeDevices.contains(AudioSystem.DEVICE_OUT_HDMI)) { sendMsg(mAudioHandler, MSG_CHECK_MUSIC_ACTIVE, SENDMSG_REPLACE, @@ -1762,8 +1766,8 @@ public class AudioService extends IAudioService.Stub // skip a2dp absolute volume control request when the device // is not an a2dp device - if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 && - (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) { + if (!AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device) + && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) { return; } @@ -1784,14 +1788,14 @@ public class AudioService extends IAudioService.Stub flags &= ~AudioManager.FLAG_FIXED_VOLUME; if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) && - ((device & mFixedVolumeDevices) != 0)) { + mFixedVolumeDevices.contains(device)) { flags |= AudioManager.FLAG_FIXED_VOLUME; // Always toggle between max safe volume and 0 for fixed volume devices where safe // volume is enforced, and max and 0 for the others. // This is simulated by stepping by the full allowed volume range if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE && - (device & mSafeMediaVolumeDevices) != 0) { + mSafeMediaVolumeDevices.contains(device)) { step = safeMediaVolumeIndex(device); } else { step = streamState.getMaxIndex(); @@ -1861,7 +1865,7 @@ public class AudioService extends IAudioService.Stub !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) { Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex); mVolumeController.postDisplaySafeVolumeWarning(flags); - } else if (((device & mFullVolumeDevices) == 0) + } else if (!mFullVolumeDevices.contains(device) && (streamState.adjustIndex(direction * step, device, caller) || streamState.mIsMuted)) { // Post message to set system volume (it in turn will post a @@ -1890,9 +1894,9 @@ public class AudioService extends IAudioService.Stub int newIndex = mStreamStates[streamType].getIndex(device); // Check if volume update should be send to AVRCP - if (streamTypeAlias == AudioSystem.STREAM_MUSIC && - (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && - (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) { + if (streamTypeAlias == AudioSystem.STREAM_MUSIC + && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device) + && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) { if (DEBUG_VOL) { Log.d(TAG, "adjustSreamVolume: postSetAvrcpAbsoluteVolumeIndex index=" + newIndex + "stream=" + streamType); @@ -1901,7 +1905,7 @@ public class AudioService extends IAudioService.Stub } // Check if volume update should be send to Hearing Aid - if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) { + if (device == AudioSystem.DEVICE_OUT_HEARING_AID) { // only modify the hearing aid attenuation when the stream to modify matches // the one expected by the hearing aid if (streamType == getHearingAidStreamType()) { @@ -1923,7 +1927,7 @@ public class AudioService extends IAudioService.Stub if (mHdmiCecSink && streamTypeAlias == AudioSystem.STREAM_MUSIC // vol change on a full volume device - && ((device & mFullVolumeDevices) != 0)) { + && mFullVolumeDevices.contains(device)) { int keyCode = KeyEvent.KEYCODE_UNKNOWN; switch (direction) { case AudioManager.ADJUST_RAISE: @@ -2291,13 +2295,17 @@ public class AudioService extends IAudioService.Stub int streamType = getHearingAidStreamType(newMode); - final int device = AudioSystem.getDevicesForStream(streamType); - if ((device & mAbsVolumeMultiModeCaseDevices) == 0) { + final Set<Integer> deviceTypes = AudioSystem.generateAudioDeviceTypesSet( + AudioSystem.getDevicesForStream(streamType)); + final Set<Integer> absVolumeMultiModeCaseDevices = AudioSystem.intersectionAudioDeviceTypes( + mAbsVolumeMultiModeCaseDevices, deviceTypes); + if (absVolumeMultiModeCaseDevices.isEmpty()) { return; } // handling of specific interfaces goes here: - if ((device & mAbsVolumeMultiModeCaseDevices) == AudioSystem.DEVICE_OUT_HEARING_AID) { + if (AudioSystem.isSingleAudioDeviceType( + absVolumeMultiModeCaseDevices, AudioSystem.DEVICE_OUT_HEARING_AID)) { final int index = getStreamVolume(streamType); sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_MODE_CHANGE_HEARING_AID, newMode, streamType, index)); @@ -2324,8 +2332,8 @@ public class AudioService extends IAudioService.Stub // skip a2dp absolute volume control request when the device // is not an a2dp device - if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 && - (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) { + if (!AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device) + && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) { return; } // If we are being called by the system (e.g. hardware keys) check for current user @@ -2357,7 +2365,7 @@ public class AudioService extends IAudioService.Stub index = rescaleIndex(index * 10, streamType, streamTypeAlias); if (streamTypeAlias == AudioSystem.STREAM_MUSIC - && (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 + && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device) && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) { if (DEBUG_VOL) { Log.d(TAG, "setStreamVolume postSetAvrcpAbsoluteVolumeIndex index=" + index @@ -2366,7 +2374,7 @@ public class AudioService extends IAudioService.Stub mDeviceBroker.postSetAvrcpAbsoluteVolumeIndex(index / 10); } - if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0 + if (device == AudioSystem.DEVICE_OUT_HEARING_AID && streamType == getHearingAidStreamType()) { Log.i(TAG, "setStreamVolume postSetHearingAidVolumeIndex index=" + index + " stream=" + streamType); @@ -2379,13 +2387,13 @@ public class AudioService extends IAudioService.Stub flags &= ~AudioManager.FLAG_FIXED_VOLUME; if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) && - ((device & mFixedVolumeDevices) != 0)) { + mFixedVolumeDevices.contains(device)) { flags |= AudioManager.FLAG_FIXED_VOLUME; // volume is either 0 or max allowed for fixed volume devices if (index != 0) { if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE && - (device & mSafeMediaVolumeDevices) != 0) { + mSafeMediaVolumeDevices.contains(device)) { index = safeMediaVolumeIndex(device); } else { index = streamState.getMaxIndex(); @@ -2568,7 +2576,7 @@ public class AudioService extends IAudioService.Stub if (streamType == AudioSystem.STREAM_MUSIC) { flags = updateFlagsForTvPlatform(flags); - if ((device & mFullVolumeDevices) != 0) { + if (mFullVolumeDevices.contains(device)) { flags &= ~AudioManager.FLAG_SHOW_UI; } } @@ -2614,7 +2622,7 @@ public class AudioService extends IAudioService.Stub int device, boolean force, String caller) { - if ((device & mFullVolumeDevices) != 0) { + if (mFullVolumeDevices.contains(device)) { return; } VolumeStreamState streamState = mStreamStates[streamType]; @@ -2731,8 +2739,8 @@ public class AudioService extends IAudioService.Stub if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) { mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb)); if (mRmtSbmxFullVolRefCount == 0) { - mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX; - mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX; + mFullVolumeDevices.add(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX); + mFixedVolumeDevices.add(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX); applyRequired = true; } mRmtSbmxFullVolRefCount++; @@ -2741,8 +2749,8 @@ public class AudioService extends IAudioService.Stub if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) { mRmtSbmxFullVolRefCount--; if (mRmtSbmxFullVolRefCount == 0) { - mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX; - mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX; + mFullVolumeDevices.remove(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX); + mFixedVolumeDevices.remove(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX); applyRequired = true; } } @@ -2824,7 +2832,7 @@ public class AudioService extends IAudioService.Stub index = 0; } if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) && - (device & mFixedVolumeDevices) != 0) { + mFixedVolumeDevices.contains(device)) { index = mStreamStates[streamType].getMaxIndex(); } return (index + 5) / 10; @@ -3699,7 +3707,7 @@ public class AudioService extends IAudioService.Stub if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) { int device = getDeviceForStream(AudioSystem.STREAM_MUSIC); - if ((device & mSafeMediaVolumeDevices) != 0) { + if (mSafeMediaVolumeDevices.contains(device)) { sendMsg(mAudioHandler, MSG_CHECK_MUSIC_ACTIVE, SENDMSG_REPLACE, @@ -4251,6 +4259,8 @@ public class AudioService extends IAudioService.Stub // retain the device on the A2DP output as the other must not correspond to an active // selection if not the speaker. // - HDMI-CEC system audio mode only output: give priority to available item in order. + // FIXME: Haven't applied audio device type refactor to this API + // as it is going to be deprecated. if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) { device = AudioSystem.DEVICE_OUT_SPEAKER; } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) { @@ -4260,7 +4270,11 @@ public class AudioService extends IAudioService.Stub } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) { device = AudioSystem.DEVICE_OUT_AUX_LINE; } else { - device &= AudioSystem.DEVICE_OUT_ALL_A2DP; + for (int deviceType : AudioSystem.DEVICE_OUT_ALL_A2DP_SET) { + if ((deviceType & device) == deviceType) { + return deviceType; + } + } } } return device; @@ -4393,12 +4407,16 @@ public class AudioService extends IAudioService.Stub mDeviceBroker.postBluetoothA2dpDeviceConfigChange(device); } - private static final int DEVICE_MEDIA_UNMUTED_ON_PLUG = - AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE | - AudioSystem.DEVICE_OUT_LINE | - AudioSystem.DEVICE_OUT_ALL_A2DP | - AudioSystem.DEVICE_OUT_ALL_USB | - AudioSystem.DEVICE_OUT_HDMI; + private static final Set<Integer> DEVICE_MEDIA_UNMUTED_ON_PLUG_SET; + static { + DEVICE_MEDIA_UNMUTED_ON_PLUG_SET = new HashSet<>(); + DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADSET); + DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE); + DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_LINE); + DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_A2DP_SET); + DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.addAll(AudioSystem.DEVICE_OUT_ALL_USB_SET); + DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.add(AudioSystem.DEVICE_OUT_HDMI); + } /** only public for mocking/spying, do not call outside of AudioService */ @VisibleForTesting @@ -4414,7 +4432,7 @@ public class AudioService extends IAudioService.Stub } if (mNm.getZenMode() != Settings.Global.ZEN_MODE_NO_INTERRUPTIONS - && (newDevice & DEVICE_MEDIA_UNMUTED_ON_PLUG) != 0 + && DEVICE_MEDIA_UNMUTED_ON_PLUG_SET.contains(newDevice) && mStreamStates[AudioSystem.STREAM_MUSIC].mIsMuted && mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(newDevice) != 0 && (newDevice & AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC)) != 0) { @@ -4543,14 +4561,7 @@ public class AudioService extends IAudioService.Stub } } synchronized (VolumeStreamState.class) { - int remainingDevices = AudioSystem.DEVICE_OUT_ALL; - - for (int i = 0; remainingDevices != 0; i++) { - int device = (1 << i); - if ((device & remainingDevices) == 0) { - continue; - } - remainingDevices &= ~device; + for (int device : AudioSystem.DEVICE_OUT_ALL_SET) { // retrieve current volume for device // if no volume stored for current stream and device, use default volume if default @@ -4610,11 +4621,12 @@ public class AudioService extends IAudioService.Stub int index; if (mIsMuted) { index = 0; - } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && isAvrcpAbsVolSupported) { + } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device) + && isAvrcpAbsVolSupported) { index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10); - } else if ((device & mFullVolumeDevices) != 0) { + } else if (mFullVolumeDevices.contains(device)) { index = (mIndexMax + 5)/10; - } else if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) { + } else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) { index = (mIndexMax + 5)/10; } else { index = (getIndex(device) + 5)/10; @@ -4632,12 +4644,12 @@ public class AudioService extends IAudioService.Stub if (device != AudioSystem.DEVICE_OUT_DEFAULT) { if (mIsMuted) { index = 0; - } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && - isAvrcpAbsVolSupported) { + } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device) + && isAvrcpAbsVolSupported) { index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10); - } else if ((device & mFullVolumeDevices) != 0) { + } else if (mFullVolumeDevices.contains(device)) { index = (mIndexMax + 5)/10; - } else if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) { + } else if (device == AudioSystem.DEVICE_OUT_HEARING_AID) { index = (mIndexMax + 5)/10; } else { index = (mIndexMap.valueAt(i) + 5)/10; @@ -4698,7 +4710,7 @@ public class AudioService extends IAudioService.Stub && device == AudioSystem.DEVICE_OUT_SPEAKER) { for (int i = 0; i < mIndexMap.size(); i++) { int otherDevice = mIndexMap.keyAt(i); - if ((otherDevice & AudioSystem.DEVICE_OUT_ALL_SCO) != 0) { + if (AudioSystem.DEVICE_OUT_ALL_SCO_SET.contains(otherDevice)) { mIndexMap.put(otherDevice, index); } } @@ -4836,8 +4848,8 @@ public class AudioService extends IAudioService.Stub for (int i = 0; i < mIndexMap.size(); i++) { int device = mIndexMap.keyAt(i); int index = mIndexMap.valueAt(i); - if (((device & mFullVolumeDevices) != 0) - || (((device & mFixedVolumeDevices) != 0) && index != 0)) { + if (mFullVolumeDevices.contains(device) + || (mFixedVolumeDevices.contains(device) && index != 0)) { mIndexMap.put(device, mIndexMax); } applyDeviceVolume_syncVSS(device, isAvrcpAbsVolSupported); @@ -5008,7 +5020,7 @@ public class AudioService extends IAudioService.Stub // that may have a different device selected int streamDevice = getDeviceForStream(streamType); if ((device != streamDevice) && isAvrcpAbsVolSupported - && ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) { + && AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device)) { mStreamStates[streamType].applyDeviceVolume_syncVSS(device, isAvrcpAbsVolSupported); } @@ -5337,7 +5349,7 @@ public class AudioService extends IAudioService.Stub } /*package*/ void checkMusicActive(int deviceType, String caller) { - if ((deviceType & mSafeMediaVolumeDevices) != 0) { + if (mSafeMediaVolumeDevices.contains(deviceType)) { sendMsg(mAudioHandler, MSG_CHECK_MUSIC_ACTIVE, SENDMSG_REPLACE, @@ -5783,9 +5795,9 @@ public class AudioService extends IAudioService.Stub // the headset is compliant to EN 60950 with a max loudness of 100dB SPL. private int mSafeUsbMediaVolumeIndex; // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced, - /*package*/ final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET - | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE - | AudioSystem.DEVICE_OUT_USB_HEADSET; + /*package*/ final Set<Integer> mSafeMediaVolumeDevices = new HashSet<>( + Arrays.asList(AudioSystem.DEVICE_OUT_WIRED_HEADSET, + AudioSystem.DEVICE_OUT_WIRED_HEADPHONE, AudioSystem.DEVICE_OUT_USB_HEADSET)); // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled. // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS. @@ -5795,7 +5807,7 @@ public class AudioService extends IAudioService.Stub private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed private int safeMediaVolumeIndex(int device) { - if ((device & mSafeMediaVolumeDevices) == 0) { + if (!mSafeMediaVolumeDevices.contains(device)) { return MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]; } if (device == AudioSystem.DEVICE_OUT_USB_HEADSET) { @@ -5830,14 +5842,9 @@ public class AudioService extends IAudioService.Stub private void enforceSafeMediaVolume(String caller) { VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC]; - int devices = mSafeMediaVolumeDevices; - int i = 0; + Set<Integer> devices = mSafeMediaVolumeDevices; - while (devices != 0) { - int device = 1 << i++; - if ((device & devices) == 0) { - continue; - } + for (int device : devices) { int index = streamState.getIndex(device); if (index > safeMediaVolumeIndex(device)) { streamState.setIndex(safeMediaVolumeIndex(device), device, caller); @@ -5849,16 +5856,15 @@ public class AudioService extends IAudioService.Stub streamState, 0); } - devices &= ~device; } } private boolean checkSafeMediaVolume(int streamType, int index, int device) { synchronized (mSafeMediaVolumeStateLock) { - if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) && - (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) && - ((device & mSafeMediaVolumeDevices) != 0) && - (index > safeMediaVolumeIndex(device))) { + if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) + && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) + && (mSafeMediaVolumeDevices.contains(device)) + && (index > safeMediaVolumeIndex(device))) { return false; } return true; @@ -5899,14 +5905,14 @@ public class AudioService extends IAudioService.Stub if (DEBUG_VOL) { Log.d(TAG, "CEC sink: setting HDMI as full vol device"); } - mFullVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI; + mFullVolumeDevices.add(AudioSystem.DEVICE_OUT_HDMI); } else { if (DEBUG_VOL) { Log.d(TAG, "TV, no CEC: setting HDMI as regular vol device"); } // Android TV devices without CEC service apply software volume on // HDMI output - mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI; + mFullVolumeDevices.remove(AudioSystem.DEVICE_OUT_HDMI); } checkAddAllFixedVolumeDevices(AudioSystem.DEVICE_OUT_HDMI, @@ -6127,6 +6133,19 @@ public class AudioService extends IAudioService.Stub pw.println(); } + private String dumpDeviceTypes(@NonNull Set<Integer> deviceTypes) { + Iterator<Integer> it = deviceTypes.iterator(); + if (!it.hasNext()) { + return ""; + } + final StringBuilder sb = new StringBuilder(); + sb.append("0x" + Integer.toHexString(it.next())); + while (it.hasNext()) { + sb.append("," + "0x" + Integer.toHexString(it.next())); + } + return sb.toString(); + } + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; @@ -6163,7 +6182,7 @@ public class AudioService extends IAudioService.Stub pw.println(mDeviceBroker.isAvrcpAbsoluteVolumeSupported()); pw.print(" mIsSingleVolume="); pw.println(mIsSingleVolume); pw.print(" mUseFixedVolume="); pw.println(mUseFixedVolume); - pw.print(" mFixedVolumeDevices=0x"); pw.println(Integer.toHexString(mFixedVolumeDevices)); + pw.print(" mFixedVolumeDevices="); pw.println(dumpDeviceTypes(mFixedVolumeDevices)); pw.print(" mHdmiCecSink="); pw.println(mHdmiCecSink); pw.print(" mHdmiAudioSystemClient="); pw.println(mHdmiAudioSystemClient); pw.print(" mHdmiPlaybackClient="); pw.println(mHdmiPlaybackClient); diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index ae5ad7ea1261..311e24fd5ee2 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -20,7 +20,7 @@ import android.app.ActivityManager; import android.app.IActivityManager; import android.content.Context; import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.os.Binder; import android.os.RemoteException; import android.os.UserHandle; @@ -32,6 +32,7 @@ import com.android.internal.compat.CompatibilityChangeConfig; import com.android.internal.compat.CompatibilityChangeInfo; import com.android.internal.compat.IPlatformCompat; import com.android.internal.util.DumpUtils; +import com.android.server.LocalServices; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -197,12 +198,8 @@ public class PlatformCompat extends IPlatformCompat.Stub { } private ApplicationInfo getApplicationInfo(String packageName, int userId) { - try { - return mContext.getPackageManager().getApplicationInfoAsUser(packageName, 0, userId); - } catch (PackageManager.NameNotFoundException e) { - Slog.e(TAG, "No installed package " + packageName); - } - return null; + return LocalServices.getService(PackageManagerInternal.class).getApplicationInfo( + packageName, 0, userId, userId); } private void reportChange(long changeId, int uid, int state) { @@ -210,11 +207,11 @@ public class PlatformCompat extends IPlatformCompat.Stub { } private void killPackage(String packageName) { - int uid = -1; - try { - uid = mContext.getPackageManager().getPackageUid(packageName, 0); - } catch (PackageManager.NameNotFoundException e) { - Slog.w(TAG, "Didn't find package " + packageName + " on device.", e); + int uid = LocalServices.getService(PackageManagerInternal.class).getPackageUid(packageName, + 0, UserHandle.myUserId()); + + if (uid < 0) { + Slog.w(TAG, "Didn't find package " + packageName + " on device."); return; } diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java index d13e6753d1b0..bc83780ad82d 100644 --- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java +++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java @@ -18,6 +18,7 @@ package com.android.server.connectivity; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import android.app.Notification; @@ -89,14 +90,22 @@ public class NetworkNotificationManager { mNotificationTypeMap = new SparseIntArray(); } + @VisibleForTesting + protected static int approximateTransportType(NetworkAgentInfo nai) { + return nai.isVPN() ? TRANSPORT_VPN : getFirstTransportType(nai); + } + // TODO: deal more gracefully with multi-transport networks. private static int getFirstTransportType(NetworkAgentInfo nai) { + // TODO: The range is wrong, the safer and correct way is to change the range from + // MIN_TRANSPORT to MAX_TRANSPORT. for (int i = 0; i < 64; i++) { if (nai.networkCapabilities.hasTransport(i)) return i; } return -1; } + // TODO: Remove @TransportType or change it to @Transport. private static String getTransportName(@TransportType int transportType) { Resources r = Resources.getSystem(); String[] networkTypes = r.getStringArray(R.array.network_switch_type_name); @@ -146,7 +155,7 @@ public class NetworkNotificationManager { final int transportType; final String name; if (nai != null) { - transportType = getFirstTransportType(nai); + transportType = approximateTransportType(nai); final String extraInfo = nai.networkInfo.getExtraInfo(); name = TextUtils.isEmpty(extraInfo) ? nai.networkCapabilities.getSSID() : extraInfo; // Only notify for Internet-capable networks. @@ -175,7 +184,7 @@ public class NetworkNotificationManager { tag, nameOf(eventId), getTransportName(transportType), name, highPriority)); } - Resources r = Resources.getSystem(); + Resources r = mContext.getResources(); final CharSequence title; final CharSequence details; int icon = getIcon(transportType, notifyType); @@ -239,7 +248,7 @@ public class NetworkNotificationManager { details = r.getString(R.string.captive_portal_logged_in_detailed); } else if (notifyType == NotificationType.NETWORK_SWITCH) { String fromTransport = getTransportName(transportType); - String toTransport = getTransportName(getFirstTransportType(switchToNai)); + String toTransport = getTransportName(approximateTransportType(switchToNai)); title = r.getString(R.string.network_switch_metered, toTransport); details = r.getString(R.string.network_switch_metered_detail, toTransport, fromTransport); @@ -340,8 +349,8 @@ public class NetworkNotificationManager { } public void showToast(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) { - String fromTransport = getTransportName(getFirstTransportType(fromNai)); - String toTransport = getTransportName(getFirstTransportType(toNai)); + String fromTransport = getTransportName(approximateTransportType(fromNai)); + String toTransport = getTransportName(approximateTransportType(toNai)); String text = mContext.getResources().getString( R.string.network_switch_metered_toast, fromTransport, toTransport); Toast.makeText(mContext, text, Toast.LENGTH_LONG).show(); diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java index 29c4bad2e172..56f4959a9714 100644 --- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java +++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java @@ -229,22 +229,22 @@ public class PermissionMonitor { } @VisibleForTesting - boolean hasPermission(PackageInfo app, String permission) { - if (app.requestedPermissions != null) { - for (String p : app.requestedPermissions) { - if (permission.equals(p)) { - return true; - } - } + boolean hasPermission(@NonNull final PackageInfo app, @NonNull final String permission) { + if (app.requestedPermissions == null || app.requestedPermissionsFlags == null) { + return false; } - return false; + final int index = ArrayUtils.indexOf(app.requestedPermissions, permission); + if (index < 0 || index >= app.requestedPermissionsFlags.length) return false; + return (app.requestedPermissionsFlags[index] & REQUESTED_PERMISSION_GRANTED) != 0; } - private boolean hasNetworkPermission(PackageInfo app) { + @VisibleForTesting + boolean hasNetworkPermission(@NonNull final PackageInfo app) { return hasPermission(app, CHANGE_NETWORK_STATE); } - private boolean hasRestrictedNetworkPermission(PackageInfo app) { + @VisibleForTesting + boolean hasRestrictedNetworkPermission(@NonNull final PackageInfo app) { // TODO : remove this check in the future(b/31479477). All apps should just // request the appropriate permission for their use case since android Q. if (app.applicationInfo != null) { @@ -260,33 +260,18 @@ public class PermissionMonitor { } } return hasPermission(app, CONNECTIVITY_INTERNAL) - || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS); - } - - private boolean hasUseBackgroundNetworksPermission(PackageInfo app) { - // This function defines what it means to hold the permission to use - // background networks. - return hasPermission(app, CHANGE_NETWORK_STATE) || hasPermission(app, NETWORK_STACK) - || hasRestrictedNetworkPermission(app); + || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS); } - public boolean hasUseBackgroundNetworksPermission(int uid) { - final String[] names = mPackageManager.getPackagesForUid(uid); - if (null == names || names.length == 0) return false; - try { - // Only using the first package name. There may be multiple names if multiple - // apps share the same UID, but in that case they also share permissions so - // querying with any of the names will return the same results. - int userId = UserHandle.getUserId(uid); - final PackageInfo app = mPackageManager.getPackageInfoAsUser( - names[0], GET_PERMISSIONS, userId); - return hasUseBackgroundNetworksPermission(app); - } catch (NameNotFoundException e) { - // App not found. - loge("NameNotFoundException " + names[0], e); - return false; - } + /** Returns whether the given uid has using background network permission. */ + public synchronized boolean hasUseBackgroundNetworksPermission(final int uid) { + // Apps with any of the CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_INTERNAL or + // CONNECTIVITY_USE_RESTRICTED_NETWORKS permission has the permission to use background + // networks. mApps contains the result of checks for both hasNetworkPermission and + // hasRestrictedNetworkPermission. If uid is in the mApps list that means uid has one of + // permissions at least. + return mApps.containsKey(uid); } private int[] toIntArray(Collection<Integer> list) { diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java index ac906bb23d32..eaae2ed40b2e 100644 --- a/services/core/java/com/android/server/lights/LightsService.java +++ b/services/core/java/com/android/server/lights/LightsService.java @@ -84,8 +84,12 @@ public class LightsService extends SystemService { if (DEBUG) { Slog.d(TAG, "Using new setBrightness path!"); } - SurfaceControl.setDisplayBrightness(mDisplayToken, - (float) brightness / mSurfaceControlMaximumBrightness); + if (brightness == 0) { + SurfaceControl.setDisplayBrightness(mDisplayToken, -1.0f); + } else { + SurfaceControl.setDisplayBrightness(mDisplayToken, + (float) (brightness - 1) / (mSurfaceControlMaximumBrightness - 1)); + } } else { int color = brightness & 0x000000ff; color = 0xff000000 | (color << 16) | (color << 8) | color; diff --git a/services/core/java/com/android/server/location/LocationSettingsStore.java b/services/core/java/com/android/server/location/LocationSettingsStore.java index a4b6d97e9471..dc5628e0a4eb 100644 --- a/services/core/java/com/android/server/location/LocationSettingsStore.java +++ b/services/core/java/com/android/server/location/LocationSettingsStore.java @@ -237,9 +237,6 @@ public class LocationSettingsStore { IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); int userId = ActivityManager.getCurrentUser(); - ipw.println("--Location Settings--"); - ipw.increaseIndent(); - ipw.print("Location Enabled: "); ipw.println(isLocationEnabled(userId)); diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 7820cd705193..2cf920d1aba4 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -83,6 +83,24 @@ class MediaRouter2ServiceImpl { mContext = context; } + @NonNull + public List<MediaRoute2Info> getSystemRoutes() { + final int uid = Binder.getCallingUid(); + final int userId = UserHandle.getUserId(uid); + + Collection<MediaRoute2Info> systemRoutes; + synchronized (mLock) { + UserRecord userRecord = mUserRecords.get(userId); + if (userRecord == null) { + userRecord = new UserRecord(userId); + mUserRecords.put(userId, userRecord); + initializeUserLocked(userRecord); + } + systemRoutes = userRecord.mHandler.mSystemProvider.getProviderInfo().getRoutes(); + } + return new ArrayList<>(systemRoutes); + } + public void registerClient(@NonNull IMediaRouter2Client client, @NonNull String packageName) { Objects.requireNonNull(client, "client must not be null"); diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index ecc1abaa2cdf..9336af427452 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -443,6 +443,12 @@ public final class MediaRouterService extends IMediaRouterService.Stub // Binder call @Override + public List<MediaRoute2Info> getSystemRoutes() { + return mService2.getSystemRoutes(); + } + + // Binder call + @Override public void registerClient2(IMediaRouter2Client client, String packageName) { final int uid = Binder.getCallingUid(); if (!validatePackageName(uid, packageName)) { diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java index 620775e4aaba..4f64177ad135 100644 --- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java @@ -42,8 +42,8 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { private static final String TAG = "MR2SystemProvider"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private static final String DEFAULT_ROUTE_ID = "DEFAULT_ROUTE"; - private static final String BLUETOOTH_ROUTE_ID = "BLUETOOTH_ROUTE"; + static final String DEFAULT_ROUTE_ID = "DEFAULT_ROUTE"; + static final String BLUETOOTH_ROUTE_ID = "BLUETOOTH_ROUTE"; // TODO: Move these to a proper place public static final String CATEGORY_LIVE_AUDIO = "android.media.intent.category.LIVE_AUDIO"; @@ -191,12 +191,20 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { publishRoutes(); } + + /** + * The first route should be the currently selected system route. + * For example, if there are two system routes (BT and device speaker), + * BT will be the first route in the list. + * + * TODO: Support multiple BT devices + */ void publishRoutes() { - MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder() - .addRoute(mDefaultRoute); + MediaRoute2ProviderInfo.Builder builder = new MediaRoute2ProviderInfo.Builder(); if (mBluetoothA2dpRoute != null) { builder.addRoute(mBluetoothA2dpRoute); } + builder.addRoute(mDefaultRoute); setAndNotifyProviderInfo(builder.build()); } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index b60306be86c1..d5f2d7e550d7 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2083,10 +2083,10 @@ public class NotificationManagerService extends SystemService { @Override public void updateAutogroupSummary(String key, boolean needsOngoingFlag) { - String pkg = null; + String pkg; synchronized (mNotificationLock) { NotificationRecord r = mNotificationsByKey.get(key); - pkg = r.sbn.getPackageName(); + pkg = r != null && r.sbn != null ? r.sbn.getPackageName() : null; } boolean isAppForeground = pkg != null && mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND; diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index 44c36ee01bbf..4f9b3962a9ea 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -209,6 +209,13 @@ abstract class ApexManager { abstract boolean abortActiveSession(); /** + * Abandons the staged session with the given sessionId. + * + * @return {@code true} upon success, {@code false} if any remote exception occurs + */ + abstract boolean abortStagedSession(int sessionId) throws PackageManagerException; + + /** * Uninstalls given {@code apexPackage}. * * <p>NOTE. Device must be rebooted in order for uninstall to take effect. @@ -496,6 +503,21 @@ abstract class ApexManager { } @Override + boolean abortStagedSession(int sessionId) throws PackageManagerException { + try { + mApexService.abortStagedSession(sessionId); + return true; + } catch (RemoteException re) { + Slog.e(TAG, "Unable to contact apexservice", re); + return false; + } catch (Exception e) { + throw new PackageManagerException( + PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, + "Failed to abort staged session : " + e.getMessage()); + } + } + + @Override boolean uninstallApex(String apexPackagePath) { try { mApexService.unstagePackages(Collections.singletonList(apexPackagePath)); @@ -683,6 +705,11 @@ abstract class ApexManager { } @Override + boolean abortStagedSession(int sessionId) throws PackageManagerException { + throw new UnsupportedOperationException(); + } + + @Override boolean uninstallApex(String apexPackagePath) { throw new UnsupportedOperationException(); } diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java index 08e55d3b766b..c7124314cae0 100644 --- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java +++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java @@ -34,8 +34,6 @@ import android.os.ServiceManager; import android.os.SystemProperties; import android.os.UserHandle; import android.os.storage.StorageManager; -import android.provider.DeviceConfig; -import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; import android.util.StatsLog; @@ -86,12 +84,6 @@ public class BackgroundDexOptService extends JobService { // Used for calculating space threshold for downgrading unused apps. private static final int LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE = 2; - private static final int DEFAULT_INACTIVE_APP_THRESHOLD_DAYS = 10; - - private static final String DOWNGRADE_UNUSED_APPS_ENABLED = "downgrade_unused_apps_enabled"; - private static final String INACTIVE_APP_THRESHOLD_DAYS = "inactive_app_threshold_days"; - private static final String LOW_STORAGE_MULTIPLIER_FOR_DOWNGRADE = - "low_storage_threshold_multiplier_for_downgrade"; /** * Set of failed packages remembered across job runs. @@ -111,6 +103,8 @@ public class BackgroundDexOptService extends JobService { private final AtomicBoolean mExitPostBootUpdate = new AtomicBoolean(false); private final File mDataDir = Environment.getDataDirectory(); + private static final long mDowngradeUnusedAppsThresholdInMillis = + getDowngradeUnusedAppsThresholdInMillis(); public static void schedule(Context context) { if (isBackgroundDexoptDisabled()) { @@ -352,14 +346,14 @@ public class BackgroundDexOptService extends JobService { // Only downgrade apps when space is low on device. // Threshold is selected above the lowStorageThreshold so that we can pro-actively clean // up disk before user hits the actual lowStorageThreshold. - final long lowStorageThresholdForDowngrade = getLowThresholdMultiplierForDowngrade() + final long lowStorageThresholdForDowngrade = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE * lowStorageThreshold; boolean shouldDowngrade = shouldDowngrade(lowStorageThresholdForDowngrade); Log.d(TAG, "Should Downgrade " + shouldDowngrade); if (shouldDowngrade) { Set<String> unusedPackages = - pm.getUnusedPackages(getDowngradeUnusedAppsThresholdInMillis()); - Log.d(TAG, "Unused Packages " + String.join(",", unusedPackages)); + pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis); + Log.d(TAG, "Unsused Packages " + String.join(",", unusedPackages)); if (!unusedPackages.isEmpty()) { for (String pkg : unusedPackages) { @@ -368,9 +362,12 @@ public class BackgroundDexOptService extends JobService { // Should be aborted by the scheduler. return abortCode; } - if (downgradePackage(pm, pkg)) { + if (downgradePackage(pm, pkg, /*isForPrimaryDex*/ true)) { updatedPackages.add(pkg); } + if (supportSecondaryDex) { + downgradePackage(pm, pkg, /*isForPrimaryDex*/ false); + } } pkgs = new ArraySet<>(pkgs); @@ -418,45 +415,39 @@ public class BackgroundDexOptService extends JobService { * Try to downgrade the package to a smaller compilation filter. * eg. if the package is in speed-profile the package will be downgraded to verify. * @param pm PackageManagerService - * @param pkg The package to be downgraded - * @return true if the package was downgraded + * @param pkg The package to be downgraded. + * @param isForPrimaryDex. Apps can have several dex file, primary and secondary. + * @return true if the package was downgraded. */ - private boolean downgradePackage(PackageManagerService pm, String pkg) { + private boolean downgradePackage(PackageManagerService pm, String pkg, + boolean isForPrimaryDex) { Log.d(TAG, "Downgrading " + pkg); - boolean downgradedPrimary = false; + boolean dex_opt_performed = false; int reason = PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE; int dexoptFlags = DexoptOptions.DEXOPT_BOOT_COMPLETE | DexoptOptions.DEXOPT_IDLE_BACKGROUND_JOB | DexoptOptions.DEXOPT_DOWNGRADE; - long package_size_before = getPackageSize(pm, pkg); - // An aggressive downgrade deletes the oat files. - boolean aggressive = false; - // This applies for system apps or if packages location is not a directory, i.e. - // monolithic install. - if (!pm.canHaveOatDir(pkg)) { - // For apps that don't have the oat directory, instead of downgrading, - // remove their compiler artifacts from dalvik cache. - pm.deleteOatArtifactsOfPackage(pkg); - aggressive = true; - downgradedPrimary = true; - } else { - downgradedPrimary = performDexOptPrimary(pm, pkg, reason, dexoptFlags); - if (supportSecondaryDex()) { - performDexOptSecondary(pm, pkg, reason, dexoptFlags); + if (isForPrimaryDex) { + // This applies for system apps or if packages location is not a directory, i.e. + // monolithic install. + if (!pm.canHaveOatDir(pkg)) { + // For apps that don't have the oat directory, instead of downgrading, + // remove their compiler artifacts from dalvik cache. + pm.deleteOatArtifactsOfPackage(pkg); + } else { + dex_opt_performed = performDexOptPrimary(pm, pkg, reason, dexoptFlags); } + } else { + dex_opt_performed = performDexOptSecondary(pm, pkg, reason, dexoptFlags); } - // This metric aims to log the storage savings when downgrading. - // The way disk size is measured using getPackageSize only looks at the primary apks. - // Any logs that are due to secondary dex files will show 0% size reduction and pollute - // the metrics. - if (downgradedPrimary) { + if (dex_opt_performed) { StatsLog.write(StatsLog.APP_DOWNGRADED, pkg, package_size_before, - getPackageSize(pm, pkg), aggressive); + getPackageSize(pm, pkg), /*aggressive=*/ false); } - return downgradedPrimary; + return dex_opt_performed; } private boolean supportSecondaryDex() { @@ -480,7 +471,7 @@ public class BackgroundDexOptService extends JobService { * concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized. * @param pm An instance of PackageManagerService * @param pkg The package to be downgraded. - * @param isForPrimaryDex Apps can have several dex file, primary and secondary. + * @param isForPrimaryDex. Apps can have several dex file, primary and secondary. * @return true if the package was downgraded. */ private boolean optimizePackage(PackageManagerService pm, String pkg, @@ -597,6 +588,12 @@ public class BackgroundDexOptService extends JobService { // the checks above. This check is not "live" - the value is determined by a background // restart with a period of ~1 minute. PackageManagerService pm = (PackageManagerService)ServiceManager.getService("package"); + if (pm.isStorageLow()) { + if (DEBUG_DEXOPT) { + Log.i(TAG, "Low storage, skipping this run"); + } + return false; + } final ArraySet<String> pkgs = pm.getOptimizablePackages(); if (pkgs.isEmpty()) { @@ -646,77 +643,17 @@ public class BackgroundDexOptService extends JobService { } private static long getDowngradeUnusedAppsThresholdInMillis() { - long defaultValue = Long.MAX_VALUE; - if (isDowngradeFeatureEnabled()) { - return getInactiveAppsThresholdMillis(); - } final String sysPropKey = "pm.dexopt.downgrade_after_inactive_days"; String sysPropValue = SystemProperties.get(sysPropKey); if (sysPropValue == null || sysPropValue.isEmpty()) { Log.w(TAG, "SysProp " + sysPropKey + " not set"); - return defaultValue; - } - try { - return TimeUnit.DAYS.toMillis(Long.parseLong(sysPropValue)); - } catch (NumberFormatException e) { - Log.w(TAG, "Couldn't parse long for pm.dexopt.downgrade_after_inactive_days: " - + sysPropValue + ". Returning default value instead."); - return defaultValue; + return Long.MAX_VALUE; } + return TimeUnit.DAYS.toMillis(Long.parseLong(sysPropValue)); } private static boolean isBackgroundDexoptDisabled() { return SystemProperties.getBoolean("pm.dexopt.disable_bg_dexopt" /* key */, false /* default */); } - - private static boolean isDowngradeFeatureEnabled() { - // DeviceConfig enables the control of on device features via remotely configurable flags, - // compared to SystemProperties which is only a way of sharing info system-widely, but are - // not configurable on the server-side. - String downgradeUnusedAppsEnabledFlag = - DeviceConfig.getProperty( - DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE, - DOWNGRADE_UNUSED_APPS_ENABLED); - return !TextUtils.isEmpty(downgradeUnusedAppsEnabledFlag) - && Boolean.parseBoolean(downgradeUnusedAppsEnabledFlag); - } - - private static long getInactiveAppsThresholdMillis() { - long defaultValue = TimeUnit.DAYS.toMillis(DEFAULT_INACTIVE_APP_THRESHOLD_DAYS); - String inactiveAppThresholdDaysFlag = - DeviceConfig.getProperty(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE, - INACTIVE_APP_THRESHOLD_DAYS); - if (!TextUtils.isEmpty(inactiveAppThresholdDaysFlag)) { - try { - return TimeUnit.DAYS.toMillis(Long.parseLong(inactiveAppThresholdDaysFlag)); - } catch (NumberFormatException e) { - Log.w(TAG, "Couldn't parse long for " + INACTIVE_APP_THRESHOLD_DAYS + " flag: " - + inactiveAppThresholdDaysFlag + ". Returning default value instead."); - return defaultValue; - } - } - return defaultValue; - } - - private static int getLowThresholdMultiplierForDowngrade() { - int defaultValue = LOW_THRESHOLD_MULTIPLIER_FOR_DOWNGRADE; - if (isDowngradeFeatureEnabled()) { - String lowStorageThresholdMultiplierFlag = - DeviceConfig.getProperty(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE, - LOW_STORAGE_MULTIPLIER_FOR_DOWNGRADE); - if (!TextUtils.isEmpty(lowStorageThresholdMultiplierFlag)) { - try { - return Integer.parseInt(lowStorageThresholdMultiplierFlag); - } catch (NumberFormatException e) { - Log.w(TAG, "Couldn't parse long for " - + LOW_STORAGE_MULTIPLIER_FOR_DOWNGRADE + " flag: " - + lowStorageThresholdMultiplierFlag - + ". Returning default value instead."); - return defaultValue; - } - } - } - return defaultValue; - } } diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java index d6108b7cc390..d2a6b42f3140 100644 --- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java +++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java @@ -202,6 +202,7 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub { final List<ResolveInfo> apps = mInjector.getPackageManagerInternal().queryIntentActivities( launchIntent, + launchIntent.resolveTypeIfNeeded(mContext.getContentResolver()), MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, callingUid, userId); diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index bd9566728b1b..f7fd1b2ddb37 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -344,6 +344,7 @@ public class LauncherAppsService extends SystemService { final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class); List<ResolveInfo> apps = pmInt.queryIntentActivities(intent, + intent.resolveTypeIfNeeded(mContext.getContentResolver()), PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, callingUid, user.getIdentifier()); @@ -468,6 +469,7 @@ public class LauncherAppsService extends SystemService { matchIntent.addCategory(Intent.CATEGORY_LAUNCHER); matchIntent.setPackage(packageName); final List<ResolveInfo> infoList = pmInt.queryIntentActivities(matchIntent, + matchIntent.resolveTypeIfNeeded(mContext.getContentResolver()), PackageManager.MATCH_DISABLED_COMPONENTS, Binder.getCallingUid(), getCallingUserId()); final int size = infoList.size(); @@ -539,6 +541,7 @@ public class LauncherAppsService extends SystemService { final PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class); List<ResolveInfo> apps = pmInt.queryIntentActivities(intent, + intent.resolveTypeIfNeeded(mContext.getContentResolver()), PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, callingUid, user.getIdentifier()); @@ -842,6 +845,7 @@ public class LauncherAppsService extends SystemService { // as calling startActivityAsUser ignores the category and just // resolves based on the component if present. List<ResolveInfo> apps = pmInt.queryIntentActivities(launchIntent, + launchIntent.resolveTypeIfNeeded(mContext.getContentResolver()), PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, callingUid, user.getIdentifier()); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index fa98c962afbf..eebc8d7db81f 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -13218,10 +13218,6 @@ public class PackageManagerService extends IPackageManager.Stub // Check if installing from ADB if ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0) { - // Do not run verification in a test harness environment - if (ActivityManager.isRunningInTestHarness()) { - return false; - } if (isUserRestricted(userId, UserManager.ENSURE_VERIFY_APPS)) { return true; } @@ -22874,39 +22870,79 @@ public class PackageManagerService extends IPackageManager.Stub return pkg == null ? null : pkg.packageName; } + /** + * Only keep package names that refer to {@link PackageParser.Package#isSystem system} + * packages. + * + * @param pkgNames The packages to filter + * + * @return The filtered packages + */ + private @NonNull String[] filterOnlySystemPackages(@Nullable String... pkgNames) { + if (pkgNames == null) { + return ArrayUtils.emptyArray(String.class); + } + + ArrayList<String> systemPackageNames = new ArrayList<>(pkgNames.length); + + for (String pkgName: pkgNames) { + synchronized (mPackages) { + if (pkgName == null) { + continue; + } + + PackageParser.Package pkg = getPackage(pkgName); + if (pkg == null) { + Log.w(TAG, "Could not find package " + pkgName); + continue; + } + + if (!pkg.isSystem()) { + Log.w(TAG, pkgName + " is not system"); + continue; + } + + systemPackageNames.add(pkgName); + } + } + + return systemPackageNames.toArray(new String[]{}); + } + @Override public @NonNull String[] getKnownPackageNames(int knownPackage, int userId) { - switch(knownPackage) { + switch (knownPackage) { case PackageManagerInternal.PACKAGE_BROWSER: return new String[]{mPermissionManager.getDefaultBrowser(userId)}; case PackageManagerInternal.PACKAGE_INSTALLER: - return new String[]{mRequiredInstallerPackage}; + return filterOnlySystemPackages(mRequiredInstallerPackage); case PackageManagerInternal.PACKAGE_SETUP_WIZARD: - return new String[]{mSetupWizardPackage}; + return filterOnlySystemPackages(mSetupWizardPackage); case PackageManagerInternal.PACKAGE_SYSTEM: return new String[]{"android"}; case PackageManagerInternal.PACKAGE_VERIFIER: - return new String[]{mRequiredVerifierPackage}; + return filterOnlySystemPackages(mRequiredVerifierPackage); case PackageManagerInternal.PACKAGE_SYSTEM_TEXT_CLASSIFIER: - return new String[]{mSystemTextClassifierPackage}; + return filterOnlySystemPackages(mSystemTextClassifierPackage); case PackageManagerInternal.PACKAGE_PERMISSION_CONTROLLER: - return new String[]{mRequiredPermissionControllerPackage}; + return filterOnlySystemPackages(mRequiredPermissionControllerPackage); case PackageManagerInternal.PACKAGE_WELLBEING: - return new String[]{mWellbeingPackage}; + return filterOnlySystemPackages(mWellbeingPackage); case PackageManagerInternal.PACKAGE_DOCUMENTER: - return new String[]{mDocumenterPackage}; + return filterOnlySystemPackages(mDocumenterPackage); case PackageManagerInternal.PACKAGE_CONFIGURATOR: - return new String[]{mConfiguratorPackage}; + return filterOnlySystemPackages(mConfiguratorPackage); case PackageManagerInternal.PACKAGE_INCIDENT_REPORT_APPROVER: - return new String[]{mIncidentReportApproverPackage}; + return filterOnlySystemPackages(mIncidentReportApproverPackage); case PackageManagerInternal.PACKAGE_APP_PREDICTOR: - return new String[]{mAppPredictionServicePackage}; + return filterOnlySystemPackages(mAppPredictionServicePackage); case PackageManagerInternal.PACKAGE_TELEPHONY: - return mTelephonyPackages; + return filterOnlySystemPackages(mTelephonyPackages); case PackageManagerInternal.PACKAGE_WIFI: - return new String[]{mWifiPackage}; + return filterOnlySystemPackages(mWifiPackage); + default: + return ArrayUtils.emptyArray(String.class); } - return ArrayUtils.emptyArray(String.class); } @Override @@ -23061,8 +23097,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public List<ResolveInfo> queryIntentActivities( - Intent intent, int flags, int filterCallingUid, int userId) { - final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver()); + Intent intent, String resolvedType, int flags, int filterCallingUid, int userId) { return PackageManagerService.this .queryIntentActivitiesInternal(intent, resolvedType, flags, filterCallingUid, userId, false /*resolveForStart*/, true /*allowDynamicSplits*/); diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 5f3650c21b8e..69c7cf2fc0f2 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -3348,7 +3348,8 @@ public final class Settings { int flags, ComponentName cn, String scheme, PatternMatcher ssp, IntentFilter.AuthorityEntry auth, PatternMatcher path, int userId) { final List<ResolveInfo> ri = - pmInternal.queryIntentActivities(intent, flags, Binder.getCallingUid(), 0); + pmInternal.queryIntentActivities( + intent, intent.getType(), flags, Binder.getCallingUid(), 0); if (PackageManagerService.DEBUG_PREFERRED) { Log.d(TAG, "Queried " + intent + " results: " + ri); } diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 3390ca780e7d..845f06d1ce5f 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -45,6 +45,7 @@ import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.storage.StorageManager; import android.util.IntArray; import android.util.Slog; import android.util.SparseArray; @@ -75,6 +76,7 @@ public class StagingManager { private final PackageInstallerService mPi; private final ApexManager mApexManager; private final PowerManager mPowerManager; + private final Context mContext; private final PreRebootVerificationHandler mPreRebootVerificationHandler; @GuardedBy("mStagedSessions") @@ -83,6 +85,7 @@ public class StagingManager { StagingManager(PackageInstallerService pi, ApexManager am, Context context) { mPi = pi; mApexManager = am; + mContext = context; mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); mPreRebootVerificationHandler = new PreRebootVerificationHandler( BackgroundThread.get().getLooper()); @@ -212,7 +215,7 @@ public class StagingManager { } final long activeVersion = activePackage.applicationInfo.longVersionCode; if (activeVersion != session.params.requiredInstalledVersionCode) { - if (!mApexManager.abortActiveSession()) { + if (!mApexManager.abortStagedSession(session.sessionId)) { Slog.e(TAG, "Failed to abort apex session " + session.sessionId); } throw new PackageManagerException( @@ -231,7 +234,7 @@ public class StagingManager { final boolean allowsDowngrade = PackageManagerServiceUtils.isDowngradePermitted( session.params.installFlags, activePackage.applicationInfo.flags); if (activeVersion > newVersionCode && !allowsDowngrade) { - if (!mApexManager.abortActiveSession()) { + if (!mApexManager.abortStagedSession(session.sessionId)) { Slog.e(TAG, "Failed to abort apex session " + session.sessionId); } throw new PackageManagerException( @@ -539,6 +542,10 @@ public class StagingManager { mPreRebootVerificationHandler.startPreRebootVerification(session.sessionId); } + private int parentOrOwnSessionId(PackageInstallerSession session) { + return session.hasParentSessionId() ? session.getParentSessionId() : session.sessionId; + } + /** * <p> Check if the session provided is non-overlapping with the active staged sessions. * @@ -561,6 +568,9 @@ public class StagingManager { "Cannot stage session " + session.sessionId + " with package name null"); } + boolean supportsCheckpoint = ((StorageManager) mContext.getSystemService( + Context.STORAGE_SERVICE)).isCheckpointSupported(); + synchronized (mStagedSessions) { for (int i = 0; i < mStagedSessions.size(); i++) { final PackageInstallerSession stagedSession = mStagedSessions.valueAt(i); @@ -601,7 +611,17 @@ public class StagingManager { + stagedSession.sessionId, null); } - // TODO(b/141843321): Add support for staging multiple sessions in apexd + // Staging multiple root sessions is not allowed if device doesn't support + // checkpoint. If session and stagedSession do not have common ancestor, they are + // from two different root sessions. + if (!supportsCheckpoint + && parentOrOwnSessionId(session) != parentOrOwnSessionId(stagedSession)) { + throw new PackageManagerException( + PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS, + "Cannot stage multiple sessions without checkpoint support", null); + } + + // TODO:b/141843321 Add support for staging multiple sessions in apexd // Since apexd doesn't support multiple staged sessions yet, we have to careful how // we handle apex sessions. We want to allow a set of apex sessions under the same // parent to be staged when there is no previously staged apex sessions. @@ -658,7 +678,10 @@ public class StagingManager { + " because it is not active or APEXD is not reachable"); return; } - mApexManager.abortActiveSession(); + try { + mApexManager.abortStagedSession(session.sessionId); + } catch (Exception ignore) { + } } } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 5e1d93fdda3d..3e528f48b6e3 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -3334,27 +3334,17 @@ public class PhoneWindowManager implements WindowManagerPolicy { return; } Bundle args = null; - if (deviceId > Integer.MIN_VALUE) { + if (deviceId > Integer.MIN_VALUE || hint != null) { args = new Bundle(); - args.putInt(Intent.EXTRA_ASSIST_INPUT_DEVICE_ID, deviceId); - } - if ((mContext.getResources().getConfiguration().uiMode - & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION) { - // On TV, use legacy handling until assistants are implemented in the proper way. - ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE)) - .launchLegacyAssist(hint, mCurrentUserId, args); - } else { + if (deviceId > Integer.MIN_VALUE) { + args.putInt(Intent.EXTRA_ASSIST_INPUT_DEVICE_ID, deviceId); + } if (hint != null) { - if (args == null) { - args = new Bundle(); - } args.putBoolean(hint, true); } - StatusBarManagerInternal statusbar = getStatusBarManagerInternal(); - if (statusbar != null) { - statusbar.startAssist(args); - } } + ((SearchManager) mContext.createContextAsUser(UserHandle.of(mCurrentUserId), 0) + .getSystemService(Context.SEARCH_SERVICE)).launchAssist(args); } /** Launches ACTION_VOICE_ASSIST. Does nothing on keyguard. */ diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java index d78aaa5f9c9d..fdb14be6b1a4 100644 --- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java +++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java @@ -27,6 +27,7 @@ import android.os.RemoteException; import android.os.SystemProperties; import android.util.Slog; +import com.android.internal.annotations.VisibleForTesting; import com.android.server.SystemService; import libcore.io.IoUtils; @@ -35,6 +36,7 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.FileWriter; import java.io.IOException; +import java.nio.charset.StandardCharsets; /** * The recovery system service is responsible for coordinating recovery related @@ -43,7 +45,7 @@ import java.io.IOException; * triggers /system/bin/uncrypt via init to de-encrypt an OTA package on the * /data partition so that it can be accessed under the recovery image. */ -public final class RecoverySystemService extends SystemService { +public class RecoverySystemService extends IRecoverySystem.Stub { private static final String TAG = "RecoverySystemService"; private static final boolean DEBUG = false; @@ -51,191 +53,321 @@ public final class RecoverySystemService extends SystemService { private static final String UNCRYPT_SOCKET = "uncrypt"; // The init services that communicate with /system/bin/uncrypt. - private static final String INIT_SERVICE_UNCRYPT = "init.svc.uncrypt"; - private static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb"; - private static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb"; + @VisibleForTesting + static final String INIT_SERVICE_UNCRYPT = "init.svc.uncrypt"; + @VisibleForTesting + static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb"; + @VisibleForTesting + static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb"; + + private static final Object sRequestLock = new Object(); private static final int SOCKET_CONNECTION_MAX_RETRY = 30; - private static final Object sRequestLock = new Object(); + private final Injector mInjector; + private final Context mContext; + + static class Injector { + protected final Context mContext; + + Injector(Context context) { + mContext = context; + } + + public Context getContext() { + return mContext; + } + + public PowerManager getPowerManager() { + return (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + } - private Context mContext; + public String systemPropertiesGet(String key) { + return SystemProperties.get(key); + } - public RecoverySystemService(Context context) { - super(context); - mContext = context; + public void systemPropertiesSet(String key, String value) { + SystemProperties.set(key, value); + } + + public boolean uncryptPackageFileDelete() { + return RecoverySystem.UNCRYPT_PACKAGE_FILE.delete(); + } + + public String getUncryptPackageFileName() { + return RecoverySystem.UNCRYPT_PACKAGE_FILE.getName(); + } + + public FileWriter getUncryptPackageFileWriter() throws IOException { + return new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE); + } + + public UncryptSocket connectService() { + UncryptSocket socket = new UncryptSocket(); + if (!socket.connectService()) { + socket.close(); + return null; + } + return socket; + } + + public void threadSleep(long millis) throws InterruptedException { + Thread.sleep(millis); + } } - @Override - public void onStart() { - publishBinderService(Context.RECOVERY_SERVICE, new BinderService()); + /** + * Handles the lifecycle events for the RecoverySystemService. + */ + public static final class Lifecycle extends SystemService { + public Lifecycle(Context context) { + super(context); + } + + @Override + public void onStart() { + RecoverySystemService recoverySystemService = new RecoverySystemService(getContext()); + publishBinderService(Context.RECOVERY_SERVICE, recoverySystemService); + } } - private final class BinderService extends IRecoverySystem.Stub { - @Override // Binder call - public boolean uncrypt(String filename, IRecoverySystemProgressListener listener) { - if (DEBUG) Slog.d(TAG, "uncrypt: " + filename); + private RecoverySystemService(Context context) { + this(new Injector(context)); + } - synchronized (sRequestLock) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null); + @VisibleForTesting + RecoverySystemService(Injector injector) { + mInjector = injector; + mContext = injector.getContext(); + } - final boolean available = checkAndWaitForUncryptService(); - if (!available) { - Slog.e(TAG, "uncrypt service is unavailable."); - return false; - } + @Override // Binder call + public boolean uncrypt(String filename, IRecoverySystemProgressListener listener) { + if (DEBUG) Slog.d(TAG, "uncrypt: " + filename); - // Write the filename into UNCRYPT_PACKAGE_FILE to be read by - // uncrypt. - RecoverySystem.UNCRYPT_PACKAGE_FILE.delete(); + synchronized (sRequestLock) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null); - try (FileWriter uncryptFile = new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE)) { - uncryptFile.write(filename + "\n"); - } catch (IOException e) { - Slog.e(TAG, "IOException when writing \"" + - RecoverySystem.UNCRYPT_PACKAGE_FILE + "\":", e); - return false; - } + if (!checkAndWaitForUncryptService()) { + Slog.e(TAG, "uncrypt service is unavailable."); + return false; + } - // Trigger uncrypt via init. - SystemProperties.set("ctl.start", "uncrypt"); + // Write the filename into uncrypt package file to be read by + // uncrypt. + mInjector.uncryptPackageFileDelete(); - // Connect to the uncrypt service socket. - LocalSocket socket = connectService(); - if (socket == null) { - Slog.e(TAG, "Failed to connect to uncrypt socket"); - return false; - } + try (FileWriter uncryptFile = mInjector.getUncryptPackageFileWriter()) { + uncryptFile.write(filename + "\n"); + } catch (IOException e) { + Slog.e(TAG, "IOException when writing \"" + + mInjector.getUncryptPackageFileName() + "\":", e); + return false; + } - // Read the status from the socket. - DataInputStream dis = null; - DataOutputStream dos = null; - try { - dis = new DataInputStream(socket.getInputStream()); - dos = new DataOutputStream(socket.getOutputStream()); - int lastStatus = Integer.MIN_VALUE; - while (true) { - int status = dis.readInt(); - // Avoid flooding the log with the same message. - if (status == lastStatus && lastStatus != Integer.MIN_VALUE) { - continue; - } - lastStatus = status; - - if (status >= 0 && status <= 100) { - // Update status - Slog.i(TAG, "uncrypt read status: " + status); - if (listener != null) { - try { - listener.onProgress(status); - } catch (RemoteException ignored) { - Slog.w(TAG, "RemoteException when posting progress"); - } - } - if (status == 100) { - Slog.i(TAG, "uncrypt successfully finished."); - // Ack receipt of the final status code. uncrypt - // waits for the ack so the socket won't be - // destroyed before we receive the code. - dos.writeInt(0); - break; + // Trigger uncrypt via init. + mInjector.systemPropertiesSet("ctl.start", "uncrypt"); + + // Connect to the uncrypt service socket. + UncryptSocket socket = mInjector.connectService(); + if (socket == null) { + Slog.e(TAG, "Failed to connect to uncrypt socket"); + return false; + } + + // Read the status from the socket. + try { + int lastStatus = Integer.MIN_VALUE; + while (true) { + int status = socket.getPercentageUncrypted(); + // Avoid flooding the log with the same message. + if (status == lastStatus && lastStatus != Integer.MIN_VALUE) { + continue; + } + lastStatus = status; + + if (status >= 0 && status <= 100) { + // Update status + Slog.i(TAG, "uncrypt read status: " + status); + if (listener != null) { + try { + listener.onProgress(status); + } catch (RemoteException ignored) { + Slog.w(TAG, "RemoteException when posting progress"); } - } else { - // Error in /system/bin/uncrypt. - Slog.e(TAG, "uncrypt failed with status: " + status); - // Ack receipt of the final status code. uncrypt waits - // for the ack so the socket won't be destroyed before - // we receive the code. - dos.writeInt(0); - return false; } + if (status == 100) { + Slog.i(TAG, "uncrypt successfully finished."); + // Ack receipt of the final status code. uncrypt + // waits for the ack so the socket won't be + // destroyed before we receive the code. + socket.sendAck(); + break; + } + } else { + // Error in /system/bin/uncrypt. + Slog.e(TAG, "uncrypt failed with status: " + status); + // Ack receipt of the final status code. uncrypt waits + // for the ack so the socket won't be destroyed before + // we receive the code. + socket.sendAck(); + return false; } - } catch (IOException e) { - Slog.e(TAG, "IOException when reading status: ", e); - return false; - } finally { - IoUtils.closeQuietly(dis); - IoUtils.closeQuietly(dos); - IoUtils.closeQuietly(socket); } - - return true; + } catch (IOException e) { + Slog.e(TAG, "IOException when reading status: ", e); + return false; + } finally { + socket.close(); } + + return true; } + } - @Override // Binder call - public boolean clearBcb() { - if (DEBUG) Slog.d(TAG, "clearBcb"); - synchronized (sRequestLock) { - return setupOrClearBcb(false, null); - } + @Override // Binder call + public boolean clearBcb() { + if (DEBUG) Slog.d(TAG, "clearBcb"); + synchronized (sRequestLock) { + return setupOrClearBcb(false, null); } + } + + @Override // Binder call + public boolean setupBcb(String command) { + if (DEBUG) Slog.d(TAG, "setupBcb: [" + command + "]"); + synchronized (sRequestLock) { + return setupOrClearBcb(true, command); + } + } - @Override // Binder call - public boolean setupBcb(String command) { - if (DEBUG) Slog.d(TAG, "setupBcb: [" + command + "]"); - synchronized (sRequestLock) { - return setupOrClearBcb(true, command); + @Override // Binder call + public void rebootRecoveryWithCommand(String command) { + if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]"); + synchronized (sRequestLock) { + if (!setupOrClearBcb(true, command)) { + return; } + + // Having set up the BCB, go ahead and reboot. + PowerManager pm = mInjector.getPowerManager(); + pm.reboot(PowerManager.REBOOT_RECOVERY); } + } - @Override // Binder call - public void rebootRecoveryWithCommand(String command) { - if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]"); - synchronized (sRequestLock) { - if (!setupOrClearBcb(true, command)) { - return; - } + /** + * Check if any of the init services is still running. If so, we cannot + * start a new uncrypt/setup-bcb/clear-bcb service right away; otherwise + * it may break the socket communication since init creates / deletes + * the socket (/dev/socket/uncrypt) on service start / exit. + */ + private boolean checkAndWaitForUncryptService() { + for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) { + final String uncryptService = mInjector.systemPropertiesGet(INIT_SERVICE_UNCRYPT); + final String setupBcbService = mInjector.systemPropertiesGet(INIT_SERVICE_SETUP_BCB); + final String clearBcbService = mInjector.systemPropertiesGet(INIT_SERVICE_CLEAR_BCB); + final boolean busy = "running".equals(uncryptService) + || "running".equals(setupBcbService) || "running".equals(clearBcbService); + if (DEBUG) { + Slog.i(TAG, "retry: " + retry + " busy: " + busy + + " uncrypt: [" + uncryptService + "]" + + " setupBcb: [" + setupBcbService + "]" + + " clearBcb: [" + clearBcbService + "]"); + } - // Having set up the BCB, go ahead and reboot. - PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); - pm.reboot(PowerManager.REBOOT_RECOVERY); + if (!busy) { + return true; + } + + try { + mInjector.threadSleep(1000); + } catch (InterruptedException e) { + Slog.w(TAG, "Interrupted:", e); } } - /** - * Check if any of the init services is still running. If so, we cannot - * start a new uncrypt/setup-bcb/clear-bcb service right away; otherwise - * it may break the socket communication since init creates / deletes - * the socket (/dev/socket/uncrypt) on service start / exit. - */ - private boolean checkAndWaitForUncryptService() { - for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) { - final String uncryptService = SystemProperties.get(INIT_SERVICE_UNCRYPT); - final String setupBcbService = SystemProperties.get(INIT_SERVICE_SETUP_BCB); - final String clearBcbService = SystemProperties.get(INIT_SERVICE_CLEAR_BCB); - final boolean busy = "running".equals(uncryptService) || - "running".equals(setupBcbService) || "running".equals(clearBcbService); - if (DEBUG) { - Slog.i(TAG, "retry: " + retry + " busy: " + busy + - " uncrypt: [" + uncryptService + "]" + - " setupBcb: [" + setupBcbService + "]" + - " clearBcb: [" + clearBcbService + "]"); - } + return false; + } - if (!busy) { - return true; - } + private boolean setupOrClearBcb(boolean isSetup, String command) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - Slog.w(TAG, "Interrupted:", e); - } + final boolean available = checkAndWaitForUncryptService(); + if (!available) { + Slog.e(TAG, "uncrypt service is unavailable."); + return false; + } + + if (isSetup) { + mInjector.systemPropertiesSet("ctl.start", "setup-bcb"); + } else { + mInjector.systemPropertiesSet("ctl.start", "clear-bcb"); + } + + // Connect to the uncrypt service socket. + UncryptSocket socket = mInjector.connectService(); + if (socket == null) { + Slog.e(TAG, "Failed to connect to uncrypt socket"); + return false; + } + + try { + // Send the BCB commands if it's to setup BCB. + if (isSetup) { + socket.sendCommand(command); } + // Read the status from the socket. + int status = socket.getPercentageUncrypted(); + + // Ack receipt of the status code. uncrypt waits for the ack so + // the socket won't be destroyed before we receive the code. + socket.sendAck(); + + if (status == 100) { + Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear") + + " bcb successfully finished."); + } else { + // Error in /system/bin/uncrypt. + Slog.e(TAG, "uncrypt failed with status: " + status); + return false; + } + } catch (IOException e) { + Slog.e(TAG, "IOException when communicating with uncrypt:", e); return false; + } finally { + socket.close(); } - private LocalSocket connectService() { - LocalSocket socket = new LocalSocket(); + return true; + } + + /** + * Provides a wrapper for the low-level details of framing packets sent to the uncrypt + * socket. + */ + public static class UncryptSocket { + private LocalSocket mLocalSocket; + private DataInputStream mInputStream; + private DataOutputStream mOutputStream; + + /** + * Attempt to connect to the uncrypt service. Connection will be retried for up to + * {@link #SOCKET_CONNECTION_MAX_RETRY} times. If the connection is unsuccessful, the + * socket will be closed. If the connection is successful, the connection must be closed + * by the caller. + * + * @return true if connection was successful, false if unsuccessful + */ + public boolean connectService() { + mLocalSocket = new LocalSocket(); boolean done = false; // The uncrypt socket will be created by init upon receiving the // service request. It may not be ready by this point. So we will // keep retrying until success or reaching timeout. for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) { try { - socket.connect(new LocalSocketAddress(UNCRYPT_SOCKET, + mLocalSocket.connect(new LocalSocketAddress(UNCRYPT_SOCKET, LocalSocketAddress.Namespace.RESERVED)); done = true; break; @@ -249,71 +381,57 @@ public final class RecoverySystemService extends SystemService { } if (!done) { Slog.e(TAG, "Timed out connecting to uncrypt socket"); - return null; - } - return socket; - } - - private boolean setupOrClearBcb(boolean isSetup, String command) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null); - - final boolean available = checkAndWaitForUncryptService(); - if (!available) { - Slog.e(TAG, "uncrypt service is unavailable."); + close(); return false; } - if (isSetup) { - SystemProperties.set("ctl.start", "setup-bcb"); - } else { - SystemProperties.set("ctl.start", "clear-bcb"); - } - - // Connect to the uncrypt service socket. - LocalSocket socket = connectService(); - if (socket == null) { - Slog.e(TAG, "Failed to connect to uncrypt socket"); + try { + mInputStream = new DataInputStream(mLocalSocket.getInputStream()); + mOutputStream = new DataOutputStream(mLocalSocket.getOutputStream()); + } catch (IOException e) { + close(); return false; } - DataInputStream dis = null; - DataOutputStream dos = null; - try { - dis = new DataInputStream(socket.getInputStream()); - dos = new DataOutputStream(socket.getOutputStream()); - - // Send the BCB commands if it's to setup BCB. - if (isSetup) { - byte[] cmdUtf8 = command.getBytes("UTF-8"); - dos.writeInt(cmdUtf8.length); - dos.write(cmdUtf8, 0, cmdUtf8.length); - } + return true; + } - // Read the status from the socket. - int status = dis.readInt(); + /** + * Sends a command to the uncrypt service. + * + * @param command command to send to the uncrypt service + * @throws IOException if there was an error writing to the socket + */ + public void sendCommand(String command) throws IOException { + byte[] cmdUtf8 = command.getBytes(StandardCharsets.UTF_8); + mOutputStream.writeInt(cmdUtf8.length); + mOutputStream.write(cmdUtf8, 0, cmdUtf8.length); + } - // Ack receipt of the status code. uncrypt waits for the ack so - // the socket won't be destroyed before we receive the code. - dos.writeInt(0); + /** + * Reads the status from the uncrypt service which is usually represented as a percentage. + * @return an integer representing the percentage completed + * @throws IOException if there was an error reading the socket + */ + public int getPercentageUncrypted() throws IOException { + return mInputStream.readInt(); + } - if (status == 100) { - Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear") + - " bcb successfully finished."); - } else { - // Error in /system/bin/uncrypt. - Slog.e(TAG, "uncrypt failed with status: " + status); - return false; - } - } catch (IOException e) { - Slog.e(TAG, "IOException when communicating with uncrypt:", e); - return false; - } finally { - IoUtils.closeQuietly(dis); - IoUtils.closeQuietly(dos); - IoUtils.closeQuietly(socket); - } + /** + * Sends a confirmation to the uncrypt service. + * @throws IOException if there was an error writing to the socket + */ + public void sendAck() throws IOException { + mOutputStream.writeInt(0); + } - return true; + /** + * Closes the socket and all underlying data streams. + */ + public void close() { + IoUtils.closeQuietly(mInputStream); + IoUtils.closeQuietly(mOutputStream); + IoUtils.closeQuietly(mLocalSocket); } } } diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 198bb146c9b2..01f29dcd4ffe 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -49,6 +49,7 @@ import android.os.UserManager; import android.provider.DeviceConfig; import android.util.ArraySet; import android.util.IntArray; +import android.util.LongArrayQueue; import android.util.Slog; import android.util.SparseBooleanArray; @@ -126,6 +127,11 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { private final RollbackPackageHealthObserver mPackageHealthObserver; private final AppDataRollbackHelper mAppDataRollbackHelper; + // The # of milli-seconds to sleep for each received ACTION_PACKAGE_ENABLE_ROLLBACK. + // Used by #blockRollbackManager to test timeout in enabling rollbacks. + // Accessed on the handler thread only. + private final LongArrayQueue mSleepDuration = new LongArrayQueue(); + // This field stores the difference in Millis between the uptime (millis since device // has booted) and current time (device wall clock) - it's used to update rollback // timestamps when the time is changed, by the user or by change of timezone. @@ -182,6 +188,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { File newPackageCodePath = new File(intent.getData().getPath()); + queueSleepIfNeeded(); + getHandler().post(() -> { boolean success = enableRollback(installFlags, newPackageCodePath, user, token); @@ -414,6 +422,19 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { Manifest.permission.TEST_MANAGE_ROLLBACKS, "blockRollbackManager"); getHandler().post(() -> { + mSleepDuration.addLast(millis); + }); + } + + private void queueSleepIfNeeded() { + if (mSleepDuration.size() == 0) { + return; + } + long millis = mSleepDuration.removeFirst(); + if (millis <= 0) { + return; + } + getHandler().post(() -> { try { Thread.sleep(millis); } catch (InterruptedException e) { @@ -1034,6 +1055,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { makeRollbackAvailable(rollback); } } + + // Clear the queue so it will never be leaked to next tests. + mSleepDuration.clear(); } } diff --git a/services/core/java/com/android/server/search/SearchManagerService.java b/services/core/java/com/android/server/search/SearchManagerService.java index bc1a12fac393..1494edf53651 100644 --- a/services/core/java/com/android/server/search/SearchManagerService.java +++ b/services/core/java/com/android/server/search/SearchManagerService.java @@ -18,7 +18,6 @@ package com.android.server.search; import android.app.ActivityManager; import android.app.ActivityTaskManager; -import android.app.IActivityManager; import android.app.IActivityTaskManager; import android.app.ISearchManager; import android.app.SearchManager; @@ -29,6 +28,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.content.res.Configuration; import android.database.ContentObserver; import android.os.Binder; import android.os.Bundle; @@ -265,11 +265,17 @@ public class SearchManagerService extends ISearchManager.Stub { } @Override - public void launchAssist(Bundle args) { - StatusBarManagerInternal statusBarManager = - LocalServices.getService(StatusBarManagerInternal.class); - if (statusBarManager != null) { - statusBarManager.startAssist(args); + public void launchAssist(int userHandle, Bundle args) { + if ((mContext.getResources().getConfiguration().uiMode + & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_TELEVISION) { + // On TV, use legacy handling until assistants are implemented in the proper way. + launchLegacyAssist(null, userHandle, args); + } else { + StatusBarManagerInternal statusBarManager = + LocalServices.getService(StatusBarManagerInternal.class); + if (statusBarManager != null) { + statusBarManager.startAssist(args); + } } } @@ -298,8 +304,7 @@ public class SearchManagerService extends ISearchManager.Stub { return null; } - @Override - public boolean launchLegacyAssist(String hint, int userHandle, Bundle args) { + private boolean launchLegacyAssist(String hint, int userHandle, Bundle args) { ComponentName comp = getLegacyAssistComponent(userHandle); if (comp == null) { return false; diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java index 72a1b9df3b3c..d76836f90e6b 100644 --- a/services/core/java/com/android/server/storage/StorageSessionController.java +++ b/services/core/java/com/android/server/storage/StorageSessionController.java @@ -69,15 +69,21 @@ public final class StorageSessionController { } /** - * Creates a storage session associated with {@code deviceFd} for {@code vol}. Sessions can be - * started with {@link #onVolumeReady} and removed with {@link #onVolumeUnmount} or - * {@link #onVolumeRemove}. + * Creates and starts a storage session associated with {@code deviceFd} for {@code vol}. + * Sessions can be started with {@link #onVolumeReady} and removed with {@link #onVolumeUnmount} + * or {@link #onVolumeRemove}. + * + * Throws an {@link IllegalStateException} if a session for {@code vol} has already been created * * Does nothing if {@link #shouldHandle} is {@code false} * + * Blocks until the session is started or fails + * + * @throws ExternalStorageServiceException if the session fails to start * @throws IllegalStateException if a session has already been created for {@code vol} */ - public void onVolumeMount(FileDescriptor deviceFd, VolumeInfo vol) { + public void onVolumeMount(FileDescriptor deviceFd, VolumeInfo vol) + throws ExternalStorageServiceException { if (!shouldHandle(vol)) { return; } @@ -87,71 +93,22 @@ public final class StorageSessionController { String sessionId = vol.getId(); int userId = vol.getMountUserId(); - if (deviceFd == null) { - Slog.w(TAG, "Null fd. Session not started for vol: " + vol); - return; - } - - // Get realpath for the fd, paths that are not /dev/null need additional - // setup by the ExternalStorageService before they can be ready - String realPath; - try { - realPath = ParcelFileDescriptor.getFile(deviceFd).getPath(); - } catch (IOException e) { - Slog.wtf(TAG, "Could not get real path from fd: " + deviceFd, e); - return; - } - - if ("/dev/null".equals(realPath)) { - Slog.i(TAG, "Volume ready for use with id: " + sessionId); - return; - } - + StorageUserConnection connection = null; synchronized (mLock) { - StorageUserConnection connection = mConnections.get(userId); + connection = mConnections.get(userId); if (connection == null) { + Slog.i(TAG, "Creating connection for user: " + userId); connection = new StorageUserConnection(mContext, userId, this); mConnections.put(userId, connection); } Slog.i(TAG, "Creating session with id: " + sessionId); - connection.createSession(sessionId, new ParcelFileDescriptor(deviceFd)); - } - } - - /** - * Starts a storage session associated with {@code vol} after {@link #onVolumeMount}. - * - * Subsequent calls will attempt to start the storage session, but does nothing if already - * started. If the user associated with {@code vol} is not yet ready, all pending sesssions - * can be restarted with {@link onUnlockUser}. - * - * Does nothing if {@link #shouldHandle} is {@code false} - * - * Blocks until the session is started or fails - * - * @throws ExternalStorageServiceException if the session fails to start - */ - public void onVolumeReady(VolumeInfo vol) throws ExternalStorageServiceException { - if (!shouldHandle(vol)) { - return; + connection.createSession(sessionId, new ParcelFileDescriptor(deviceFd), + vol.getPath().getPath(), vol.getInternalPath().getPath()); } - Slog.i(TAG, "On volume ready " + vol); - String sessionId = vol.getId(); - - StorageUserConnection connection = null; - synchronized (mLock) { - connection = mConnections.get(vol.getMountUserId()); - if (connection == null) { - Slog.i(TAG, "Volume ready but no associated connection"); - return; - } - } - - connection.initSession(sessionId, vol.getPath().getPath(), - vol.getInternalPath().getPath()); - - if (isReady()) { + // At boot, a volume can be mounted before user is unlocked, in that case, we create it + // above and save it so that we can restart all sessions when the user is unlocked + if (mExternalStorageServiceComponent != null) { connection.startSession(sessionId); } else { Slog.i(TAG, "Controller not initialised, session not started " + sessionId); @@ -205,14 +162,10 @@ public final class StorageSessionController { if (connection != null) { String sessionId = vol.getId(); - if (isReady()) { - try { - connection.removeSessionAndWait(sessionId); - } catch (ExternalStorageServiceException e) { - Slog.e(TAG, "Failed to end session for vol with id: " + sessionId, e); - } - } else { - Slog.i(TAG, "Controller not initialised, session not ended " + sessionId); + try { + connection.removeSessionAndWait(sessionId); + } catch (ExternalStorageServiceException e) { + Slog.e(TAG, "Failed to end session for vol with id: " + sessionId, e); } } } @@ -232,7 +185,7 @@ public final class StorageSessionController { Slog.i(TAG, "On user unlock " + userId); if (userId == 0) { - init(); + initExternalStorageServiceComponent(); } StorageUserConnection connection = null; @@ -259,13 +212,6 @@ public final class StorageSessionController { return; } - if (!isReady()) { - synchronized (mLock) { - mConnections.clear(); - } - return; - } - SparseArray<StorageUserConnection> connections = new SparseArray(); synchronized (mLock) { mIsResetting = true; @@ -311,7 +257,7 @@ public final class StorageSessionController { } } - private void init() throws ExternalStorageServiceException { + private void initExternalStorageServiceComponent() throws ExternalStorageServiceException { Slog.i(TAG, "Initialialising..."); ProviderInfo provider = mContext.getPackageManager().resolveContentProvider( MediaStore.AUTHORITY, PackageManager.MATCH_DIRECT_BOOT_AWARE @@ -415,8 +361,4 @@ public final class StorageSessionController { private boolean shouldHandle(@Nullable VolumeInfo vol) { return mIsFuseEnabled && !mIsResetting && (vol == null || isEmulatedOrPublic(vol)); } - - private boolean isReady() { - return mExternalStorageServiceComponent != null; - } } diff --git a/services/core/java/com/android/server/storage/StorageUserConnection.java b/services/core/java/com/android/server/storage/StorageUserConnection.java index 24b56a48900b..7c4773033518 100644 --- a/services/core/java/com/android/server/storage/StorageUserConnection.java +++ b/services/core/java/com/android/server/storage/StorageUserConnection.java @@ -75,46 +75,20 @@ public final class StorageUserConnection { /** * Creates and stores a storage {@link Session}. * - * Created sessions must be initialised with {@link #initSession} before starting with - * {@link #startSession}. - * * They must also be cleaned up with {@link #removeSession}. * * @throws IllegalArgumentException if a {@code Session} with {@code sessionId} already exists */ - public void createSession(String sessionId, ParcelFileDescriptor pfd) { + public void createSession(String sessionId, ParcelFileDescriptor pfd, String upperPath, + String lowerPath) { Preconditions.checkNotNull(sessionId); Preconditions.checkNotNull(pfd); + Preconditions.checkNotNull(upperPath); + Preconditions.checkNotNull(lowerPath); synchronized (mLock) { Preconditions.checkArgument(!mSessions.containsKey(sessionId)); - mSessions.put(sessionId, new Session(sessionId, pfd)); - } - } - - /** - * Initialise a storage {@link Session}. - * - * Initialised sessions can be started with {@link #startSession}. - * - * They must also be cleaned up with {@link #removeSession}. - * - * @throws IllegalArgumentException if {@code sessionId} does not exist or is initialised - */ - public void initSession(String sessionId, String upperPath, String lowerPath) { - synchronized (mLock) { - Session session = mSessions.get(sessionId); - if (session == null) { - throw new IllegalStateException("Failed to initialise non existent session. Id: " - + sessionId + ". Upper path: " + upperPath + ". Lower path: " + lowerPath); - } else if (session.isInitialisedLocked()) { - throw new IllegalStateException("Already initialised session. Id: " - + sessionId + ". Upper path: " + upperPath + ". Lower path: " + lowerPath); - } else { - session.upperPath = upperPath; - session.lowerPath = lowerPath; - Slog.i(TAG, "Initialised session: " + session); - } + mSessions.put(sessionId, new Session(sessionId, pfd, upperPath, lowerPath)); } } @@ -440,14 +414,14 @@ public final class StorageUserConnection { private static final class Session implements AutoCloseable { public final String sessionId; public final ParcelFileDescriptor pfd; - @GuardedBy("mLock") - public String lowerPath; - @GuardedBy("mLock") - public String upperPath; + public final String lowerPath; + public final String upperPath; - Session(String sessionId, ParcelFileDescriptor pfd) { + Session(String sessionId, ParcelFileDescriptor pfd, String upperPath, String lowerPath) { this.sessionId = sessionId; this.pfd = pfd; + this.upperPath = upperPath; + this.lowerPath = lowerPath; } @Override diff --git a/services/core/java/com/android/server/updates/EmergencyNumberDbInstallReceiver.java b/services/core/java/com/android/server/updates/EmergencyNumberDbInstallReceiver.java index cb0b45ceaf05..c78a8e62cf85 100644 --- a/services/core/java/com/android/server/updates/EmergencyNumberDbInstallReceiver.java +++ b/services/core/java/com/android/server/updates/EmergencyNumberDbInstallReceiver.java @@ -37,9 +37,8 @@ public class EmergencyNumberDbInstallReceiver extends ConfigUpdateInstallReceive Slog.i(TAG, "Emergency number database is updated in file partition"); // Notify EmergencyNumberTracker for emergency number installation complete. - Intent notifyInstallComplete = new Intent( - TelephonyManager.ACTION_OTA_EMERGENCY_NUMBER_DB_INSTALLED); - context.sendBroadcast( - notifyInstallComplete, android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE); + TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService( + Context.TELEPHONY_SERVICE); + telephonyManager.notifyOtaEmergencyNumberDbInstalled(); } } diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java index ebfc65e5d1e5..be7dfe53c1c1 100644 --- a/services/core/java/com/android/server/wm/ActivityDisplay.java +++ b/services/core/java/com/android/server/wm/ActivityDisplay.java @@ -1080,6 +1080,8 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND); mService.mH.sendMessage(msg); } + mService.mWindowManager.mDisplayNotificationController.dispatchDisplayChanged( + this, getConfiguration()); } return changes; } @@ -1408,7 +1410,7 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack> { boolean preserveWindows, boolean notifyClients) { for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) { final ActivityStack stack = getChildAt(stackNdx); - stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows, + stack.ensureActivitiesVisible(starting, configChanges, preserveWindows, notifyClients); } } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index f24fa077bb6c..e16f3fc948ac 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -121,6 +121,7 @@ import static com.android.server.am.ActivityRecordProto.PROC_ID; import static com.android.server.am.ActivityRecordProto.STATE; import static com.android.server.am.ActivityRecordProto.TRANSLUCENT; import static com.android.server.am.ActivityRecordProto.VISIBLE; +import static com.android.server.am.ActivityRecordProto.VISIBLE_REQUESTED; import static com.android.server.am.EventLogTags.AM_RELAUNCH_ACTIVITY; import static com.android.server.am.EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; @@ -172,11 +173,10 @@ import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_W import static com.android.server.wm.ActivityTaskManagerService.getInputDispatchingTimeoutLocked; import static com.android.server.wm.AppWindowTokenProto.ALL_DRAWN; import static com.android.server.wm.AppWindowTokenProto.APP_STOPPED; -import static com.android.server.wm.AppWindowTokenProto.CLIENT_HIDDEN; +import static com.android.server.wm.AppWindowTokenProto.CLIENT_VISIBLE; import static com.android.server.wm.AppWindowTokenProto.DEFER_HIDING_CLIENT; import static com.android.server.wm.AppWindowTokenProto.FILLS_PARENT; import static com.android.server.wm.AppWindowTokenProto.FROZEN_BOUNDS; -import static com.android.server.wm.AppWindowTokenProto.HIDDEN_SET_FROM_TRANSFERRED_STARTING_WINDOW; import static com.android.server.wm.AppWindowTokenProto.IS_ANIMATING; import static com.android.server.wm.AppWindowTokenProto.IS_WAITING_FOR_TRANSITION_START; import static com.android.server.wm.AppWindowTokenProto.LAST_ALL_DRAWN; @@ -190,7 +190,7 @@ import static com.android.server.wm.AppWindowTokenProto.STARTING_DISPLAYED; import static com.android.server.wm.AppWindowTokenProto.STARTING_MOVED; import static com.android.server.wm.AppWindowTokenProto.STARTING_WINDOW; import static com.android.server.wm.AppWindowTokenProto.THUMBNAIL; -import static com.android.server.wm.AppWindowTokenProto.VISIBLE_REQUESTED; +import static com.android.server.wm.AppWindowTokenProto.VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW; import static com.android.server.wm.AppWindowTokenProto.WINDOW_TOKEN; import static com.android.server.wm.IdentifierProto.HASH_CODE; import static com.android.server.wm.IdentifierProto.TITLE; @@ -333,6 +333,9 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; /** * An entry in the history stack, representing an activity. @@ -461,15 +464,16 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A private boolean keysPaused; // has key dispatching been paused for it? int launchMode; // the launch mode activity attribute. int lockTaskLaunchMode; // the lockTaskMode manifest attribute, subject to override + private boolean mVisible; // Should this token's windows be visible? boolean visibleIgnoringKeyguard; // is this activity visible, ignoring the fact that Keyguard // might hide this activity? - // True if the hidden state of this token was forced to false due to a transferred starting + // True if the visible state of this token was forced to true due to a transferred starting // window. - private boolean mHiddenSetFromTransferredStartingWindow; - // TODO: figureout how to consolidate with the same variable in ActivityRecord. + private boolean mVisibleSetFromTransferredStartingWindow; + // TODO: figure out how to consolidate with the same variable in ActivityRecord. private boolean mDeferHidingClient; // If true we told WM to defer reporting to the client // process that it is hidden. - private boolean mLastDeferHidingClient; // If true we will defer setting mClientHidden to true + private boolean mLastDeferHidingClient; // If true we will defer setting mClientVisible to false // and reporting to the client that it is hidden. boolean sleeping; // have we told the activity to sleep? boolean nowVisible; // is this activity's window visible? @@ -534,8 +538,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A private Task mLastParent; - // Have we told the window clients to hide themselves? - private boolean mClientHidden; + // Have we told the window clients to show themselves? + private boolean mClientVisible; boolean firstWindowDrawn; // Last drawn state we reported to the app token. @@ -849,13 +853,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pw.println(requestedVrComponent); } super.dump(pw, prefix, dumpAll); + pw.print(" visible="); pw.print(mVisible); if (appToken != null) { pw.println(prefix + "app=true mVoiceInteraction=" + mVoiceInteraction); } pw.print(prefix); pw.print(" mOccludesParent="); pw.print(mOccludesParent); pw.print(" mOrientation="); pw.println(mOrientation); pw.println(prefix + "mVisibleRequested=" + mVisibleRequested - + " mClientHidden=" + mClientHidden + + " mClientVisible=" + mClientVisible + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "") + " reportedDrawn=" + reportedDrawn + " reportedVisible=" + reportedVisible); if (paused) { @@ -879,13 +884,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A pw.print(" mIsExiting="); pw.println(mIsExiting); } if (startingWindow != null || startingSurface != null - || startingDisplayed || startingMoved || mHiddenSetFromTransferredStartingWindow) { + || startingDisplayed || startingMoved || mVisibleSetFromTransferredStartingWindow) { pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow); pw.print(" startingSurface="); pw.print(startingSurface); pw.print(" startingDisplayed="); pw.print(startingDisplayed); pw.print(" startingMoved="); pw.print(startingMoved); pw.println(" mHiddenSetFromTransferredStartingWindow=" - + mHiddenSetFromTransferredStartingWindow); + + mVisibleSetFromTransferredStartingWindow); } if (!mFrozenBounds.isEmpty()) { pw.print(prefix); pw.print("mFrozenBounds="); pw.println(mFrozenBounds); @@ -1481,7 +1486,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } // Application tokens start out hidden. - setHidden(true); + setVisible(false); mVisibleRequested = false; ColorDisplayService.ColorDisplayServiceInternal cds = LocalServices.getService( @@ -1513,6 +1518,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A inHistory = false; nowVisible = false; mDrawn = false; + mClientVisible = true; idle = false; hasBeenLaunched = false; mStackSupervisor = supervisor; @@ -1581,6 +1587,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return this; } + @Override + boolean hasActivity() { + // I am an activity! + return true; + } + void setProcess(WindowProcessController proc) { app = proc; final ActivityRecord root = task != null ? task.getRootActivity() : null; @@ -3198,7 +3210,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A "Removing starting %s from %s", tStartingWindow, fromActivity); fromActivity.removeChild(tStartingWindow); fromActivity.postWindowRemoveStartingWindowCleanup(tStartingWindow); - fromActivity.mHiddenSetFromTransferredStartingWindow = false; + fromActivity.mVisibleSetFromTransferredStartingWindow = false; addWindow(tStartingWindow); // Propagate other interesting state between the tokens. If the old token is displayed, @@ -3211,12 +3223,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A if (fromActivity.firstWindowDrawn) { firstWindowDrawn = true; } - if (!fromActivity.isHidden()) { - setHidden(false); + if (fromActivity.isVisible()) { + setVisible(true); mVisibleRequested = true; - mHiddenSetFromTransferredStartingWindow = true; + mVisibleSetFromTransferredStartingWindow = true; } - setClientHidden(fromActivity.mClientHidden); + setClientVisible(fromActivity.mClientVisible); transferAnimation(fromActivity); @@ -3418,11 +3430,21 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } @Override - boolean forAllActivities(ToBooleanFunction<ActivityRecord> callback) { + boolean forAllActivities(Function<ActivityRecord, Boolean> callback) { return callback.apply(this); } @Override + void forAllActivities(Consumer<ActivityRecord> callback, boolean traverseTopToBottom) { + callback.accept(this); + } + + @Override + ActivityRecord getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom) { + return callback.test(this) ? this : null; + } + + @Override protected void setLayer(Transaction t, int layer) { if (!mSurfaceAnimator.hasLeash()) { t.setLayer(mSurfaceControl, layer); @@ -3828,7 +3850,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean isVisible() { // If the activity isn't hidden then it is considered visible and there is no need to check // its children windows to see if they are visible. - return !isHidden(); + return mVisible; + } + + void setVisible(boolean visible) { + if (visible != mVisible) { + mVisible = visible; + scheduleAnimation(); + } } void setVisibility(boolean visible) { @@ -3864,14 +3893,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // We previously deferred telling the client to hide itself when visibility was // initially set to false. Now we would like it to hide, so go ahead and set it. mLastDeferHidingClient = deferHidingClient; - setClientHidden(true); + setClientVisible(false); } return; } ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, - "setAppVisibility(%s, visible=%b): %s hidden=%b mVisibleRequested=%b Callers=%s", - appToken, visible, appTransition, isHidden(), mVisibleRequested, + "setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s", + appToken, visible, appTransition, isVisible(), mVisibleRequested, Debug.getCallers(6)); final DisplayContent displayContent = getDisplayContent(); @@ -3901,15 +3930,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A startingMoved = false; // If the token is currently hidden (should be the common case), or has been // stopped, then we need to set up to wait for its windows to be ready. - if (isHidden() || mAppStopped) { + if (!isVisible() || mAppStopped) { clearAllDrawn(); // If the app was already visible, don't reset the waitingToShow state. - if (isHidden()) { + if (!isVisible()) { waitingToShow = true; // If the client isn't hidden, we don't need to reset the drawing state. - if (isClientHidden()) { + if (!isClientVisible()) { // Let's reset the draw state in order to prevent the starting window to be // immediately dismissed when the app still has the surface. forAllWindows(w -> { @@ -3929,7 +3958,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // we still need to tell the client to make its windows visible so they get drawn. // Otherwise, we will wait on performing the transition until all windows have been // drawn, they never will be, and we are sad. - setClientHidden(false); + setClientVisible(true); requestUpdateWallpaperIfNeeded(); @@ -3975,9 +4004,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) { boolean delayed = false; - // Reset the state of mHiddenSetFromTransferredStartingWindow since visibility is actually + // Reset the state of mVisibleSetFromTransferredStartingWindow since visibility is actually // been set by the app now. - mHiddenSetFromTransferredStartingWindow = false; + mVisibleSetFromTransferredStartingWindow = false; // Allow for state changes and animation to be applied if: // * token is transitioning visibility state @@ -3987,7 +4016,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // * or the token is the opening app and visible while opening task behind existing one. final DisplayContent displayContent = getDisplayContent(); boolean visibilityChanged = false; - if (isHidden() == visible || (isHidden() && mIsExiting) + if (isVisible() != visible || (!isVisible() && mIsExiting) || (visible && waitingForReplacement()) || (visible && displayContent.mOpeningApps.contains(this) && displayContent.mAppTransition.getAppTransition() == TRANSIT_TASK_OPEN_BEHIND)) { @@ -3995,7 +4024,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A mWmService.mAccessibilityController; boolean changed = false; ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, - "Changing app %s hidden=%b performLayout=%b", this, isHidden(), + "Changing app %s visible=%b performLayout=%b", this, isVisible(), performLayout); boolean runningAppAnimation = false; @@ -4020,7 +4049,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A changed |= win.onAppVisibilityChanged(visible, runningAppAnimation); } - setHidden(!visible); + setVisible(visible); mVisibleRequested = visible; visibilityChanged = true; if (!visible) { @@ -4039,8 +4068,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, - "commitVisibility: %s: hidden=%b visibleRequested=%b", this, - isHidden(), mVisibleRequested); + "commitVisibility: %s: visible=%b visibleRequested=%b", this, + isVisible(), mVisibleRequested); if (changed) { displayContent.getInputMonitor().setUpdateInputWindowsNeededLw(); @@ -4077,7 +4106,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // If we're becoming invisible, update the client visibility if we are not running an // animation. Otherwise, we'll update client visibility in onAnimationFinished. if (visible || !isAnimating()) { - setClientHidden(!visible); + setClientVisible(visible); } if (!displayContent.mClosingApps.contains(this) @@ -4104,7 +4133,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // no animation but there will still be a transition set. // We still need to delay hiding the surface such that it // can be synchronized with showing the next surface in the transition. - if (isHidden() && !delayed && !displayContent.mAppTransition.isTransitionSet()) { + if (!isVisible() && !delayed && !displayContent.mAppTransition.isTransitionSet()) { SurfaceControl.openTransaction(); for (int i = mChildren.size() - 1; i >= 0; i--) { mChildren.get(i).mWinAnimator.hide("immediately hidden"); @@ -4116,12 +4145,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return delayed; } - @Override - void setHidden(boolean hidden) { - super.setHidden(hidden); - scheduleAnimation(); - } - /** * See {@link Activity#setDisablePreviewScreenshots}. */ @@ -4550,7 +4573,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // If the activity is stopped, stopping, cycle to an active state. We avoid doing // this when there is an activity waiting to become translucent as the extra binder // calls will lead to noticeable jank. A later call to - // ActivityStack#ensureActivitiesVisibleLocked will bring the activity to a proper + // ActivityStack#ensureActivitiesVisible will bring the activity to a proper // active state. if (!isState(STARTED, RESUMED, PAUSED, STOPPED, STOPPING) || getActivityStack().mTranslucentActivityWaiting != null) { @@ -4882,8 +4905,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A void startFreezingScreen() { ProtoLog.i(WM_DEBUG_ORIENTATION, - "Set freezing of %s: hidden=%b freezing=%b visibleRequested=%b. %s", - appToken, isHidden(), mFreezingScreen, mVisibleRequested, + "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s", + appToken, isVisible(), mFreezingScreen, mVisibleRequested, new RuntimeException().fillInStackTrace()); if (mVisibleRequested) { if (!mFreezingScreen) { @@ -4921,8 +4944,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A return; } ProtoLog.v(WM_DEBUG_ORIENTATION, - "Clear freezing of %s: hidden=%b freezing=%b", appToken, - isHidden(), isFreezingScreen()); + "Clear freezing of %s: visible=%b freezing=%b", appToken, + isVisible(), isFreezingScreen()); stopFreezingScreen(true, force); } } @@ -5082,7 +5105,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean nowGone = mReportedVisibilityResults.nowGone; boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting; - boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting && !isHidden(); + boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting && isVisible(); if (!nowGone) { // If the app is not yet gone, then it can only become visible/drawn. if (!nowDrawn) { @@ -5110,18 +5133,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } - boolean isClientHidden() { - return mClientHidden; + boolean isClientVisible() { + return mClientVisible; } - void setClientHidden(boolean hideClient) { - if (mClientHidden == hideClient || (hideClient && mDeferHidingClient)) { + void setClientVisible(boolean clientVisible) { + if (mClientVisible == clientVisible || (!clientVisible && mDeferHidingClient)) { return; } ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, - "setClientHidden: %s clientHidden=%b Callers=%s", this, hideClient, + "setClientVisible: %s clientVisible=%b Callers=%s", this, clientVisible, Debug.getCallers(5)); - mClientHidden = hideClient; + mClientVisible = clientVisible; sendAppVisibilityToClients(); } @@ -5443,11 +5466,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // well there is no point now. ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Nulling last startingData"); mStartingData = null; - if (mHiddenSetFromTransferredStartingWindow) { - // We set the hidden state to false for the token from a transferred starting window. - // We now reset it back to true since the starting window was the last window in the - // token. - setHidden(true); + if (mVisibleSetFromTransferredStartingWindow) { + // We set the visible state to true for the token from a transferred starting + // window. We now reset it back to false since the starting window was the last + // window in the token. + setVisible(false); } } else if (mChildren.size() == 1 && startingSurface != null && !isRelaunching()) { // If this is the last window except for a starting transition window, @@ -5785,7 +5808,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @Override void prepareSurfaces() { - final boolean show = !isHidden() || isAnimating(); + final boolean show = isVisible() || isAnimating(); if (mSurfaceControl != null) { if (show && !mLastSurfaceShowing) { @@ -5904,7 +5927,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A "AppWindowToken"); clearThumbnail(); - setClientHidden(isHidden() && !mVisibleRequested); + setClientVisible(isVisible() || mVisibleRequested); getDisplayContent().computeImeTargetIfNeeded(this); @@ -6216,9 +6239,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // relatively fixed. overrideConfig.colorMode = fullConfig.colorMode; overrideConfig.densityDpi = fullConfig.densityDpi; - overrideConfig.screenLayout = fullConfig.screenLayout - & (Configuration.SCREENLAYOUT_LONG_MASK - | Configuration.SCREENLAYOUT_SIZE_MASK); // The smallest screen width is the short side of screen bounds. Because the bounds // and density won't be changed, smallestScreenWidthDp is also fixed. overrideConfig.smallestScreenWidthDp = fullConfig.smallestScreenWidthDp; @@ -6353,6 +6373,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // Use resolvedBounds to compute other override configurations such as appBounds task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration, mCompatDisplayInsets); + // Use current screen layout as source because the size of app is independent to parent. + resolvedConfig.screenLayout = Task.computeScreenLayoutOverride( + getConfiguration().screenLayout, resolvedConfig.screenWidthDp, + resolvedConfig.screenHeightDp); // Use parent orientation if it cannot be decided by bounds, so the activity can fit inside // the parent bounds appropriately. @@ -7287,12 +7311,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A writeToProto(proto, APP_WINDOW_TOKEN, WindowTraceLogLevel.ALL); writeIdentifierToProto(proto, IDENTIFIER); proto.write(STATE, mState.toString()); - proto.write(VISIBLE, mVisibleRequested); + proto.write(VISIBLE_REQUESTED, mVisibleRequested); proto.write(FRONT_OF_TASK, isRootOfTask()); if (hasProcess()) { proto.write(PROC_ID, app.getPid()); } proto.write(TRANSLUCENT, !occludesParent()); + proto.write(VISIBLE, mVisible); } public void writeToProto(ProtoOutputStream proto, long fieldId) { @@ -7323,8 +7348,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } proto.write(FILLS_PARENT, mOccludesParent); proto.write(APP_STOPPED, mAppStopped); - proto.write(VISIBLE_REQUESTED, mVisibleRequested); - proto.write(CLIENT_HIDDEN, mClientHidden); + proto.write(com.android.server.wm.AppWindowTokenProto.VISIBLE_REQUESTED, mVisibleRequested); + proto.write(CLIENT_VISIBLE, mClientVisible); proto.write(DEFER_HIDING_CLIENT, mDeferHidingClient); proto.write(REPORTED_DRAWN, reportedDrawn); proto.write(REPORTED_VISIBLE, reportedVisible); @@ -7337,11 +7362,12 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } proto.write(STARTING_DISPLAYED, startingDisplayed); proto.write(STARTING_MOVED, startingMoved); - proto.write(HIDDEN_SET_FROM_TRANSFERRED_STARTING_WINDOW, - mHiddenSetFromTransferredStartingWindow); + proto.write(VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW, + mVisibleSetFromTransferredStartingWindow); for (Rect bounds : mFrozenBounds) { bounds.writeToProto(proto, FROZEN_BOUNDS); } + proto.write(com.android.server.wm.AppWindowTokenProto.VISIBLE, mVisible); proto.end(token); } diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index ac94125469ba..f1c47eb8644c 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -62,7 +62,6 @@ import static com.android.server.am.ActivityStackProto.DISPLAY_ID; import static com.android.server.am.ActivityStackProto.FULLSCREEN; import static com.android.server.am.ActivityStackProto.RESUMED_ACTIVITY; import static com.android.server.am.ActivityStackProto.STACK; -import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED; import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; @@ -119,7 +118,6 @@ import static com.android.server.wm.StackProto.DEFER_REMOVAL; import static com.android.server.wm.StackProto.FILLS_PARENT; import static com.android.server.wm.StackProto.MINIMIZE_AMOUNT; import static com.android.server.wm.StackProto.WINDOW_CONTAINER; -import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE; import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT; @@ -203,7 +201,7 @@ import java.util.function.Consumer; class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarget, ConfigurationContainerListener { private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_ATM; - private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE; + static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE; private static final String TAG_APP = TAG + POSTFIX_APP; private static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP; private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE; @@ -212,10 +210,10 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg private static final String TAG_STACK = TAG + POSTFIX_STACK; private static final String TAG_STATES = TAG + POSTFIX_STATES; private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH; - private static final String TAG_TASKS = TAG + POSTFIX_TASKS; + static final String TAG_TASKS = TAG + POSTFIX_TASKS; private static final String TAG_TRANSITION = TAG + POSTFIX_TRANSITION; private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING; - private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY; + static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY; // Ticks during which we check progress while waiting for an app to launch. private static final int LAUNCH_TICK = 500; @@ -516,6 +514,10 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg } } + private static final ResetTargetTaskHelper sResetTargetTaskHelper = new ResetTargetTaskHelper(); + private final EnsureActivitiesVisibleHelper mEnsureActivitiesVisibleHelper = + new EnsureActivitiesVisibleHelper(this); + int numActivities() { int count = 0; for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) { @@ -1492,8 +1494,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg void goToSleep() { // Ensure visibility without updating configuration, as activities are about to sleep. - ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */, - !PRESERVE_WINDOWS); + ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, !PRESERVE_WINDOWS); // Make sure any paused or stopped but visible activities are now sleeping. // This ensures that the activity's onStop() is called. @@ -1979,127 +1980,25 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg * Make sure that all activities that need to be visible in the stack (that is, they * currently can be seen by the user) actually are and update their configuration. */ - final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges, + void ensureActivitiesVisible(ActivityRecord starting, int configChanges, boolean preserveWindows) { - ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows, - true /* notifyClients */); + ensureActivitiesVisible(starting, configChanges, preserveWindows, true /* notifyClients */); } /** * Ensure visibility with an option to also update the configuration of visible activities. - * @see #ensureActivitiesVisibleLocked(ActivityRecord, int, boolean) + * @see #ensureActivitiesVisible(ActivityRecord, int, boolean) * @see RootActivityContainer#ensureActivitiesVisible(ActivityRecord, int, boolean) */ // TODO: Should be re-worked based on the fact that each task as a stack in most cases. - final void ensureActivitiesVisibleLocked(ActivityRecord starting, int configChanges, + void ensureActivitiesVisible(ActivityRecord starting, int configChanges, boolean preserveWindows, boolean notifyClients) { mTopActivityOccludesKeyguard = false; mTopDismissingKeyguardActivity = null; mStackSupervisor.getKeyguardController().beginActivityVisibilityUpdate(); try { - ActivityRecord top = topRunningActivityLocked(); - if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible behind " + top - + " configChanges=0x" + Integer.toHexString(configChanges)); - if (top != null) { - checkTranslucentActivityWaiting(top); - } - - // If the top activity is not fullscreen, then we need to - // make sure any activities under it are now visible. - boolean aboveTop = top != null; - final boolean stackShouldBeVisible = shouldBeVisible(starting); - boolean behindFullscreenActivity = !stackShouldBeVisible; - // We should not resume activities that being launched behind because these - // activities are actually behind other fullscreen activities, but still required - // to be visible (such as performing Recents animation). - final boolean resumeTopActivity = isFocusable() && isInStackLocked(starting) == null - && top != null && !top.mLaunchTaskBehind; - for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) { - final Task task = getChildAt(taskNdx); - for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) { - final ActivityRecord r = task.getChildAt(activityNdx); - final boolean isTop = r == top; - if (aboveTop && !isTop) { - continue; - } - aboveTop = false; - - final boolean reallyVisible = r.shouldBeVisible(behindFullscreenActivity, - false /* ignoringKeyguard */); - // Check whether activity should be visible without Keyguard influence - if (r.visibleIgnoringKeyguard) { - if (r.occludesParent()) { - // At this point, nothing else needs to be shown in this task. - if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Fullscreen: at " + r - + " stackVisible=" + stackShouldBeVisible - + " behindFullscreen=" + behindFullscreenActivity); - behindFullscreenActivity = true; - } else { - behindFullscreenActivity = false; - } - } - - if (reallyVisible) { - if (r.finishing) { - continue; - } - if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make visible? " + r - + " finishing=" + r.finishing + " state=" + r.getState()); - // First: if this is not the current activity being started, make - // sure it matches the current configuration. - if (r != starting && notifyClients) { - r.ensureActivityConfiguration(0 /* globalChanges */, preserveWindows, - true /* ignoreVisibility */); - } - - if (!r.attachedToProcess()) { - makeVisibleAndRestartIfNeeded(starting, configChanges, isTop, - resumeTopActivity && isTop, r); - } else if (r.mVisibleRequested) { - // If this activity is already visible, then there is nothing to do here. - if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, - "Skipping: already visible at " + r); - - if (r.mClientVisibilityDeferred && notifyClients) { - r.makeClientVisible(); - } - - r.handleAlreadyVisible(); - if (notifyClients) { - r.makeActiveIfNeeded(starting); - } - } else { - r.makeVisibleIfNeeded(starting, notifyClients); - } - // Aggregate current change flags. - configChanges |= r.configChangeFlags; - } else { - if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make invisible? " + r - + " finishing=" + r.finishing + " state=" + r.getState() - + " stackShouldBeVisible=" + stackShouldBeVisible - + " behindFullscreenActivity=" + behindFullscreenActivity - + " mLaunchTaskBehind=" + r.mLaunchTaskBehind); - r.makeInvisible(); - } - } - final int windowingMode = getWindowingMode(); - if (windowingMode == WINDOWING_MODE_FREEFORM) { - // The visibility of tasks and the activities they contain in freeform stack are - // determined individually unlike other stacks where the visibility or fullscreen - // status of an activity in a previous task affects other. - behindFullscreenActivity = !stackShouldBeVisible; - } else if (isActivityTypeHome()) { - if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Home task: at " + task - + " stackShouldBeVisible=" + stackShouldBeVisible - + " behindFullscreenActivity=" + behindFullscreenActivity); - // No other task in the home stack should be visible behind the home activity. - // Home activities is usually a translucent activity with the wallpaper behind - // them. However, when they don't have the wallpaper behind them, we want to - // show activities in the next application stack behind them vs. another - // task in the home stack like recents. - behindFullscreenActivity = true; - } - } + mEnsureActivitiesVisibleHelper.process( + starting, configChanges, preserveWindows, notifyClients); if (mTranslucentActivityWaiting != null && mUndrawnActivitiesBelowTopTranslucent.isEmpty()) { @@ -2214,7 +2113,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg return (flags & FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0; } - private void checkTranslucentActivityWaiting(ActivityRecord top) { + void checkTranslucentActivityWaiting(ActivityRecord top) { if (mTranslucentActivityWaiting != top) { mUndrawnActivitiesBelowTopTranslucent.clear(); if (mTranslucentActivityWaiting != null) { @@ -2226,31 +2125,6 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg } } - private boolean makeVisibleAndRestartIfNeeded(ActivityRecord starting, int configChanges, - boolean isTop, boolean andResume, ActivityRecord r) { - // We need to make sure the app is running if it's the top, or it is just made visible from - // invisible. If the app is already visible, it must have died while it was visible. In this - // case, we'll show the dead window but will not restart the app. Otherwise we could end up - // thrashing. - if (isTop || !r.mVisibleRequested) { - // This activity needs to be visible, but isn't even running... - // get it started and resume if no other stack in this stack is resumed. - if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Start and freeze screen for " + r); - if (r != starting) { - r.startFreezingScreenLocked(configChanges); - } - if (!r.mVisibleRequested || r.mLaunchTaskBehind) { - if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Starting and making visible: " + r); - r.setVisibility(true); - } - if (r != starting) { - mStackSupervisor.startSpecificActivityLocked(r, andResume, true /* checkConfig */); - return true; - } - } - return false; - } - void convertActivityToTranslucent(ActivityRecord r) { mTranslucentActivityWaiting = r; mUndrawnActivitiesBelowTopTranslucent.clear(); @@ -2490,7 +2364,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg && next.containsDismissKeyguardWindow(); if (canShowWhenLocked || mayDismissKeyguard) { - ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */, + ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, !PRESERVE_WINDOWS); nothingToResume = shouldSleepActivities(); } @@ -2819,7 +2693,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg next.showStartingWindow(null /* prev */, false /* newTask */, false /* taskSwitch */); } - mStackSupervisor.startSpecificActivityLocked(next, true, false); + mStackSupervisor.startSpecificActivity(next, true, false); return true; } @@ -2846,7 +2720,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next); } if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Restarting " + next); - mStackSupervisor.startSpecificActivityLocked(next, true, true); + mStackSupervisor.startSpecificActivity(next, true, true); } return true; @@ -2980,7 +2854,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg // If the caller has requested that the target task be // reset, then do so. if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { - resetTaskIfNeededLocked(r, r); + resetTaskIfNeeded(r, r); doShow = topRunningNonDelayedActivityLocked(null) == r; } } else if (options != null && options.getAnimationType() @@ -2991,7 +2865,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg // Don't do a starting window for mLaunchTaskBehind. More importantly make sure we // tell WindowManager that r is visible even though it is at the back of the stack. r.setVisibility(true); - ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); + ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); // Go ahead to execute app transition for this activity since the app transition // will not be triggered through the resume channel. getDisplay().mDisplayContent.executeAppTransition(); @@ -3052,297 +2926,6 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg } /** - * Helper method for {@link #resetTaskIfNeededLocked(ActivityRecord, ActivityRecord)}. - * Performs a reset of the given task, if needed for new activity start. - * @param task The task containing the Activity (taskTop) that might be reset. - * @param forceReset Flag indicating if clear task was requested - * @return An ActivityOptions that needs to be processed. - */ - private ActivityOptions resetTargetTaskIfNeededLocked(Task task, boolean forceReset) { - ActivityOptions topOptions = null; - - // Tracker of the end of currently handled reply chain (sublist) of activities. What happens - // to activities in the same chain will depend on what the end activity of the chain needs. - int replyChainEnd = -1; - boolean canMoveOptions = true; - int numTasksCreated = 0; - - // We only do this for activities that are not the root of the task (since if we finish - // the root, we may no longer have the task!). - final int numActivities = task.getChildCount(); - int lastActivityNdx = task.findRootIndex(true /* effectiveRoot */); - if (lastActivityNdx == -1) { - lastActivityNdx = 0; - } - for (int i = numActivities - 1; i > lastActivityNdx; --i) { - ActivityRecord target = task.getChildAt(i); - // TODO: Why is this needed? Looks like we're breaking the loop before we reach the root - if (target.isRootOfTask()) break; - - final int flags = target.info.flags; - final boolean finishOnTaskLaunch = - (flags & ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0; - final boolean allowTaskReparenting = - (flags & ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0; - final boolean clearWhenTaskReset = - (target.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0; - - if (!finishOnTaskLaunch - && !clearWhenTaskReset - && target.resultTo != null) { - // If this activity is sending a reply to a previous - // activity, we can't do anything with it now until - // we reach the start of the reply chain. - // XXX note that we are assuming the result is always - // to the previous activity, which is almost always - // the case but we really shouldn't count on. - if (replyChainEnd < 0) { - replyChainEnd = i; - } - } else if (!finishOnTaskLaunch - && !clearWhenTaskReset - && allowTaskReparenting - && target.taskAffinity != null - && !target.taskAffinity.equals(task.affinity)) { - // If this activity has an affinity for another - // task, then we need to move it out of here. We will - // move it as far out of the way as possible, to the - // bottom of the activity stack. This also keeps it - // correctly ordered with any activities we previously - // moved. - // TODO: We should probably look for other stacks also, since corresponding task - // with the same affinity is unlikely to be in the same stack. - final Task targetTask; - final ActivityRecord bottom = - hasChild() && getChildAt(0).hasChild() ? - getChildAt(0).getChildAt(0) : null; - if (bottom != null && target.taskAffinity.equals(bottom.getTask().affinity)) { - // If the activity currently at the bottom has the - // same task affinity as the one we are moving, - // then merge it into the same task. - targetTask = bottom.getTask(); - if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target - + " out to bottom task " + targetTask); - } else { - targetTask = createTask( - mStackSupervisor.getNextTaskIdForUserLocked(target.mUserId), - target.info, null /* intent */, null /* voiceSession */, - null /* voiceInteractor */, false /* toTop */); - targetTask.affinityIntent = target.intent; - numTasksCreated++; - if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target - + " out to new task " + targetTask); - } - - boolean noOptions = canMoveOptions; - final int start = replyChainEnd < 0 ? i : replyChainEnd; - for (int srcPos = start; srcPos >= i; --srcPos) { - final ActivityRecord p = task.getChildAt(srcPos); - if (p.finishing) { - continue; - } - - canMoveOptions = false; - if (noOptions && topOptions == null) { - topOptions = p.takeOptionsLocked(false /* fromClient */); - if (topOptions != null) { - noOptions = false; - } - } - if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, - "Removing activity " + p + " from task=" + task + " adding to task=" - + targetTask + " Callers=" + Debug.getCallers(4)); - if (DEBUG_TASKS) Slog.v(TAG_TASKS, - "Pushing next activity " + p + " out to target's task " + target); - p.reparent(targetTask, 0 /* position - bottom */, "resetTargetTaskIfNeeded"); - } - - positionChildAtBottom(targetTask); - mStackSupervisor.mRecentTasks.add(targetTask); - replyChainEnd = -1; - } else if (forceReset || finishOnTaskLaunch || clearWhenTaskReset) { - // If the activity should just be removed -- either - // because it asks for it, or the task should be - // cleared -- then finish it and anything that is - // part of its reply chain. - int end; - if (clearWhenTaskReset) { - // In this case, we want to finish this activity - // and everything above it, so be sneaky and pretend - // like these are all in the reply chain. - end = task.getChildCount() - 1; - } else if (replyChainEnd < 0) { - end = i; - } else { - end = replyChainEnd; - } - boolean noOptions = canMoveOptions; - for (int srcPos = i; srcPos <= end; srcPos++) { - ActivityRecord p = task.getChildAt(srcPos); - if (p.finishing) { - continue; - } - canMoveOptions = false; - if (noOptions && topOptions == null) { - topOptions = p.takeOptionsLocked(false /* fromClient */); - if (topOptions != null) { - noOptions = false; - } - } - if (DEBUG_TASKS) Slog.w(TAG_TASKS, - "resetTaskIntendedTask: calling finishActivity on " + p); - if (p.finishIfPossible("reset-task", false /* oomAdj */) - == FINISH_RESULT_REMOVED) { - end--; - srcPos--; - } - } - replyChainEnd = -1; - } else { - // If we were in the middle of a chain, well the - // activity that started it all doesn't want anything - // special, so leave it all as-is. - replyChainEnd = -1; - } - } - - // Create target stack for the newly created tasks if necessary - if (numTasksCreated > 0) { - ActivityDisplay display = getDisplay(); - final boolean singleTaskInstanceDisplay = display.isSingleTaskInstance(); - if (singleTaskInstanceDisplay) { - display = mRootActivityContainer.getDefaultDisplay(); - } - - if (singleTaskInstanceDisplay || display.alwaysCreateStack(getWindowingMode(), - getActivityType())) { - for (int index = numTasksCreated - 1; index >= 0; index--) { - final Task targetTask = getChildAt(index); - final ActivityStack targetStack = display.getOrCreateStack(getWindowingMode(), - getActivityType(), false /* onTop */); - targetTask.reparent(targetStack, false /* toTop */, - REPARENT_LEAVE_STACK_IN_PLACE, false /* animate */, - true /* deferResume */, "resetTargetTask"); - } - } - } - - return topOptions; - } - - /** - * Helper method for {@link #resetTaskIfNeededLocked(ActivityRecord, ActivityRecord)}. - * Processes all of the activities in a given Task looking for an affinity with the task - * of resetTaskIfNeededLocked.taskTop. - * @param affinityTask The task we are looking for an affinity to. - * @param task Task that resetTaskIfNeededLocked.taskTop belongs to. - * @param topTaskIsHigher True if #task has already been processed by resetTaskIfNeededLocked. - * @param forceReset Flag indicating if clear task was requested - */ - // TODO: Consider merging with #resetTargetTaskIfNeededLocked() above - private int resetAffinityTaskIfNeededLocked(Task affinityTask, Task task, - boolean topTaskIsHigher, boolean forceReset, int taskInsertionPoint) { - // Tracker of the end of currently handled reply chain (sublist) of activities. What happens - // to activities in the same chain will depend on what the end activity of the chain needs. - int replyChainEnd = -1; - final String taskAffinity = task.affinity; - - final int numActivities = task.getChildCount(); - - // Do not operate on or below the effective root Activity. - int lastActivityNdx = affinityTask.findRootIndex(true /* effectiveRoot */); - if (lastActivityNdx == -1) { - lastActivityNdx = 0; - } - for (int i = numActivities - 1; i > lastActivityNdx; --i) { - ActivityRecord target = task.getChildAt(i); - // TODO: Why is this needed? Looks like we're breaking the loop before we reach the root - if (target.isRootOfTask()) break; - - final int flags = target.info.flags; - boolean finishOnTaskLaunch = (flags & ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0; - boolean allowTaskReparenting = (flags & ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0; - - if (target.resultTo != null) { - // If this activity is sending a reply to a previous - // activity, we can't do anything with it now until - // we reach the start of the reply chain. - // XXX note that we are assuming the result is always - // to the previous activity, which is almost always - // the case but we really shouldn't count on. - if (replyChainEnd < 0) { - replyChainEnd = i; - } - } else if (topTaskIsHigher - && allowTaskReparenting - && taskAffinity != null - && taskAffinity.equals(target.taskAffinity)) { - // This activity has an affinity for our task. Either remove it if we are - // clearing or move it over to our task. Note that - // we currently punt on the case where we are resetting a - // task that is not at the top but who has activities above - // with an affinity to it... this is really not a normal - // case, and we will need to later pull that task to the front - // and usually at that point we will do the reset and pick - // up those remaining activities. (This only happens if - // someone starts an activity in a new task from an activity - // in a task that is not currently on top.) - if (forceReset || finishOnTaskLaunch) { - final int start = replyChainEnd >= 0 ? replyChainEnd : i; - if (DEBUG_TASKS) Slog.v(TAG_TASKS, - "Finishing task at index " + start + " to " + i); - for (int srcPos = start; srcPos >= i; --srcPos) { - final ActivityRecord p = task.getChildAt(srcPos); - if (p.finishing) { - continue; - } - p.finishIfPossible("move-affinity", false /* oomAdj */); - } - } else { - if (taskInsertionPoint < 0) { - taskInsertionPoint = task.getChildCount(); - - } - - final int start = replyChainEnd >= 0 ? replyChainEnd : i; - if (DEBUG_TASKS) Slog.v(TAG_TASKS, - "Reparenting from task=" + affinityTask + ":" + start + "-" + i - + " to task=" + task + ":" + taskInsertionPoint); - for (int srcPos = start; srcPos >= i; --srcPos) { - final ActivityRecord p = task.getChildAt(srcPos); - p.reparent(task, taskInsertionPoint, "resetAffinityTaskIfNeededLocked"); - - if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, - "Removing and adding activity " + p + " to stack at " + task - + " callers=" + Debug.getCallers(3)); - if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Pulling activity " + p - + " from " + srcPos + " in to resetting task " + task); - } - positionChildAtTop(task); - - // Now we've moved it in to place... but what if this is - // a singleTop activity and we have put it on top of another - // instance of the same activity? Then we drop the instance - // below so it remains singleTop. - if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) { - final ArrayList<ActivityRecord> taskActivities = task.mChildren; - final int targetNdx = taskActivities.indexOf(target); - if (targetNdx > 0) { - final ActivityRecord p = taskActivities.get(targetNdx - 1); - if (p.intent.getComponent().equals(target.intent.getComponent())) { - p.finishIfPossible("replace", false /* oomAdj */); - } - } - } - } - - replyChainEnd = -1; - } - } - return taskInsertionPoint; - } - - /** * Reset the task by reparenting the activities that have same affinity to the task or * reparenting the activities that have different affinityies out of the task, while these * activities allow task reparenting. @@ -3352,37 +2935,16 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg * @return The non-finishing top activity of the task after reset or the original task top * activity if all activities within the task are finishing. */ - final ActivityRecord resetTaskIfNeededLocked(ActivityRecord taskTop, - ActivityRecord newActivity) { + ActivityRecord resetTaskIfNeeded(ActivityRecord taskTop, ActivityRecord newActivity) { final boolean forceReset = (newActivity.info.flags & ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0; final Task task = taskTop.getTask(); - // False until we evaluate the Task associated with taskTop. Switches to true - // for remaining tasks. Used for later tasks to reparent to task. - boolean taskFound = false; - // If ActivityOptions are moved out and need to be aborted or moved to taskTop. - ActivityOptions topOptions = null; - - // Preserve the location for reparenting in the new task. - int reparentInsertionPoint = -1; - - for (int i = getChildCount() - 1; i >= 0; --i) { - final Task targetTask = getChildAt(i); - - if (targetTask == task) { - topOptions = resetTargetTaskIfNeededLocked(task, forceReset); - taskFound = true; - } else { - reparentInsertionPoint = resetAffinityTaskIfNeededLocked(targetTask, task, - taskFound, forceReset, reparentInsertionPoint); - } - } + final ActivityOptions topOptions = sResetTargetTaskHelper.process(this, task, forceReset); - int taskNdx = mChildren.indexOf(task); - if (taskNdx >= 0) { - ActivityRecord newTop = getChildAt(taskNdx).getTopNonFinishingActivity(); + if (mChildren.contains(task)) { + final ActivityRecord newTop = task.getTopNonFinishingActivity(); if (newTop != null) { taskTop = newTop; } @@ -3391,11 +2953,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg if (topOptions != null) { // If we got some ActivityOptions from an activity on top that // was removed from the task, propagate them to the new real top. - if (taskTop != null) { - taskTop.updateOptionsLocked(topOptions); - } else { - topOptions.abort(); - } + taskTop.updateOptionsLocked(topOptions); } return taskTop; @@ -4697,7 +4255,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg // The task might have already been running and its visibility needs to be synchronized with // the visibility of the stack / windows. - ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); + ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); mRootActivityContainer.resumeFocusedStacksTopActivities(); } @@ -5219,7 +4777,7 @@ class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarg displayContent.layoutAndAssignWindowLayersIfNeeded(); } - private void positionChildAtBottom(Task child) { + void positionChildAtBottom(Task child) { // If there are other focusable stacks on the display, the z-order of the display should not // be changed just because a task was placed at the bottom. E.g. if it is moving the topmost // task to bottom, the next focusable stack on the same display should be focused. diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 6ea80d259a4d..304f2300e308 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -975,7 +975,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } } - void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) { + void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) { // Is this activity's application already running? final WindowProcessController wpc = mService.getProcessController(r.processName, r.info.applicationInfo.uid); @@ -1742,12 +1742,12 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { * to the fullscreen stack. This is to guarantee that when we are removing a stack, * that the client receives onStop() before it is reparented. We do this by detaching * the stack from the display so that it will be considered invisible when - * ensureActivitiesVisibleLocked() is called, and all of its activitys will be marked + * ensureActivitiesVisible() is called, and all of its activitys will be marked * invisible as well and added to the stopping list. After which we process the * stopping list by handling the idle. */ stack.mForceHidden = true; - stack.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS); + stack.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); stack.mForceHidden = false; activityIdleInternalLocked(null, false /* fromTimeout */, true /* processPausingActivites */, null /* configuration */); @@ -2072,7 +2072,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { mRecentTasks.add(task); mService.getTaskChangeNotificationController().notifyTaskStackChanged(); - stack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); + stack.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); // When launching tasks behind, update the last active time of the top task after the new // task has been shown briefly diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index be7f88700d88..8455c6d04b3d 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1574,7 +1574,7 @@ class ActivityStarter { // Also, we don't want to resume activities in a task that currently has an overlay // as the starting activity just needs to be in the visible paused state until the // over is removed. - mTargetStack.ensureActivitiesVisibleLocked(mStartActivity, 0, !PRESERVE_WINDOWS); + mTargetStack.ensureActivitiesVisible(mStartActivity, 0, !PRESERVE_WINDOWS); // Go ahead and tell window manager to execute app transition for this activity // since the app transition will not be triggered through the resume channel. mTargetStack.getDisplay().mDisplayContent.executeAppTransition(); @@ -1812,7 +1812,7 @@ class ActivityStarter { final boolean resetTask = reusedActivity != null && (mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0; if (resetTask) { - targetTaskTop = mTargetStack.resetTaskIfNeededLocked(targetTaskTop, mStartActivity); + targetTaskTop = mTargetStack.resetTaskIfNeeded(targetTaskTop, mStartActivity); } if ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index bef6af350269..ff1b42377f5f 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -688,15 +688,16 @@ public class AppTransitionController { * compare z-order. * * @param apps The list of apps to search. - * @param ignoreHidden If set to true, ignores apps that are {@link ActivityRecord#isHidden}. + * @param ignoreInvisible If set to true, ignores apps that are not + * {@link ActivityRecord#isVisible}. * @return The top {@link ActivityRecord}. */ - private ActivityRecord getTopApp(ArraySet<ActivityRecord> apps, boolean ignoreHidden) { + private ActivityRecord getTopApp(ArraySet<ActivityRecord> apps, boolean ignoreInvisible) { int topPrefixOrderIndex = Integer.MIN_VALUE; ActivityRecord topApp = null; for (int i = apps.size() - 1; i >= 0; i--) { final ActivityRecord app = apps.valueAt(i); - if (ignoreHidden && app.isHidden()) { + if (ignoreInvisible && !app.isVisible()) { continue; } final int prefixOrderIndex = app.getPrefixOrderIndex(); diff --git a/services/core/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java index b4cecff728fd..8ab17950f4fc 100644 --- a/services/core/java/com/android/server/wm/BlackFrame.java +++ b/services/core/java/com/android/server/wm/BlackFrame.java @@ -52,7 +52,6 @@ public class BlackFrame { .setParent(surfaceControl) .build(); transaction.setWindowCrop(surface, w, h); - transaction.setLayerStack(surface, dc.getDisplayId()); transaction.setAlpha(surface, 1); transaction.setLayer(surface, layer); transaction.setPosition(surface, left, top); diff --git a/services/core/java/com/android/server/wm/CompatModePackages.java b/services/core/java/com/android/server/wm/CompatModePackages.java index 104805fba308..320ca65d215b 100644 --- a/services/core/java/com/android/server/wm/CompatModePackages.java +++ b/services/core/java/com/android/server/wm/CompatModePackages.java @@ -346,7 +346,7 @@ public final class CompatModePackages { false /* preserveWindow */); // And we need to make sure at this point that all other activities // are made visible with the correct configuration. - stack.ensureActivitiesVisibleLocked(starting, 0, !PRESERVE_WINDOWS); + stack.ensureActivitiesVisible(starting, 0, !PRESERVE_WINDOWS); } } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 456f65009eae..283b92c8e478 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -644,11 +644,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo + " config reported=" + w.isLastConfigReportedToClient()); final ActivityRecord activity = w.mActivityRecord; if (gone) Slog.v(TAG, " GONE: mViewVisibility=" + w.mViewVisibility - + " mRelayoutCalled=" + w.mRelayoutCalled + " hidden=" + w.mToken.isHidden() + + " mRelayoutCalled=" + w.mRelayoutCalled + " visible=" + w.mToken.isVisible() + " visibleRequested=" + (activity != null && activity.mVisibleRequested) + " parentHidden=" + w.isParentWindowHidden()); else Slog.v(TAG, " VIS: mViewVisibility=" + w.mViewVisibility - + " mRelayoutCalled=" + w.mRelayoutCalled + " hidden=" + w.mToken.isHidden() + + " mRelayoutCalled=" + w.mRelayoutCalled + " visible=" + w.mToken.isVisible() + " visibleRequested=" + (activity != null && activity.mVisibleRequested) + " parentHidden=" + w.isParentWindowHidden()); } @@ -3053,7 +3053,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo wsa.destroySurface(); mWmService.mForceRemoves.add(w); mTmpWindow = w; - } else if (w.mActivityRecord != null && w.mActivityRecord.isClientHidden()) { + } else if (w.mActivityRecord != null && !w.mActivityRecord.isClientVisible()) { Slog.w(TAG_WM, "LEAKED SURFACE (app token hidden): " + w + " surface=" + wsa.mSurfaceController + " token=" + w.mActivityRecord); @@ -4512,6 +4512,12 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mName = name; } + @Override + boolean hasActivity() { + // I am a non-app-window-container :P + return false; + } + void addChild(WindowToken token) { addChild(token, mWindowComparator); } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 8d5f90d53019..77e557b87648 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -3126,12 +3126,13 @@ public class DisplayPolicy { : new AppearanceRegion[]{ new AppearanceRegion(fullscreenAppearance, fullscreenStackBounds)}; final boolean isNavbarColorManagedByIme = result.second; + String cause = win.toString(); mHandler.post(() -> { StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); if (statusBar != null) { final int displayId = getDisplayId(); statusBar.setDisableFlags(displayId, visibility & StatusBarManager.DISABLE_MASK, - win.toString()); + cause); if (transientState.first.length > 0) { statusBar.showTransient(displayId, transientState.first); } @@ -3143,8 +3144,10 @@ public class DisplayPolicy { statusBar.topAppWindowChanged(displayId, isFullscreen, isImmersive); // TODO(b/118118435): Remove this after removing system UI visibilities. - mDisplayContent.statusBarVisibilityChanged( - visibility & ~(View.STATUS_BAR_UNHIDE | View.NAVIGATION_BAR_UNHIDE)); + synchronized (mLock) { + mDisplayContent.statusBarVisibilityChanged( + visibility & ~(View.STATUS_BAR_UNHIDE | View.NAVIGATION_BAR_UNHIDE)); + } } }); return diff; diff --git a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java index dbc452f6e026..2da76ea64d85 100644 --- a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java +++ b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import android.content.res.Configuration; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.view.IDisplayWindowListener; @@ -62,6 +63,28 @@ class DisplayWindowListenerController { mDisplayListeners.finishBroadcast(); } + void dispatchDisplayChanged(ActivityDisplay display, Configuration newConfig) { + // Only report changed if this has actually been added to the hierarchy already. + boolean isInHierarchy = false; + for (int i = 0; i < display.getParent().getChildCount(); ++i) { + if (display.getParent().getChildAt(i) == display) { + isInHierarchy = true; + } + } + if (!isInHierarchy) { + return; + } + int count = mDisplayListeners.beginBroadcast(); + for (int i = 0; i < count; ++i) { + try { + mDisplayListeners.getBroadcastItem(i).onDisplayConfigurationChanged( + display.mDisplayId, newConfig); + } catch (RemoteException e) { + } + } + mDisplayListeners.finishBroadcast(); + } + void dispatchDisplayRemoved(ActivityDisplay display) { int count = mDisplayListeners.beginBroadcast(); for (int i = 0; i < count; ++i) { diff --git a/services/core/java/com/android/server/wm/EmbeddedWindowController.java b/services/core/java/com/android/server/wm/EmbeddedWindowController.java index 24948a254a26..0291017cd039 100644 --- a/services/core/java/com/android/server/wm/EmbeddedWindowController.java +++ b/services/core/java/com/android/server/wm/EmbeddedWindowController.java @@ -16,8 +16,8 @@ package com.android.server.wm; -import static com.android.server.wm.ActivityRecord.INVALID_PID; +import android.annotation.Nullable; import android.os.IBinder; import android.os.RemoteException; import android.util.ArrayMap; @@ -39,8 +39,21 @@ class EmbeddedWindowController { mWmLock = wmLock; } - void add(IBinder inputToken, IWindow window, WindowState hostWindowState, int ownerUid, - int ownerPid) { + /** + * Adds a new embedded window. + * + * @param inputToken input channel token passed in by the embedding process when it requests + * the server to add an input channel to the embedded surface. + * @param window client token used to clean up the map if the embedding process dies + * @param hostWindowState input channel token belonging to the host window. This is needed to + * handle input callbacks to wm. It's used when raising ANR and when + * the user taps out side of the focused region on screen. This can be + * null if there is no host window. + * @param ownerUid calling uid + * @param ownerPid calling pid used for anr blaming + */ + void add(IBinder inputToken, IWindow window, @Nullable WindowState hostWindowState, + int ownerUid, int ownerPid) { EmbeddedWindow embeddedWindow = new EmbeddedWindow(window, hostWindowState, ownerUid, ownerPid); try { @@ -61,31 +74,30 @@ class EmbeddedWindowController { return embeddedWindow != null ? embeddedWindow.mHostWindowState : null; } - int getOwnerPid(IBinder inputToken) { - EmbeddedWindow embeddedWindow = mWindows.get(inputToken); - return embeddedWindow != null ? embeddedWindow.mOwnerPid : INVALID_PID; - } - void remove(IWindow client) { - for (ArrayMap.Entry<IBinder, EmbeddedWindow> entry: mWindows.entrySet()) { - if (entry.getValue().mClient.asBinder() == client.asBinder()) { - mWindows.remove(entry.getKey()); + for (int i = mWindows.size() - 1; i >= 0; i--) { + if (mWindows.valueAt(i).mClient.asBinder() == client.asBinder()) { + mWindows.removeAt(i); return; } } } void removeWindowsWithHost(WindowState host) { - for (ArrayMap.Entry<IBinder, EmbeddedWindow> entry: mWindows.entrySet()) { - if (entry.getValue().mHostWindowState == host) { - mWindows.remove(entry.getKey()); + for (int i = mWindows.size() - 1; i >= 0; i--) { + if (mWindows.valueAt(i).mHostWindowState == host) { + mWindows.removeAt(i); } } } - private static class EmbeddedWindow { + EmbeddedWindow get(IBinder inputToken) { + return mWindows.get(inputToken); + } + + static class EmbeddedWindow { final IWindow mClient; - final WindowState mHostWindowState; + @Nullable final WindowState mHostWindowState; final int mOwnerUid; final int mOwnerPid; diff --git a/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java new file mode 100644 index 000000000000..3aae1b1d7c8f --- /dev/null +++ b/services/core/java/com/android/server/wm/EnsureActivitiesVisibleHelper.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2019 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.server.wm; + +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; + +import static com.android.server.wm.ActivityStack.TAG_VISIBILITY; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY; + +import android.util.Slog; + +import com.android.internal.util.function.pooled.PooledConsumer; +import com.android.internal.util.function.pooled.PooledLambda; + +/** Helper class to ensure activities are in the right visible state for a container. */ +class EnsureActivitiesVisibleHelper { + private final ActivityStack mContiner; + private ActivityRecord mTop; + private ActivityRecord mStarting; + private boolean mAboveTop; + private boolean mContainerShouldBeVisible; + private boolean mBehindFullscreenActivity; + private int mConfigChanges; + private boolean mPreserveWindows; + private boolean mNotifyClients; + + EnsureActivitiesVisibleHelper(ActivityStack container) { + mContiner = container; + } + + void reset(ActivityRecord starting, int configChanges, boolean preserveWindows, + boolean notifyClients) { + mStarting = starting; + mTop = mContiner.topRunningActivityLocked(); + // If the top activity is not fullscreen, then we need to make sure any activities under it + // are now visible. + mAboveTop = mTop != null; + mContainerShouldBeVisible = mContiner.shouldBeVisible(mStarting); + mBehindFullscreenActivity = !mContainerShouldBeVisible; + mConfigChanges = configChanges; + mPreserveWindows = preserveWindows; + mNotifyClients = notifyClients; + } + + /** + * Ensure visibility with an option to also update the configuration of visible activities. + * @see ActivityStack#ensureActivitiesVisible(ActivityRecord, int, boolean) + * @see RootActivityContainer#ensureActivitiesVisible(ActivityRecord, int, boolean) + */ + void process(ActivityRecord starting, int configChanges, boolean preserveWindows, + boolean notifyClients) { + reset(starting, configChanges, preserveWindows, notifyClients); + + if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "ensureActivitiesVisible behind " + mTop + + " configChanges=0x" + Integer.toHexString(configChanges)); + if (mTop != null) { + mContiner.checkTranslucentActivityWaiting(mTop); + } + + // We should not resume activities that being launched behind because these + // activities are actually behind other fullscreen activities, but still required + // to be visible (such as performing Recents animation). + final boolean resumeTopActivity = mTop != null && !mTop.mLaunchTaskBehind + && mContiner.isFocusable() && mContiner.isInStackLocked(starting) == null; + + final PooledConsumer f = PooledLambda.obtainConsumer( + EnsureActivitiesVisibleHelper::setActivityVisibilityState, this, + PooledLambda.__(ActivityRecord.class), resumeTopActivity); + mContiner.forAllActivities(f); + f.recycle(); + } + + private void setActivityVisibilityState(ActivityRecord r, final boolean resumeTopActivity) { + final boolean isTop = r == mTop; + if (mAboveTop && !isTop) { + return; + } + mAboveTop = false; + + final boolean reallyVisible = r.shouldBeVisible( + mBehindFullscreenActivity, false /* ignoringKeyguard */); + + // Check whether activity should be visible without Keyguard influence + if (r.visibleIgnoringKeyguard) { + if (r.occludesParent()) { + // At this point, nothing else needs to be shown in this task. + if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Fullscreen: at " + r + + " stackVisible=" + mContainerShouldBeVisible + + " behindFullscreen=" + mBehindFullscreenActivity); + mBehindFullscreenActivity = true; + } else { + mBehindFullscreenActivity = false; + } + } + + if (reallyVisible) { + if (r.finishing) { + return; + } + if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make visible? " + r + + " finishing=" + r.finishing + " state=" + r.getState()); + // First: if this is not the current activity being started, make + // sure it matches the current configuration. + if (r != mStarting && mNotifyClients) { + r.ensureActivityConfiguration(0 /* globalChanges */, mPreserveWindows, + true /* ignoreVisibility */); + } + + if (!r.attachedToProcess()) { + makeVisibleAndRestartIfNeeded(mStarting, mConfigChanges, isTop, + resumeTopActivity && isTop, r); + } else if (r.mVisibleRequested) { + // If this activity is already visible, then there is nothing to do here. + if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, + "Skipping: already visible at " + r); + + if (r.mClientVisibilityDeferred && mNotifyClients) { + r.makeClientVisible(); + } + + r.handleAlreadyVisible(); + if (mNotifyClients) { + r.makeActiveIfNeeded(mStarting); + } + } else { + r.makeVisibleIfNeeded(mStarting, mNotifyClients); + } + // Aggregate current change flags. + mConfigChanges |= r.configChangeFlags; + } else { + if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make invisible? " + r + + " finishing=" + r.finishing + " state=" + r.getState() + + " stackShouldBeVisible=" + mContainerShouldBeVisible + + " behindFullscreenActivity=" + mBehindFullscreenActivity + + " mLaunchTaskBehind=" + r.mLaunchTaskBehind); + r.makeInvisible(); + } + + final int windowingMode = mContiner.getWindowingMode(); + if (windowingMode == WINDOWING_MODE_FREEFORM) { + // The visibility of tasks and the activities they contain in freeform stack are + // determined individually unlike other stacks where the visibility or fullscreen + // status of an activity in a previous task affects other. + mBehindFullscreenActivity = !mContainerShouldBeVisible; + } else if (mContiner.isActivityTypeHome()) { + if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Home task: at " + mContiner + + " stackShouldBeVisible=" + mContainerShouldBeVisible + + " behindFullscreenActivity=" + mBehindFullscreenActivity); + // No other task in the home stack should be visible behind the home activity. + // Home activities is usually a translucent activity with the wallpaper behind + // them. However, when they don't have the wallpaper behind them, we want to + // show activities in the next application stack behind them vs. another + // task in the home stack like recents. + mBehindFullscreenActivity = true; + } + } + + private void makeVisibleAndRestartIfNeeded(ActivityRecord starting, int configChanges, + boolean isTop, boolean andResume, ActivityRecord r) { + // We need to make sure the app is running if it's the top, or it is just made visible from + // invisible. If the app is already visible, it must have died while it was visible. In this + // case, we'll show the dead window but will not restart the app. Otherwise we could end up + // thrashing. + if (!isTop && r.mVisibleRequested) { + return; + } + + // This activity needs to be visible, but isn't even running... + // get it started and resume if no other stack in this stack is resumed. + if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Start and freeze screen for " + r); + if (r != starting) { + r.startFreezingScreenLocked(configChanges); + } + if (!r.mVisibleRequested || r.mLaunchTaskBehind) { + if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Starting and making visible: " + r); + r.setVisibility(true); + } + if (r != starting) { + mContiner.mStackSupervisor.startSpecificActivity(r, andResume, true /* checkConfig */); + } + } +} diff --git a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java b/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java index 29b6bc479f72..d9cf637ffaf8 100644 --- a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java +++ b/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java @@ -105,8 +105,10 @@ class HighRefreshRateBlacklist { private class OnPropertiesChangedListener implements DeviceConfig.OnPropertiesChangedListener { public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) { - updateBlacklist( - properties.getString(KEY_HIGH_REFRESH_RATE_BLACKLIST, null /*default*/)); + if (properties.getKeyset().contains(KEY_HIGH_REFRESH_RATE_BLACKLIST)) { + updateBlacklist( + properties.getString(KEY_HIGH_REFRESH_RATE_BLACKLIST, null /*default*/)); + } } } } diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java index 2a6fb4af86ab..1f9f8830c34b 100644 --- a/services/core/java/com/android/server/wm/InputManagerCallback.java +++ b/services/core/java/com/android/server/wm/InputManagerCallback.java @@ -20,6 +20,7 @@ import android.view.KeyEvent; import android.view.WindowManager; import com.android.server.input.InputManagerService; +import com.android.server.wm.EmbeddedWindowController.EmbeddedWindow; import java.io.PrintWriter; import java.util.concurrent.atomic.AtomicReference; @@ -90,20 +91,39 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal int windowPid = INVALID_PID; //TODO(b/141764879) Limit scope of wm lock when input calls notifyANR synchronized (mService.mGlobalLock) { + + // Check if we can blame a window if (token != null) { windowState = mService.mInputToWindowMap.get(token); if (windowState != null) { activity = windowState.mActivityRecord; windowPid = windowState.mSession.mPid; - } else { - // Check if this is an embedded window and if so get the embedded app pid - windowPid = mService.mEmbeddedWindowController.getOwnerPid(token); - WindowState hostWindowState = - mService.mEmbeddedWindowController.getHostWindow(token); - aboveSystem = isWindowAboveSystem(hostWindowState); + // Figure out whether this window is layered above system windows. + // We need to do this here to help the activity manager know how to + // layer its ANR dialog. + aboveSystem = isWindowAboveSystem(windowState); + } + } + + // Check if we can blame an embedded window + if (token != null && windowState == null) { + EmbeddedWindow embeddedWindow = mService.mEmbeddedWindowController.get(token); + if (embeddedWindow != null) { + windowPid = embeddedWindow.mOwnerPid; + WindowState hostWindowState = embeddedWindow.mHostWindowState; + if (hostWindowState == null) { + // The embedded window has no host window and we cannot easily determine + // its z order. Try to place the anr dialog as high as possible. + aboveSystem = true; + } else { + aboveSystem = isWindowAboveSystem(hostWindowState); + } } } + // Check if we can blame an activity. If we don't have an activity to blame, pull out + // the token passed in via input application handle. This can happen if there are no + // focused windows but input dispatcher knows the focused app. if (activity == null && inputApplicationHandle != null) { activity = ActivityRecord.forTokenLocked(inputApplicationHandle.token); } @@ -112,10 +132,6 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal Slog.i(TAG_WM, "Input event dispatching timed out " + "sending to " + windowState.mAttrs.getTitle() + ". Reason: " + reason); - // Figure out whether this window is layered above system windows. - // We need to do this here to help the activity manager know how to - // layer its ANR dialog. - aboveSystem = isWindowAboveSystem(windowState); } else if (activity != null) { Slog.i(TAG_WM, "Input event dispatching timed out " + "sending to application " + activity.stringName diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index a17bd24294c5..824a3c8193d2 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -134,7 +134,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, if (!targetActivity.attachedToProcess()) { ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Real start recents"); - mStackSupervisor.startSpecificActivityLocked(targetActivity, false /* andResume */, + mStackSupervisor.startSpecificActivity(targetActivity, false /* andResume */, false /* checkConfig */); // Make sure the activity won't be involved in transition. if (targetActivity.getDisplayContent() != null) { @@ -368,7 +368,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks, // transition (the target activity will be one of closing apps). if (!controller.shouldDeferCancelWithScreenshot() && !targetStack.isFocusedStackOnDisplay()) { - targetStack.ensureActivitiesVisibleLocked(null /* starting */, + targetStack.ensureActivitiesVisible(null /* starting */, 0 /* starting */, false /* preserveWindows */); } // Keep target stack in place, nothing changes, so ignore the transition diff --git a/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java new file mode 100644 index 000000000000..413dfd5eac97 --- /dev/null +++ b/services/core/java/com/android/server/wm/ResetTargetTaskHelper.java @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2019 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.server.wm; + +import static com.android.server.wm.ActivityStack.TAG_ADD_REMOVE; +import static com.android.server.wm.ActivityStack.TAG_TASKS; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE; +import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS; +import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE; + +import android.app.ActivityOptions; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.os.Debug; +import android.util.Slog; + +import com.android.internal.util.function.pooled.PooledConsumer; +import com.android.internal.util.function.pooled.PooledFunction; +import com.android.internal.util.function.pooled.PooledLambda; + +import java.util.ArrayList; + +/** Helper class for processing the reset of a task. */ +class ResetTargetTaskHelper { + private Task mTask; + private ActivityStack mParent; + private Task mTargetTask; + private ActivityRecord mRoot; + private boolean mForceReset; + private boolean mCanMoveOptions; + private boolean mTargetTaskFound; + private int mActivityReparentPosition; + private ActivityOptions mTopOptions; + private ArrayList<ActivityRecord> mResultActivities = new ArrayList<>(); + private ArrayList<ActivityRecord> mAllActivities = new ArrayList<>(); + private ArrayList<Task> mCreatedTasks = new ArrayList<>(); + + private void reset(Task task) { + mTask = task; + mRoot = null; + mCanMoveOptions = true; + mTopOptions = null; + mResultActivities.clear(); + mAllActivities.clear(); + mCreatedTasks.clear(); + } + + ActivityOptions process(ActivityStack parent, Task targetTask, boolean forceReset) { + mParent = parent; + mForceReset = forceReset; + mTargetTask = targetTask; + mTargetTaskFound = false; + mActivityReparentPosition = -1; + + final PooledConsumer c = PooledLambda.obtainConsumer( + ResetTargetTaskHelper::processTask, this, PooledLambda.__(Task.class)); + parent.forAllTasks(c); + c.recycle(); + + reset(null); + mParent = null; + return mTopOptions; + } + + private void processTask(Task task) { + reset(task); + mRoot = task.getRootActivity(true); + if (mRoot == null) return; + + final boolean isTargetTask = task == mTargetTask; + if (isTargetTask) mTargetTaskFound = true; + + final PooledFunction f = PooledLambda.obtainFunction( + ResetTargetTaskHelper::processActivity, this, + PooledLambda.__(ActivityRecord.class), isTargetTask); + task.forAllActivities(f); + f.recycle(); + + processCreatedTasks(); + } + + private boolean processActivity(ActivityRecord r, boolean isTargetTask) { + // End processing if we have reached the root. + if (r == mRoot) return true; + + mAllActivities.add(r); + final int flags = r.info.flags; + final boolean finishOnTaskLaunch = + (flags & ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0; + final boolean allowTaskReparenting = + (flags & ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0; + final boolean clearWhenTaskReset = + (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0; + + if (isTargetTask) { + if (!finishOnTaskLaunch && !clearWhenTaskReset) { + if (r.resultTo != null) { + // If this activity is sending a reply to a previous activity, we can't do + // anything with it now until we reach the start of the reply chain. + // NOTE: that we are assuming the result is always to the previous activity, + // which is almost always the case but we really shouldn't count on. + mResultActivities.add(r); + return false; + } + if (allowTaskReparenting && r.taskAffinity != null + && !r.taskAffinity.equals(mTask.affinity)) { + // If this activity has an affinity for another task, then we need to move + // it out of here. We will move it as far out of the way as possible, to the + // bottom of the activity stack. This also keeps it correctly ordered with + // any activities we previously moved. + // TODO: We should probably look for other stacks also, since corresponding + // task with the same affinity is unlikely to be in the same stack. + final Task targetTask; + final ActivityRecord bottom = mParent.getActivity( + (ar) -> true, false /*traverseTopToBottom*/); + + if (bottom != null && r.taskAffinity.equals(bottom.getTask().affinity)) { + // If the activity currently at the bottom has the same task affinity as + // the one we are moving, then merge it into the same task. + targetTask = bottom.getTask(); + if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + + r + " out to bottom task " + targetTask); + } else { + targetTask = mParent.createTask( + mParent.mStackSupervisor.getNextTaskIdForUserLocked(r.mUserId), + r.info, null /* intent */, null /* voiceSession */, + null /* voiceInteractor */, false /* toTop */); + targetTask.affinityIntent = r.intent; + mCreatedTasks.add(targetTask); + if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + + r + " out to new task " + targetTask); + } + + mResultActivities.add(r); + processResultActivities(r, targetTask, 0 /*bottom*/, true, true); + mParent.positionChildAtBottom(targetTask); + mParent.mStackSupervisor.mRecentTasks.add(targetTask); + return false; + } + } + if (mForceReset || finishOnTaskLaunch || clearWhenTaskReset) { + // If the activity should just be removed either because it asks for it, or the + // task should be cleared, then finish it and anything that is part of its reply + // chain. + if (clearWhenTaskReset) { + // In this case, we want to finish this activity and everything above it, + // so be sneaky and pretend like these are all in the reply chain. + finishActivities(mAllActivities, "clearWhenTaskReset"); + } else { + mResultActivities.add(r); + finishActivities(mResultActivities, "reset-task"); + } + + mResultActivities.clear(); + return false; + } else { + // If we were in the middle of a chain, well the activity that started it all + // doesn't want anything special, so leave it all as-is. + mResultActivities.clear(); + } + + return false; + + } else { + mResultActivities.add(r); + if (r.resultTo != null) { + // If this activity is sending a reply to a previous activity, we can't do + // anything with it now until we reach the start of the reply chain. + // NOTE: that we are assuming the result is always to the previous activity, + // which is almost always the case but we really shouldn't count on. + return false; + } else if (mTargetTaskFound && allowTaskReparenting && mTargetTask.affinity != null + && mTargetTask.affinity.equals(r.taskAffinity)) { + // This activity has an affinity for our task. Either remove it if we are + // clearing or move it over to our task. Note that we currently punt on the case + // where we are resetting a task that is not at the top but who has activities + // above with an affinity to it... this is really not a normal case, and we will + // need to later pull that task to the front and usually at that point we will + // do the reset and pick up those remaining activities. (This only happens if + // someone starts an activity in a new task from an activity in a task that is + // not currently on top.) + if (mForceReset || finishOnTaskLaunch) { + finishActivities(mResultActivities, "move-affinity"); + return false; + } + if (mActivityReparentPosition == -1) { + mActivityReparentPosition = mTargetTask.getChildCount(); + } + + processResultActivities( + r, mTargetTask, mActivityReparentPosition, false, false); + + mParent.positionChildAtTop(mTargetTask); + + // Now we've moved it in to place...but what if this is a singleTop activity and + // we have put it on top of another instance of the same activity? Then we drop + // the instance below so it remains singleTop. + if (r.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) { + final ArrayList<ActivityRecord> taskActivities = mTargetTask.mChildren; + final int targetNdx = taskActivities.indexOf(r); + if (targetNdx > 0) { + final ActivityRecord p = taskActivities.get(targetNdx - 1); + if (p.intent.getComponent().equals(r.intent.getComponent())) { + p.finishIfPossible("replace", false /* oomAdj */); + } + } + } + } + return false; + } + } + + private void finishActivities(ArrayList<ActivityRecord> activities, String reason) { + boolean noOptions = mCanMoveOptions; + + while (!activities.isEmpty()) { + final ActivityRecord p = activities.remove(0); + if (p.finishing) continue; + + noOptions = takeOption(p, noOptions); + + if (DEBUG_TASKS) Slog.w(TAG_TASKS, + "resetTaskIntendedTask: calling finishActivity on " + p); + p.finishIfPossible(reason, false /* oomAdj */); + } + } + + private void processResultActivities(ActivityRecord target, Task targetTask, int position, + boolean ignoreFinishing, boolean takeOptions) { + boolean noOptions = mCanMoveOptions; + + while (!mResultActivities.isEmpty()) { + final ActivityRecord p = mResultActivities.remove(0); + if (ignoreFinishing&& p.finishing) continue; + + if (takeOptions) { + noOptions = takeOption(p, noOptions); + } + if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing activity " + p + " from task=" + + mTask + " adding to task=" + targetTask + " Callers=" + Debug.getCallers(4)); + if (DEBUG_TASKS) Slog.v(TAG_TASKS, + "Pushing next activity " + p + " out to target's task " + target); + p.reparent(targetTask, position, "resetTargetTaskIfNeeded"); + } + } + + private void processCreatedTasks() { + if (mCreatedTasks.isEmpty()) return; + + ActivityDisplay display = mParent.getDisplay(); + final boolean singleTaskInstanceDisplay = display.isSingleTaskInstance(); + if (singleTaskInstanceDisplay) { + display = mParent.mRootActivityContainer.getDefaultDisplay(); + } + + final int windowingMode = mParent.getWindowingMode(); + final int activityType = mParent.getActivityType(); + if (!singleTaskInstanceDisplay && !display.alwaysCreateStack(windowingMode, activityType)) { + return; + } + + while (!mCreatedTasks.isEmpty()) { + final Task targetTask = mCreatedTasks.remove(mCreatedTasks.size() - 1); + final ActivityStack targetStack = display.getOrCreateStack( + windowingMode, activityType, false /* onTop */); + targetTask.reparent(targetStack, false /* toTop */, REPARENT_LEAVE_STACK_IN_PLACE, + false /* animate */, true /* deferResume */, "resetTargetTask"); + } + } + + private boolean takeOption(ActivityRecord p, boolean noOptions) { + mCanMoveOptions = false; + if (noOptions && mTopOptions == null) { + mTopOptions = p.takeOptionsLocked(false /* fromClient */); + if (mTopOptions != null) { + noOptions = false; + } + } + return noOptions; + } +} diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index c0432b679e86..a175d63dce80 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -621,8 +621,15 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { return false; } + @Override public void grantInputChannel(int displayId, SurfaceControl surface, IWindow window, IBinder hostInputToken, InputChannel outInputChannel) { + if (hostInputToken == null && !mCanAddInternalSystemWindow) { + // Callers without INTERNAL_SYSTEM_WINDOW permission cannot grant input channel to + // embedded windows without providing a host window input token + throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission"); + } + final long identity = Binder.clearCallingIdentity(); try { mService.grantInputChannel(mUid, mPid, displayId, surface, window, diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 6ddd943dcf68..28c5575b604b 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -1067,12 +1067,30 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta /** Returns the first non-finishing activity from the bottom. */ ActivityRecord getRootActivity() { - final int rootActivityIndex = findRootIndex(false /* effectiveRoot */); - if (rootActivityIndex == -1) { - // There are no non-finishing activities in the task. - return null; + // TODO: Figure out why we historical ignore relinquish identity for this case... + return getRootActivity(true /*ignoreRelinquishIdentity*/, false /*setToBottomIfNone*/); + } + + ActivityRecord getRootActivity(boolean setToBottomIfNone) { + return getRootActivity(false /*ignoreRelinquishIdentity*/, false /*setToBottomIfNone*/); + } + + ActivityRecord getRootActivity(boolean ignoreRelinquishIdentity, boolean setToBottomIfNone) { + ActivityRecord root; + if (ignoreRelinquishIdentity) { + root = getActivity((r) -> !r.finishing, false /*traverseTopToBottom*/); + } else { + root = getActivity((r) -> + !r.finishing && (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0, + false /*traverseTopToBottom*/); + } + + if (root == null && setToBottomIfNone) { + // All activities in the task are either finishing or relinquish task identity. + // But we still want to update the intent, so let's use the bottom activity. + root = getActivity((r) -> true, false /*traverseTopToBottom*/); } - return getChildAt(rootActivityIndex); + return root; } ActivityRecord getTopNonFinishingActivity() { @@ -2046,17 +2064,22 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta // could never go away in Honeycomb. final int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density); final int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density); - // We're only overriding LONG, SIZE and COMPAT parts of screenLayout, so we start - // override calculation with partial default. // Reducing the screen layout starting from its parent config. - final int sl = parentConfig.screenLayout - & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK); - final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp); - final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp); - inOutConfig.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize); + inOutConfig.screenLayout = computeScreenLayoutOverride(parentConfig.screenLayout, + compatScreenWidthDp, compatScreenHeightDp); } } + /** Computes LONG, SIZE and COMPAT parts of {@link Configuration#screenLayout}. */ + static int computeScreenLayoutOverride(int sourceScreenLayout, int screenWidthDp, + int screenHeightDp) { + sourceScreenLayout = sourceScreenLayout + & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK); + final int longSize = Math.max(screenWidthDp, screenHeightDp); + final int shortSize = Math.min(screenWidthDp, screenHeightDp); + return Configuration.reduceScreenLayout(sourceScreenLayout, longSize, shortSize); + } + @Override void resolveOverrideConfiguration(Configuration newParentConfig) { mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds()); @@ -2508,7 +2531,7 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta for (int i = mChildren.size() - 1; i >= 0; i--) { final ActivityRecord token = mChildren.get(i); // skip hidden (or about to hide) apps - if (token.mIsExiting || token.isClientHidden() || !token.mVisibleRequested) { + if (token.mIsExiting || !token.isClientVisible() || !token.mVisibleRequested) { continue; } final WindowState win = token.findMainWindow(); @@ -2726,10 +2749,9 @@ class Task extends WindowContainer<ActivityRecord> implements ConfigurationConta ActivityRecord getTopVisibleActivity() { for (int i = mChildren.size() - 1; i >= 0; i--) { - final ActivityRecord token = mChildren.get(i); - // skip hidden (or about to hide) apps - if (!token.mIsExiting && !token.isClientHidden() && token.mVisibleRequested) { - return token; + final ActivityRecord activity = mChildren.get(i); + if (!activity.mIsExiting && activity.isClientVisible() && activity.mVisibleRequested) { + return activity; } } return null; diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index ef7940368f15..6ff4b2e504f1 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -120,7 +120,7 @@ class WallpaperController { } mFindResults.resetTopWallpaper = true; - if (w.mActivityRecord != null && w.mActivityRecord.isHidden() + if (w.mActivityRecord != null && !w.mActivityRecord.isVisible() && !w.mActivityRecord.isAnimating(TRANSITION)) { // If this window's app token is hidden and not animating, it is of no interest to us. @@ -278,9 +278,11 @@ class WallpaperController { for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) { final WallpaperWindowToken token = mWallpaperTokens.get(i); token.hideWallpaperToken(wasDeferred, "hideWallpapers"); - if (DEBUG_WALLPAPER_LIGHT && !token.isHidden()) Slog.d(TAG, "Hiding wallpaper " + token - + " from " + winGoingAway + " target=" + mWallpaperTarget + " prev=" - + mPrevWallpaperTarget + "\n" + Debug.getCallers(5, " ")); + if (DEBUG_WALLPAPER_LIGHT && token.isVisible()) { + Slog.d(TAG, "Hiding wallpaper " + token + + " from " + winGoingAway + " target=" + mWallpaperTarget + " prev=" + + mPrevWallpaperTarget + "\n" + Debug.getCallers(5, " ")); + } } } diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java index 528cece9a78b..d23bf978cbab 100644 --- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java +++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java @@ -56,7 +56,6 @@ class WallpaperWindowToken extends WindowToken { final WindowState wallpaper = mChildren.get(j); wallpaper.hideWallpaperWindow(wasDeferred, reason); } - setHidden(true); } void sendWindowWallpaperCommand( @@ -88,9 +87,7 @@ class WallpaperWindowToken extends WindowToken { final int dw = displayInfo.logicalWidth; final int dh = displayInfo.logicalHeight; - if (isHidden() == visible) { - setHidden(!visible); - + if (isVisible() != visible) { // Need to do a layout to ensure the wallpaper now has the correct size. mDisplayContent.setLayoutNeeded(); } @@ -118,10 +115,9 @@ class WallpaperWindowToken extends WindowToken { void updateWallpaperWindows(boolean visible) { - if (isHidden() == visible) { + if (isVisible() != visible) { if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, - "Wallpaper token " + token + " hidden=" + !visible); - setHidden(!visible); + "Wallpaper token " + token + " visible=" + visible); // Need to do a layout to ensure the wallpaper now has the correct size. mDisplayContent.setLayoutNeeded(); } diff --git a/services/core/java/com/android/server/wm/Watermark.java b/services/core/java/com/android/server/wm/Watermark.java index 725aaa48c645..4e1b2177c87c 100644 --- a/services/core/java/com/android/server/wm/Watermark.java +++ b/services/core/java/com/android/server/wm/Watermark.java @@ -121,8 +121,7 @@ class Watermark { .setBufferSize(1, 1) .setFormat(PixelFormat.TRANSLUCENT) .build(); - t.setLayerStack(ctrl, mDisplay.getLayerStack()) - .setLayer(ctrl, WindowManagerService.TYPE_LAYER_MULTIPLIER * 100) + t.setLayer(ctrl, WindowManagerService.TYPE_LAYER_MULTIPLIER * 100) .setPosition(ctrl, 0, 0) .show(ctrl); mSurface.copyFrom(ctrl); diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 3e78d5ef0f65..453514b2f46e 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -79,6 +79,7 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.LinkedList; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Predicate; /** @@ -775,10 +776,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< /** * @return {@code true} if in this subtree of the hierarchy we have an - * {@ode ActivityRecord#isAnimating(TRANSITION)}, {@code false} otherwise. + * {@code ActivityRecord#isAnimating(TRANSITION)}, {@code false} otherwise. */ boolean isAppTransitioning() { - return forAllActivities(app -> app.isAnimating(TRANSITION)); + return getActivity(app -> app.isAnimating(TRANSITION)) != null; } /** @@ -1094,7 +1095,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< wrapper.release(); } - boolean forAllActivities(ToBooleanFunction<ActivityRecord> callback) { + boolean forAllActivities(Function<ActivityRecord, Boolean> callback) { for (int i = mChildren.size() - 1; i >= 0; --i) { if (mChildren.get(i).forAllActivities(callback)) { return true; @@ -1103,6 +1104,72 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< return false; } + void forAllActivities(Consumer<ActivityRecord> callback) { + forAllActivities(callback, true /*traverseTopToBottom*/); + } + + void forAllActivities(Consumer<ActivityRecord> callback, boolean traverseTopToBottom) { + if (traverseTopToBottom) { + for (int i = mChildren.size() - 1; i >= 0; --i) { + mChildren.get(i).forAllActivities(callback, traverseTopToBottom); + } + } else { + final int count = mChildren.size(); + for (int i = 0; i < count; i++) { + mChildren.get(i).forAllActivities(callback, traverseTopToBottom); + } + } + } + + /** @return {@code true} if this node or any of its children contains an activity. */ + boolean hasActivity() { + for (int i = mChildren.size() - 1; i >= 0; --i) { + if (mChildren.get(i).hasActivity()) { + return true; + } + } + return false; + } + + ActivityRecord getActivity(Predicate<ActivityRecord> callback) { + return getActivity(callback, true /*traverseTopToBottom*/); + } + + ActivityRecord getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom) { + if (traverseTopToBottom) { + for (int i = mChildren.size() - 1; i >= 0; --i) { + final ActivityRecord r = mChildren.get(i).getActivity(callback, traverseTopToBottom); + if (r != null) { + return r; + } + } + } else { + final int count = mChildren.size(); + for (int i = 0; i < count; i++) { + final ActivityRecord r = mChildren.get(i).getActivity(callback, traverseTopToBottom); + if (r != null) { + return r; + } + } + } + + return null; + } + + ActivityRecord getTopActivity(boolean includeFinishing, boolean includeOverlays) { + // Break down into 4 calls to avoid object creation due to capturing input params. + if (includeFinishing) { + if (includeOverlays) { + return getActivity((r) -> true); + } + return getActivity((r) -> !r.mTaskOverlay); + } else if (includeOverlays) { + return getActivity((r) -> !r.finishing); + } + + return getActivity((r) -> !r.finishing && !r.mTaskOverlay); + } + void forAllWallpaperWindows(Consumer<WallpaperWindowToken> callback) { for (int i = mChildren.size() - 1; i >= 0; --i) { mChildren.get(i).forAllWallpaperWindows(callback); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index a42f2e14c71a..5afcab0cc11c 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1668,7 +1668,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mInTouchMode) { res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE; } - if (win.mActivityRecord == null || !win.mActivityRecord.isClientHidden()) { + if (win.mActivityRecord == null || win.mActivityRecord.isClientVisible()) { res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE; } @@ -2201,7 +2201,7 @@ public class WindowManagerService extends IWindowManager.Stub // associated appToken is not hidden. final boolean shouldRelayout = viewVisibility == View.VISIBLE && (win.mActivityRecord == null || win.mAttrs.type == TYPE_APPLICATION_STARTING - || !win.mActivityRecord.isClientHidden()); + || win.mActivityRecord.isClientVisible()); // If we are not currently running the exit animation, we need to see about starting // one. @@ -7674,19 +7674,17 @@ public class WindowManagerService extends IWindowManager.Stub */ void grantInputChannel(int callingUid, int callingPid, int displayId, SurfaceControl surface, IWindow window, IBinder hostInputToken, InputChannel outInputChannel) { - final InputApplicationHandle applicationHandle; + InputApplicationHandle applicationHandle = null; final String name; final InputChannel[] inputChannels; final InputChannel clientChannel; final InputChannel serverChannel; synchronized (mGlobalLock) { final WindowState hostWindow = mInputToWindowMap.get(hostInputToken); - if (hostWindow == null) { - Slog.e(TAG, "Failed to grant input channel"); - return; - } + final String hostWindowName = (hostWindow != null) + ? hostWindow.getWindowTag().toString() : "Internal"; name = "EmbeddedWindow{ u" + UserHandle.getUserId(callingUid) - + " " + hostWindow.getWindowTag() + "}"; + + " " + hostWindowName + "}"; inputChannels = InputChannel.openInputChannelPair(name); serverChannel = inputChannels[0]; @@ -7694,8 +7692,10 @@ public class WindowManagerService extends IWindowManager.Stub mInputManager.registerInputChannel(serverChannel); mEmbeddedWindowController.add(serverChannel.getToken(), window, hostWindow, callingUid, callingPid); - applicationHandle = new InputApplicationHandle( - hostWindow.mInputWindowHandle.inputApplicationHandle); + if (hostWindow != null) { + applicationHandle = new InputApplicationHandle( + hostWindow.mInputWindowHandle.inputApplicationHandle); + } } clientChannel.transferTo(outInputChannel); diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index 22183667832e..5da3eb6d77cb 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -20,7 +20,6 @@ import static android.os.Build.IS_USER; import android.graphics.Point; import android.graphics.Rect; -import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ShellCommand; import android.os.UserHandle; @@ -352,9 +351,7 @@ public class WindowManagerShellCommand extends ShellCommand { } private int runDumpVisibleWindowViews(PrintWriter pw) { - ParcelFileDescriptor outFile = openFileForSystem(getNextArgRequired(), "w"); - try (ZipOutputStream out = new ZipOutputStream( - new ParcelFileDescriptor.AutoCloseOutputStream(outFile))) { + try (ZipOutputStream out = new ZipOutputStream(getRawOutputStream())) { ArrayList<Pair<String, ByteTransferPipe>> requestList = new ArrayList<>(); synchronized (mInternal.mGlobalLock) { // Request dump from all windows parallelly before writing to disk. @@ -368,7 +365,6 @@ public class WindowManagerShellCommand extends ShellCommand { requestList.add(Pair.create(w.getName(), pipe)); } catch (IOException | RemoteException e) { // Skip this window - pw.println("Error for window " + w.getName() + " : " + e.getMessage()); if (pipe != null) { pipe.kill(); } @@ -382,8 +378,6 @@ public class WindowManagerShellCommand extends ShellCommand { data = entry.second.get(); } catch (IOException e) { // Ignore this window - pw.println( - "Error for window " + entry.first + " : " + e.getMessage()); continue; } out.putNextEntry(new ZipEntry(entry.first)); @@ -414,7 +408,7 @@ public class WindowManagerShellCommand extends ShellCommand { pw.println(" Dismiss the keyguard, prompting user for auth if necessary."); pw.println(" set-user-rotation [free|lock] [-d DISPLAY_ID] [rotation]"); pw.println(" Set user rotation mode and user rotation."); - pw.println(" dump-visible-window-views out-file"); + pw.println(" dump-visible-window-views"); pw.println(" Dumps the encoded view hierarchies of visible windows"); pw.println(" set-fix-to-user-rotation [-d DISPLAY_ID] [enabled|disabled]"); pw.println(" Enable or disable rotating display for app requested orientation."); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 593b84f86a2e..044166924489 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1569,7 +1569,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * not the pending requested hidden state. */ boolean isVisibleNow() { - return (!mToken.isHidden() || mAttrs.type == TYPE_APPLICATION_STARTING) + return (mToken.isVisible() || mAttrs.type == TYPE_APPLICATION_STARTING) && isVisible(); } @@ -1642,7 +1642,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP return false; } final boolean parentAndClientVisible = !isParentWindowHidden() - && mViewVisibility == View.VISIBLE && !mToken.isHidden(); + && mViewVisibility == View.VISIBLE && mToken.isVisible(); return mHasSurface && isVisibleByPolicy() && !mDestroying && (parentAndClientVisible || isAnimating(TRANSITION | PARENTS)); } @@ -1661,7 +1661,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } else { final Task task = getTask(); final boolean canFromTask = task != null && task.canAffectSystemUiFlags(); - return canFromTask && !mActivityRecord.isHidden(); + return canFromTask && mActivityRecord.isVisible(); } } @@ -1690,7 +1690,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP final ActivityRecord atoken = mActivityRecord; return mViewVisibility == View.GONE || !mRelayoutCalled - || (atoken == null && mToken.isHidden()) + || (atoken == null && !mToken.isVisible()) || (atoken != null && !atoken.mVisibleRequested) || isParentWindowGoneForLayout() || (mAnimatingExit && !isAnimatingLw()) @@ -2595,7 +2595,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * interacts with it. */ private boolean shouldKeepVisibleDeadAppWindow() { - if (!isWinVisibleLw() || mActivityRecord == null || mActivityRecord.isClientHidden()) { + if (!isWinVisibleLw() || mActivityRecord == null || !mActivityRecord.isClientVisible()) { // Not a visible app window or the app isn't dead. return false; } @@ -2907,13 +2907,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP void sendAppVisibilityToClients() { super.sendAppVisibilityToClients(); - final boolean clientHidden = mActivityRecord.isClientHidden(); - if (mAttrs.type == TYPE_APPLICATION_STARTING && clientHidden) { + final boolean clientVisible = mActivityRecord.isClientVisible(); + if (mAttrs.type == TYPE_APPLICATION_STARTING && !clientVisible) { // Don't hide the starting window. return; } - if (clientHidden) { + if (!clientVisible) { // Once we are notifying the client that it's visibility has changed, we need to prevent // it from destroying child surfaces until the animation has finished. We do this by // detaching any surface control the client added from the client. @@ -2927,8 +2927,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP try { if (DEBUG_VISIBILITY) Slog.v(TAG, - "Setting visibility of " + this + ": " + (!clientHidden)); - mClient.dispatchAppVisibility(!clientHidden); + "Setting visibility of " + this + ": " + clientVisible); + mClient.dispatchAppVisibility(clientVisible); } catch (RemoteException e) { } } @@ -4170,7 +4170,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP + " parentHidden=" + isParentWindowHidden() + " tok.visibleRequested=" + (mActivityRecord != null && mActivityRecord.mVisibleRequested) - + " tok.hidden=" + (mActivityRecord != null && mActivityRecord.isHidden()) + + " tok.visible=" + (mActivityRecord != null && mActivityRecord.isVisible()) + " animating=" + isAnimating(TRANSITION | PARENTS) + " tok animating=" + (mActivityRecord != null && mActivityRecord.isAnimating(TRANSITION)) diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 057f4931dec1..287d7cd8a758 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -29,7 +29,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; import static com.android.server.wm.WindowTokenProto.HASH_CODE; -import static com.android.server.wm.WindowTokenProto.HIDDEN; import static com.android.server.wm.WindowTokenProto.PAUSED; import static com.android.server.wm.WindowTokenProto.WAITING_TO_SHOW; import static com.android.server.wm.WindowTokenProto.WINDOWS; @@ -72,9 +71,6 @@ class WindowToken extends WindowContainer<WindowState> { // Is key dispatching paused for this token? boolean paused = false; - // Should this token's windows be hidden? - private boolean mHidden; - // Temporary for finding which tokens no longer have visible windows. boolean hasVisible; @@ -124,16 +120,6 @@ class WindowToken extends WindowContainer<WindowState> { } } - void setHidden(boolean hidden) { - if (hidden != mHidden) { - mHidden = hidden; - } - } - - boolean isHidden() { - return mHidden; - } - void removeAllWindowsIfPossible() { for (int i = mChildren.size() - 1; i >= 0; --i) { final WindowState win = mChildren.get(i); @@ -152,7 +138,7 @@ class WindowToken extends WindowContainer<WindowState> { // This token is exiting, so allow it to be removed when it no longer contains any windows. mPersistOnEmpty = false; - if (mHidden) { + if (!isVisible()) { return; } @@ -165,7 +151,10 @@ class WindowToken extends WindowContainer<WindowState> { changed |= win.onSetAppExiting(); } - setHidden(true); + final ActivityRecord app = asActivityRecord(); + if (app != null) { + app.setVisible(false); + } if (changed) { mWmService.mWindowPlacerLocked.performSurfacePlacement(); @@ -282,7 +271,6 @@ class WindowToken extends WindowContainer<WindowState> { final WindowState w = mChildren.get(i); w.writeToProto(proto, WINDOWS, logLevel); } - proto.write(HIDDEN, mHidden); proto.write(WAITING_TO_SHOW, waitingToShow); proto.write(PAUSED, paused); proto.end(token); @@ -292,7 +280,6 @@ class WindowToken extends WindowContainer<WindowState> { super.dump(pw, prefix, dumpAll); pw.print(prefix); pw.print("windows="); pw.println(mChildren); pw.print(prefix); pw.print("windowType="); pw.print(windowType); - pw.print(" hidden="); pw.print(mHidden); pw.print(" hasVisible="); pw.println(hasVisible); if (waitingToShow) { pw.print(prefix); pw.print("waitingToShow="); pw.print(waitingToShow); diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp index 746610df11ae..612a1e7074f9 100644 --- a/services/core/jni/com_android_server_VibratorService.cpp +++ b/services/core/jni/com_android_server_VibratorService.cpp @@ -291,7 +291,7 @@ static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jclass) { static void vibratorSetAmplitude(JNIEnv*, jclass, jint amplitude) { if (auto hal = getHal<aidl::IVibrator>()) { - auto status = hal->call(&aidl::IVibrator::IVibrator::setAmplitude, amplitude); + auto status = hal->call(&aidl::IVibrator::IVibrator::setAmplitude, static_cast<float>(amplitude) / UINT8_MAX); if (!status.isOk()) { ALOGE("Failed to set vibrator amplitude: %s", status.toString8().string()); } diff --git a/services/coverage/Android.bp b/services/coverage/Android.bp index 16c9c1bfcdaa..e4f54644df46 100644 --- a/services/coverage/Android.bp +++ b/services/coverage/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.coverage-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.coverage", - srcs: ["java/**/*.java"], + srcs: [":services.coverage-sources"], libs: ["jacocoagent"], } diff --git a/services/devicepolicy/Android.bp b/services/devicepolicy/Android.bp index bffa44e868a7..380ee942af98 100644 --- a/services/devicepolicy/Android.bp +++ b/services/devicepolicy/Android.bp @@ -1,6 +1,13 @@ +filegroup { + name: "services.devicepolicy-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.devicepolicy", - srcs: ["java/**/*.java"], + srcs: [":services.devicepolicy-sources"], libs: [ "services.core", @@ -15,4 +22,4 @@ java_library_static { platform_compat_config { name: "services-devicepolicy-platform-compat-config", src: ":services.devicepolicy", -}
\ No newline at end of file +} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index f1ed1d9d954e..cb4e377c0110 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -281,7 +281,8 @@ public final class SystemServer { "com.android.server.DeviceIdleController"; private static final String BLOB_STORE_MANAGER_SERVICE_CLASS = "com.android.server.blob.BlobStoreManagerService"; - + private static final String APP_SEARCH_MANAGER_SERVICE_CLASS = + "com.android.server.appsearch.AppSearchManagerService"; private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst"; private static final String UNCRYPT_PACKAGE_FILE = "/cache/recovery/uncrypt_file"; @@ -387,15 +388,6 @@ public final class SystemServer { EventLog.writeEvent(EventLogTags.SYSTEM_SERVER_START, mStartCount, mRuntimeStartUptime, mRuntimeStartElapsedTime); - // If a device's clock is before 1970 (before 0), a lot of - // APIs crash dealing with negative numbers, notably - // java.io.File#setLastModified, so instead we fake it and - // hope that time from cell towers or NTP fixes it shortly. - if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) { - Slog.w(TAG, "System clock is before 1970; setting to 1970."); - SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME); - } - // // Default the timezone property to GMT if not set. // @@ -704,7 +696,7 @@ public final class SystemServer { // Bring up recovery system in case a rescue party needs a reboot t.traceBegin("StartRecoverySystemService"); - mSystemServiceManager.startService(RecoverySystemService.class); + mSystemServiceManager.startService(RecoverySystemService.Lifecycle.class); t.traceEnd(); // Now that we have the bare essentials of the OS up and running, take @@ -2023,6 +2015,10 @@ public final class SystemServer { mSystemServiceManager.startBootPhase(t, SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY); t.traceEnd(); + t.traceBegin("AppSearchManagerService"); + mSystemServiceManager.startService(APP_SEARCH_MANAGER_SERVICE_CLASS); + t.traceEnd(); + // These are needed to propagate to the runnable below. final NetworkManagementService networkManagementF = networkManagement; final NetworkStatsService networkStatsF = networkStats; diff --git a/services/midi/Android.bp b/services/midi/Android.bp index 3745e89e8034..20e00834d0ad 100644 --- a/services/midi/Android.bp +++ b/services/midi/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.midi-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.midi", - srcs: ["java/**/*.java"], + srcs: [":services.midi-sources"], libs: ["services.core"], } diff --git a/services/net/Android.bp b/services/net/Android.bp index c56ecd6e19e7..7ef9f448f7ce 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -1,38 +1,34 @@ +filegroup { + name: "services.net-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.net", srcs: [ + ":net-module-utils-srcs", ":tethering-servicesnet-srcs", - "java/**/*.java", + ":services.net-sources", ], static_libs: [ "dnsresolver_aidl_interface-V2-java", "netd_aidl_interface-unstable-java", + "netlink-client", "networkstack-client", "tethering-client", ], } filegroup { - name: "services-networkstack-shared-srcs", - srcs: [ - "java/android/net/ip/InterfaceController.java", // TODO: move to NetworkStack with tethering - "java/android/net/util/InterfaceParams.java", // TODO: move to NetworkStack with IpServer - "java/android/net/shared/*.java", - "java/android/net/netlink/*.java", - ], -} - -filegroup { name: "services-tethering-shared-srcs", srcs: [ ":framework-annotations", "java/android/net/ConnectivityModuleConnector.java", "java/android/net/NetworkStackClient.java", - "java/android/net/ip/InterfaceController.java", - "java/android/net/netlink/*.java", - "java/android/net/util/InterfaceParams.java", "java/android/net/util/NetdService.java", "java/android/net/util/NetworkConstants.java", - "java/android/net/util/SharedLog.java" ], + visibility: ["//frameworks/base/packages/Tethering"], } diff --git a/services/net/java/android/net/ip/InterfaceController.java b/services/net/java/android/net/ip/InterfaceController.java deleted file mode 100644 index 970bc9cf667b..000000000000 --- a/services/net/java/android/net/ip/InterfaceController.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (C) 2017 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.ip; - -import android.net.INetd; -import android.net.InterfaceConfigurationParcel; -import android.net.LinkAddress; -import android.net.util.SharedLog; -import android.os.RemoteException; -import android.os.ServiceSpecificException; -import android.system.OsConstants; - -import java.net.Inet4Address; -import java.net.InetAddress; - - -/** - * Encapsulates the multiple IP configuration operations performed on an interface. - * - * TODO: refactor/eliminate the redundant ways to set and clear addresses. - * - * @hide - */ -public class InterfaceController { - private final static boolean DBG = false; - - private final String mIfName; - private final INetd mNetd; - private final SharedLog mLog; - - public InterfaceController(String ifname, INetd netd, SharedLog log) { - mIfName = ifname; - mNetd = netd; - mLog = log; - } - - private boolean setInterfaceAddress(LinkAddress addr) { - final InterfaceConfigurationParcel ifConfig = new InterfaceConfigurationParcel(); - ifConfig.ifName = mIfName; - ifConfig.ipv4Addr = addr.getAddress().getHostAddress(); - ifConfig.prefixLength = addr.getPrefixLength(); - ifConfig.hwAddr = ""; - ifConfig.flags = new String[0]; - try { - mNetd.interfaceSetCfg(ifConfig); - } catch (RemoteException | ServiceSpecificException e) { - logError("Setting IPv4 address to %s/%d failed: %s", - ifConfig.ipv4Addr, ifConfig.prefixLength, e); - return false; - } - return true; - } - - /** - * Set the IPv4 address of the interface. - */ - public boolean setIPv4Address(LinkAddress address) { - if (!(address.getAddress() instanceof Inet4Address)) { - return false; - } - return setInterfaceAddress(address); - } - - /** - * Clear the IPv4Address of the interface. - */ - public boolean clearIPv4Address() { - return setInterfaceAddress(new LinkAddress("0.0.0.0/0")); - } - - private boolean setEnableIPv6(boolean enabled) { - try { - mNetd.interfaceSetEnableIPv6(mIfName, enabled); - } catch (RemoteException | ServiceSpecificException e) { - logError("%s IPv6 failed: %s", (enabled ? "enabling" : "disabling"), e); - return false; - } - return true; - } - - /** - * Enable IPv6 on the interface. - */ - public boolean enableIPv6() { - return setEnableIPv6(true); - } - - /** - * Disable IPv6 on the interface. - */ - public boolean disableIPv6() { - return setEnableIPv6(false); - } - - /** - * Enable or disable IPv6 privacy extensions on the interface. - * @param enabled Whether the extensions should be enabled. - */ - public boolean setIPv6PrivacyExtensions(boolean enabled) { - try { - mNetd.interfaceSetIPv6PrivacyExtensions(mIfName, enabled); - } catch (RemoteException | ServiceSpecificException e) { - logError("error %s IPv6 privacy extensions: %s", - (enabled ? "enabling" : "disabling"), e); - return false; - } - return true; - } - - /** - * Set IPv6 address generation mode on the interface. - * - * <p>IPv6 should be disabled before changing the mode. - */ - public boolean setIPv6AddrGenModeIfSupported(int mode) { - try { - mNetd.setIPv6AddrGenMode(mIfName, mode); - } catch (RemoteException e) { - logError("Unable to set IPv6 addrgen mode: %s", e); - return false; - } catch (ServiceSpecificException e) { - if (e.errorCode != OsConstants.EOPNOTSUPP) { - logError("Unable to set IPv6 addrgen mode: %s", e); - return false; - } - } - return true; - } - - /** - * Add an address to the interface. - */ - public boolean addAddress(LinkAddress addr) { - return addAddress(addr.getAddress(), addr.getPrefixLength()); - } - - /** - * Add an address to the interface. - */ - public boolean addAddress(InetAddress ip, int prefixLen) { - try { - mNetd.interfaceAddAddress(mIfName, ip.getHostAddress(), prefixLen); - } catch (ServiceSpecificException | RemoteException e) { - logError("failed to add %s/%d: %s", ip, prefixLen, e); - return false; - } - return true; - } - - /** - * Remove an address from the interface. - */ - public boolean removeAddress(InetAddress ip, int prefixLen) { - try { - mNetd.interfaceDelAddress(mIfName, ip.getHostAddress(), prefixLen); - } catch (ServiceSpecificException | RemoteException e) { - logError("failed to remove %s/%d: %s", ip, prefixLen, e); - return false; - } - return true; - } - - /** - * Remove all addresses from the interface. - */ - public boolean clearAllAddresses() { - try { - mNetd.interfaceClearAddrs(mIfName); - } catch (Exception e) { - logError("Failed to clear addresses: %s", e); - return false; - } - return true; - } - - private void logError(String fmt, Object... args) { - mLog.e(String.format(fmt, args)); - } -} diff --git a/services/net/java/android/net/netlink/ConntrackMessage.java b/services/net/java/android/net/netlink/ConntrackMessage.java deleted file mode 100644 index 6978739886c3..000000000000 --- a/services/net/java/android/net/netlink/ConntrackMessage.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2017 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.netlink; - -import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK; -import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE; -import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST; - -import static java.nio.ByteOrder.BIG_ENDIAN; - -import android.system.OsConstants; - -import java.net.Inet4Address; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - - -/** - * A NetlinkMessage subclass for netlink conntrack messages. - * - * see also: <linux_src>/include/uapi/linux/netfilter/nfnetlink_conntrack.h - * - * @hide - */ -public class ConntrackMessage extends NetlinkMessage { - public static final int STRUCT_SIZE = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE; - - public static final short NFNL_SUBSYS_CTNETLINK = 1; - public static final short IPCTNL_MSG_CT_NEW = 0; - - // enum ctattr_type - public static final short CTA_TUPLE_ORIG = 1; - public static final short CTA_TUPLE_REPLY = 2; - public static final short CTA_TIMEOUT = 7; - - // enum ctattr_tuple - public static final short CTA_TUPLE_IP = 1; - public static final short CTA_TUPLE_PROTO = 2; - - // enum ctattr_ip - public static final short CTA_IP_V4_SRC = 1; - public static final short CTA_IP_V4_DST = 2; - - // enum ctattr_l4proto - public static final short CTA_PROTO_NUM = 1; - public static final short CTA_PROTO_SRC_PORT = 2; - public static final short CTA_PROTO_DST_PORT = 3; - - public static byte[] newIPv4TimeoutUpdateRequest( - int proto, Inet4Address src, int sport, Inet4Address dst, int dport, int timeoutSec) { - // *** STYLE WARNING *** - // - // Code below this point uses extra block indentation to highlight the - // packing of nested tuple netlink attribute types. - final StructNlAttr ctaTupleOrig = new StructNlAttr(CTA_TUPLE_ORIG, - new StructNlAttr(CTA_TUPLE_IP, - new StructNlAttr(CTA_IP_V4_SRC, src), - new StructNlAttr(CTA_IP_V4_DST, dst)), - new StructNlAttr(CTA_TUPLE_PROTO, - new StructNlAttr(CTA_PROTO_NUM, (byte) proto), - new StructNlAttr(CTA_PROTO_SRC_PORT, (short) sport, BIG_ENDIAN), - new StructNlAttr(CTA_PROTO_DST_PORT, (short) dport, BIG_ENDIAN))); - - final StructNlAttr ctaTimeout = new StructNlAttr(CTA_TIMEOUT, timeoutSec, BIG_ENDIAN); - - final int payloadLength = ctaTupleOrig.getAlignedLength() + ctaTimeout.getAlignedLength(); - final byte[] bytes = new byte[STRUCT_SIZE + payloadLength]; - final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); - byteBuffer.order(ByteOrder.nativeOrder()); - - final ConntrackMessage ctmsg = new ConntrackMessage(); - ctmsg.mHeader.nlmsg_len = bytes.length; - ctmsg.mHeader.nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_NEW; - ctmsg.mHeader.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE; - ctmsg.mHeader.nlmsg_seq = 1; - ctmsg.pack(byteBuffer); - - ctaTupleOrig.pack(byteBuffer); - ctaTimeout.pack(byteBuffer); - - return bytes; - } - - protected StructNfGenMsg mNfGenMsg; - - private ConntrackMessage() { - super(new StructNlMsgHdr()); - mNfGenMsg = new StructNfGenMsg((byte) OsConstants.AF_INET); - } - - public void pack(ByteBuffer byteBuffer) { - mHeader.pack(byteBuffer); - mNfGenMsg.pack(byteBuffer); - } -} diff --git a/services/net/java/android/net/netlink/InetDiagMessage.java b/services/net/java/android/net/netlink/InetDiagMessage.java deleted file mode 100644 index ca07630d3e63..000000000000 --- a/services/net/java/android/net/netlink/InetDiagMessage.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (C) 2018 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.netlink; - -import static android.net.netlink.NetlinkConstants.SOCK_DIAG_BY_FAMILY; -import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE; -import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP; -import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST; -import static android.os.Process.INVALID_UID; -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; -import static android.system.OsConstants.IPPROTO_UDP; -import static android.system.OsConstants.NETLINK_INET_DIAG; - -import android.annotation.Nullable; -import android.net.util.SocketUtils; -import android.system.ErrnoException; -import android.util.Log; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.InterruptedIOException; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetSocketAddress; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * A NetlinkMessage subclass for netlink inet_diag messages. - * - * see also: <linux_src>/include/uapi/linux/inet_diag.h - * - * @hide - */ -public class InetDiagMessage extends NetlinkMessage { - public static final String TAG = "InetDiagMessage"; - private static final int TIMEOUT_MS = 500; - - public static byte[] InetDiagReqV2(int protocol, InetSocketAddress local, - InetSocketAddress remote, int family, short flags) { - return InetDiagReqV2(protocol, local, remote, family, flags, 0 /* pad */, - 0 /* idiagExt */, StructInetDiagReqV2.INET_DIAG_REQ_V2_ALL_STATES); - } - - /** - * Construct an inet_diag_req_v2 message. This method will throw {@code NullPointerException} - * if local and remote are not both null or both non-null. - * - * @param protocol the request protocol type. This should be set to one of IPPROTO_TCP, - * IPPROTO_UDP, or IPPROTO_UDPLITE. - * @param local local socket address of the target socket. This will be packed into a - * {@Code StructInetDiagSockId}. Request to diagnose for all sockets if both of - * local or remote address is null. - * @param remote remote socket address of the target socket. This will be packed into a - * {@Code StructInetDiagSockId}. Request to diagnose for all sockets if both of - * local or remote address is null. - * @param family the ip family of the request message. This should be set to either AF_INET or - * AF_INET6 for IPv4 or IPv6 sockets respectively. - * @param flags message flags. See <linux_src>/include/uapi/linux/netlink.h. - * @param pad for raw socket protocol specification. - * @param idiagExt a set of flags defining what kind of extended information to report. - * @param state a bit mask that defines a filter of socket states. - * - * @return bytes array representation of the message - **/ - public static byte[] InetDiagReqV2(int protocol, @Nullable InetSocketAddress local, - @Nullable InetSocketAddress remote, int family, short flags, int pad, int idiagExt, - int state) throws NullPointerException { - final byte[] bytes = new byte[StructNlMsgHdr.STRUCT_SIZE + StructInetDiagReqV2.STRUCT_SIZE]; - final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); - byteBuffer.order(ByteOrder.nativeOrder()); - - final StructNlMsgHdr nlMsgHdr = new StructNlMsgHdr(); - nlMsgHdr.nlmsg_len = bytes.length; - nlMsgHdr.nlmsg_type = SOCK_DIAG_BY_FAMILY; - nlMsgHdr.nlmsg_flags = flags; - nlMsgHdr.pack(byteBuffer); - final StructInetDiagReqV2 inetDiagReqV2 = - new StructInetDiagReqV2(protocol, local, remote, family, pad, idiagExt, state); - - inetDiagReqV2.pack(byteBuffer); - return bytes; - } - - public StructInetDiagMsg mStructInetDiagMsg; - - private InetDiagMessage(StructNlMsgHdr header) { - super(header); - mStructInetDiagMsg = new StructInetDiagMsg(); - } - - public static InetDiagMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) { - final InetDiagMessage msg = new InetDiagMessage(header); - msg.mStructInetDiagMsg = StructInetDiagMsg.parse(byteBuffer); - return msg; - } - - private static int lookupUidByFamily(int protocol, InetSocketAddress local, - InetSocketAddress remote, int family, short flags, - FileDescriptor fd) - throws ErrnoException, InterruptedIOException { - byte[] msg = InetDiagReqV2(protocol, local, remote, family, flags); - NetlinkSocket.sendMessage(fd, msg, 0, msg.length, TIMEOUT_MS); - ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT_MS); - - final NetlinkMessage nlMsg = NetlinkMessage.parse(response); - final StructNlMsgHdr hdr = nlMsg.getHeader(); - if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) { - return INVALID_UID; - } - if (nlMsg instanceof InetDiagMessage) { - return ((InetDiagMessage) nlMsg).mStructInetDiagMsg.idiag_uid; - } - return INVALID_UID; - } - - private static final int FAMILY[] = {AF_INET6, AF_INET}; - - private static int lookupUid(int protocol, InetSocketAddress local, - InetSocketAddress remote, FileDescriptor fd) - throws ErrnoException, InterruptedIOException { - int uid; - - for (int family : FAMILY) { - /** - * For exact match lookup, swap local and remote for UDP lookups due to kernel - * bug which will not be fixed. See aosp/755889 and - * https://www.mail-archive.com/netdev@vger.kernel.org/msg248638.html - */ - if (protocol == IPPROTO_UDP) { - uid = lookupUidByFamily(protocol, remote, local, family, NLM_F_REQUEST, fd); - } else { - uid = lookupUidByFamily(protocol, local, remote, family, NLM_F_REQUEST, fd); - } - if (uid != INVALID_UID) { - return uid; - } - } - - /** - * For UDP it's possible for a socket to send packets to arbitrary destinations, even if the - * socket is not connected (and even if the socket is connected to a different destination). - * If we want this API to work for such packets, then on miss we need to do a second lookup - * with only the local address and port filled in. - * Always use flags == NLM_F_REQUEST | NLM_F_DUMP for wildcard. - */ - if (protocol == IPPROTO_UDP) { - try { - InetSocketAddress wildcard = new InetSocketAddress( - Inet6Address.getByName("::"), 0); - uid = lookupUidByFamily(protocol, local, wildcard, AF_INET6, - (short) (NLM_F_REQUEST | NLM_F_DUMP), fd); - if (uid != INVALID_UID) { - return uid; - } - wildcard = new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), 0); - uid = lookupUidByFamily(protocol, local, wildcard, AF_INET, - (short) (NLM_F_REQUEST | NLM_F_DUMP), fd); - if (uid != INVALID_UID) { - return uid; - } - } catch (UnknownHostException e) { - Log.e(TAG, e.toString()); - } - } - return INVALID_UID; - } - - /** - * Use an inet_diag socket to look up the UID associated with the input local and remote - * address/port and protocol of a connection. - */ - public static int getConnectionOwnerUid(int protocol, InetSocketAddress local, - InetSocketAddress remote) { - int uid = INVALID_UID; - FileDescriptor fd = null; - try { - fd = NetlinkSocket.forProto(NETLINK_INET_DIAG); - NetlinkSocket.connectToKernel(fd); - uid = lookupUid(protocol, local, remote, fd); - } catch (ErrnoException | SocketException | IllegalArgumentException - | InterruptedIOException e) { - Log.e(TAG, e.toString()); - } finally { - if (fd != null) { - try { - SocketUtils.closeSocket(fd); - } catch (IOException e) { - Log.e(TAG, e.toString()); - } - } - } - return uid; - } - - @Override - public String toString() { - return "InetDiagMessage{ " - + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, " - + "inet_diag_msg{" - + (mStructInetDiagMsg == null ? "" : mStructInetDiagMsg.toString()) + "} " - + "}"; - } -} diff --git a/services/net/java/android/net/netlink/NetlinkConstants.java b/services/net/java/android/net/netlink/NetlinkConstants.java deleted file mode 100644 index fc1551c87b6b..000000000000 --- a/services/net/java/android/net/netlink/NetlinkConstants.java +++ /dev/null @@ -1,129 +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.net.netlink; - -import android.system.OsConstants; -import com.android.internal.util.HexDump; - -import java.nio.ByteBuffer; - - -/** - * Various constants and static helper methods for netlink communications. - * - * Values taken from: - * - * <linux_src>/include/uapi/linux/netlink.h - * <linux_src>/include/uapi/linux/rtnetlink.h - * - * @hide - */ -public class NetlinkConstants { - private NetlinkConstants() {} - - public static final int NLA_ALIGNTO = 4; - - public static final int alignedLengthOf(short length) { - final int intLength = (int) length & 0xffff; - return alignedLengthOf(intLength); - } - - public static final int alignedLengthOf(int length) { - if (length <= 0) { return 0; } - return (((length + NLA_ALIGNTO - 1) / NLA_ALIGNTO) * NLA_ALIGNTO); - } - - public static String stringForAddressFamily(int family) { - if (family == OsConstants.AF_INET) { return "AF_INET"; } - if (family == OsConstants.AF_INET6) { return "AF_INET6"; } - if (family == OsConstants.AF_NETLINK) { return "AF_NETLINK"; } - return String.valueOf(family); - } - - public static String stringForProtocol(int protocol) { - if (protocol == OsConstants.IPPROTO_TCP) { return "IPPROTO_TCP"; } - if (protocol == OsConstants.IPPROTO_UDP) { return "IPPROTO_UDP"; } - return String.valueOf(protocol); - } - - public static String hexify(byte[] bytes) { - if (bytes == null) { return "(null)"; } - return HexDump.toHexString(bytes); - } - - public static String hexify(ByteBuffer buffer) { - if (buffer == null) { return "(null)"; } - return HexDump.toHexString( - buffer.array(), buffer.position(), buffer.remaining()); - } - - // Known values for struct nlmsghdr nlm_type. - public static final short NLMSG_NOOP = 1; // Nothing - public static final short NLMSG_ERROR = 2; // Error - public static final short NLMSG_DONE = 3; // End of a dump - public static final short NLMSG_OVERRUN = 4; // Data lost - public static final short NLMSG_MAX_RESERVED = 15; // Max reserved value - - public static final short RTM_NEWLINK = 16; - public static final short RTM_DELLINK = 17; - public static final short RTM_GETLINK = 18; - public static final short RTM_SETLINK = 19; - public static final short RTM_NEWADDR = 20; - public static final short RTM_DELADDR = 21; - public static final short RTM_GETADDR = 22; - public static final short RTM_NEWROUTE = 24; - public static final short RTM_DELROUTE = 25; - public static final short RTM_GETROUTE = 26; - public static final short RTM_NEWNEIGH = 28; - public static final short RTM_DELNEIGH = 29; - public static final short RTM_GETNEIGH = 30; - public static final short RTM_NEWRULE = 32; - public static final short RTM_DELRULE = 33; - public static final short RTM_GETRULE = 34; - public static final short RTM_NEWNDUSEROPT = 68; - - /* see <linux_src>/include/uapi/linux/sock_diag.h */ - public static final short SOCK_DIAG_BY_FAMILY = 20; - - public static String stringForNlMsgType(short nlm_type) { - switch (nlm_type) { - case NLMSG_NOOP: return "NLMSG_NOOP"; - case NLMSG_ERROR: return "NLMSG_ERROR"; - case NLMSG_DONE: return "NLMSG_DONE"; - case NLMSG_OVERRUN: return "NLMSG_OVERRUN"; - case RTM_NEWLINK: return "RTM_NEWLINK"; - case RTM_DELLINK: return "RTM_DELLINK"; - case RTM_GETLINK: return "RTM_GETLINK"; - case RTM_SETLINK: return "RTM_SETLINK"; - case RTM_NEWADDR: return "RTM_NEWADDR"; - case RTM_DELADDR: return "RTM_DELADDR"; - case RTM_GETADDR: return "RTM_GETADDR"; - case RTM_NEWROUTE: return "RTM_NEWROUTE"; - case RTM_DELROUTE: return "RTM_DELROUTE"; - case RTM_GETROUTE: return "RTM_GETROUTE"; - case RTM_NEWNEIGH: return "RTM_NEWNEIGH"; - case RTM_DELNEIGH: return "RTM_DELNEIGH"; - case RTM_GETNEIGH: return "RTM_GETNEIGH"; - case RTM_NEWRULE: return "RTM_NEWRULE"; - case RTM_DELRULE: return "RTM_DELRULE"; - case RTM_GETRULE: return "RTM_GETRULE"; - case RTM_NEWNDUSEROPT: return "RTM_NEWNDUSEROPT"; - default: - return "unknown RTM type: " + String.valueOf(nlm_type); - } - } -} diff --git a/services/net/java/android/net/netlink/NetlinkErrorMessage.java b/services/net/java/android/net/netlink/NetlinkErrorMessage.java deleted file mode 100644 index e2755740453a..000000000000 --- a/services/net/java/android/net/netlink/NetlinkErrorMessage.java +++ /dev/null @@ -1,61 +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.net.netlink; - -import android.net.netlink.StructNlMsgHdr; -import android.net.netlink.NetlinkMessage; - -import java.nio.ByteBuffer; - - -/** - * A NetlinkMessage subclass for netlink error messages. - * - * @hide - */ -public class NetlinkErrorMessage extends NetlinkMessage { - - public static NetlinkErrorMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) { - final NetlinkErrorMessage errorMsg = new NetlinkErrorMessage(header); - - errorMsg.mNlMsgErr = StructNlMsgErr.parse(byteBuffer); - if (errorMsg.mNlMsgErr == null) { - return null; - } - - return errorMsg; - } - - private StructNlMsgErr mNlMsgErr; - - NetlinkErrorMessage(StructNlMsgHdr header) { - super(header); - mNlMsgErr = null; - } - - public StructNlMsgErr getNlMsgError() { - return mNlMsgErr; - } - - @Override - public String toString() { - return "NetlinkErrorMessage{ " - + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, " - + "nlmsgerr{" + (mNlMsgErr == null ? "" : mNlMsgErr.toString()) + "} " - + "}"; - } -} diff --git a/services/net/java/android/net/netlink/NetlinkMessage.java b/services/net/java/android/net/netlink/NetlinkMessage.java deleted file mode 100644 index a325db800813..000000000000 --- a/services/net/java/android/net/netlink/NetlinkMessage.java +++ /dev/null @@ -1,99 +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.net.netlink; - -import android.net.netlink.NetlinkConstants; -import android.net.netlink.NetlinkErrorMessage; -import android.net.netlink.RtNetlinkNeighborMessage; -import android.net.netlink.StructNlAttr; -import android.net.netlink.StructNlMsgHdr; -import android.util.Log; - -import java.nio.ByteBuffer; - - -/** - * NetlinkMessage base class for other, more specific netlink message types. - * - * Classes that extend NetlinkMessage should: - * - implement a public static parse(StructNlMsgHdr, ByteBuffer) method - * - returning either null (parse errors) or a new object of the subclass - * type (cast-able to NetlinkMessage) - * - * NetlinkMessage.parse() should be updated to know which nlmsg_type values - * correspond with which message subclasses. - * - * @hide - */ -public class NetlinkMessage { - private final static String TAG = "NetlinkMessage"; - - public static NetlinkMessage parse(ByteBuffer byteBuffer) { - final int startPosition = (byteBuffer != null) ? byteBuffer.position() : -1; - final StructNlMsgHdr nlmsghdr = StructNlMsgHdr.parse(byteBuffer); - if (nlmsghdr == null) { - return null; - } - - int payloadLength = NetlinkConstants.alignedLengthOf(nlmsghdr.nlmsg_len); - payloadLength -= StructNlMsgHdr.STRUCT_SIZE; - if (payloadLength < 0 || payloadLength > byteBuffer.remaining()) { - // Malformed message or runt buffer. Pretend the buffer was consumed. - byteBuffer.position(byteBuffer.limit()); - return null; - } - - switch (nlmsghdr.nlmsg_type) { - //case NetlinkConstants.NLMSG_NOOP: - case NetlinkConstants.NLMSG_ERROR: - return (NetlinkMessage) NetlinkErrorMessage.parse(nlmsghdr, byteBuffer); - case NetlinkConstants.NLMSG_DONE: - byteBuffer.position(byteBuffer.position() + payloadLength); - return new NetlinkMessage(nlmsghdr); - //case NetlinkConstants.NLMSG_OVERRUN: - case NetlinkConstants.RTM_NEWNEIGH: - case NetlinkConstants.RTM_DELNEIGH: - case NetlinkConstants.RTM_GETNEIGH: - return (NetlinkMessage) RtNetlinkNeighborMessage.parse(nlmsghdr, byteBuffer); - case NetlinkConstants.SOCK_DIAG_BY_FAMILY: - return (NetlinkMessage) InetDiagMessage.parse(nlmsghdr, byteBuffer); - default: - if (nlmsghdr.nlmsg_type <= NetlinkConstants.NLMSG_MAX_RESERVED) { - // Netlink control message. Just parse the header for now, - // pretending the whole message was consumed. - byteBuffer.position(byteBuffer.position() + payloadLength); - return new NetlinkMessage(nlmsghdr); - } - return null; - } - } - - protected StructNlMsgHdr mHeader; - - public NetlinkMessage(StructNlMsgHdr nlmsghdr) { - mHeader = nlmsghdr; - } - - public StructNlMsgHdr getHeader() { - return mHeader; - } - - @Override - public String toString() { - return "NetlinkMessage{" + (mHeader == null ? "" : mHeader.toString()) + "}"; - } -} diff --git a/services/net/java/android/net/netlink/NetlinkSocket.java b/services/net/java/android/net/netlink/NetlinkSocket.java deleted file mode 100644 index 7311fc537205..000000000000 --- a/services/net/java/android/net/netlink/NetlinkSocket.java +++ /dev/null @@ -1,158 +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.net.netlink; - -import static android.net.util.SocketUtils.makeNetlinkSocketAddress; -import static android.system.OsConstants.AF_NETLINK; -import static android.system.OsConstants.EIO; -import static android.system.OsConstants.EPROTO; -import static android.system.OsConstants.ETIMEDOUT; -import static android.system.OsConstants.SOCK_DGRAM; -import static android.system.OsConstants.SOL_SOCKET; -import static android.system.OsConstants.SO_RCVBUF; -import static android.system.OsConstants.SO_RCVTIMEO; -import static android.system.OsConstants.SO_SNDTIMEO; - -import android.net.util.SocketUtils; -import android.system.ErrnoException; -import android.system.Os; -import android.system.StructTimeval; -import android.util.Log; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.io.InterruptedIOException; -import java.net.SocketException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - - -/** - * NetlinkSocket - * - * A small static class to assist with AF_NETLINK socket operations. - * - * @hide - */ -public class NetlinkSocket { - private static final String TAG = "NetlinkSocket"; - - public static final int DEFAULT_RECV_BUFSIZE = 8 * 1024; - public static final int SOCKET_RECV_BUFSIZE = 64 * 1024; - - public static void sendOneShotKernelMessage(int nlProto, byte[] msg) throws ErrnoException { - final String errPrefix = "Error in NetlinkSocket.sendOneShotKernelMessage"; - final long IO_TIMEOUT = 300L; - - final FileDescriptor fd = forProto(nlProto); - - try { - connectToKernel(fd); - sendMessage(fd, msg, 0, msg.length, IO_TIMEOUT); - final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT); - // recvMessage() guaranteed to not return null if it did not throw. - final NetlinkMessage response = NetlinkMessage.parse(bytes); - if (response != null && response instanceof NetlinkErrorMessage && - (((NetlinkErrorMessage) response).getNlMsgError() != null)) { - final int errno = ((NetlinkErrorMessage) response).getNlMsgError().error; - if (errno != 0) { - // TODO: consider ignoring EINVAL (-22), which appears to be - // normal when probing a neighbor for which the kernel does - // not already have / no longer has a link layer address. - Log.e(TAG, errPrefix + ", errmsg=" + response.toString()); - // Note: convert kernel errnos (negative) into userspace errnos (positive). - throw new ErrnoException(response.toString(), Math.abs(errno)); - } - } else { - final String errmsg; - if (response == null) { - bytes.position(0); - errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes); - } else { - errmsg = response.toString(); - } - Log.e(TAG, errPrefix + ", errmsg=" + errmsg); - throw new ErrnoException(errmsg, EPROTO); - } - } catch (InterruptedIOException e) { - Log.e(TAG, errPrefix, e); - throw new ErrnoException(errPrefix, ETIMEDOUT, e); - } catch (SocketException e) { - Log.e(TAG, errPrefix, e); - throw new ErrnoException(errPrefix, EIO, e); - } finally { - try { - SocketUtils.closeSocket(fd); - } catch (IOException e) { - // Nothing we can do here - } - } - } - - public static FileDescriptor forProto(int nlProto) throws ErrnoException { - final FileDescriptor fd = Os.socket(AF_NETLINK, SOCK_DGRAM, nlProto); - Os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, SOCKET_RECV_BUFSIZE); - return fd; - } - - public static void connectToKernel(FileDescriptor fd) throws ErrnoException, SocketException { - Os.connect(fd, makeNetlinkSocketAddress(0, 0)); - } - - private static void checkTimeout(long timeoutMs) { - if (timeoutMs < 0) { - throw new IllegalArgumentException("Negative timeouts not permitted"); - } - } - - /** - * Wait up to |timeoutMs| (or until underlying socket error) for a - * netlink message of at most |bufsize| size. - * - * Multi-threaded calls with different timeouts will cause unexpected results. - */ - public static ByteBuffer recvMessage(FileDescriptor fd, int bufsize, long timeoutMs) - throws ErrnoException, IllegalArgumentException, InterruptedIOException { - checkTimeout(timeoutMs); - - Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs)); - - ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize); - int length = Os.read(fd, byteBuffer); - if (length == bufsize) { - Log.w(TAG, "maximum read"); - } - byteBuffer.position(0); - byteBuffer.limit(length); - byteBuffer.order(ByteOrder.nativeOrder()); - return byteBuffer; - } - - /** - * Send a message to a peer to which this socket has previously connected, - * waiting at most |timeoutMs| milliseconds for the send to complete. - * - * Multi-threaded calls with different timeouts will cause unexpected results. - */ - public static int sendMessage( - FileDescriptor fd, byte[] bytes, int offset, int count, long timeoutMs) - throws ErrnoException, IllegalArgumentException, InterruptedIOException { - checkTimeout(timeoutMs); - Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs)); - return Os.write(fd, bytes, offset, count); - } -} diff --git a/services/net/java/android/net/netlink/RtNetlinkNeighborMessage.java b/services/net/java/android/net/netlink/RtNetlinkNeighborMessage.java deleted file mode 100644 index e784fbb5e0dc..000000000000 --- a/services/net/java/android/net/netlink/RtNetlinkNeighborMessage.java +++ /dev/null @@ -1,251 +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.net.netlink; - -import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK; -import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP; -import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE; -import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST; - -import android.net.netlink.StructNdaCacheInfo; -import android.net.netlink.StructNdMsg; -import android.net.netlink.StructNlAttr; -import android.net.netlink.StructNlMsgHdr; -import android.net.netlink.NetlinkMessage; -import android.system.OsConstants; -import android.util.Log; - -import java.net.InetAddress; -import java.net.Inet6Address; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - - -/** - * A NetlinkMessage subclass for rtnetlink neighbor messages. - * - * see also: <linux_src>/include/uapi/linux/neighbour.h - * - * @hide - */ -public class RtNetlinkNeighborMessage extends NetlinkMessage { - public static final short NDA_UNSPEC = 0; - public static final short NDA_DST = 1; - public static final short NDA_LLADDR = 2; - public static final short NDA_CACHEINFO = 3; - public static final short NDA_PROBES = 4; - public static final short NDA_VLAN = 5; - public static final short NDA_PORT = 6; - public static final short NDA_VNI = 7; - public static final short NDA_IFINDEX = 8; - public static final short NDA_MASTER = 9; - - private static StructNlAttr findNextAttrOfType(short attrType, ByteBuffer byteBuffer) { - while (byteBuffer != null && byteBuffer.remaining() > 0) { - final StructNlAttr nlAttr = StructNlAttr.peek(byteBuffer); - if (nlAttr == null) { - break; - } - if (nlAttr.nla_type == attrType) { - return StructNlAttr.parse(byteBuffer); - } - if (byteBuffer.remaining() < nlAttr.getAlignedLength()) { - break; - } - byteBuffer.position(byteBuffer.position() + nlAttr.getAlignedLength()); - } - return null; - } - - public static RtNetlinkNeighborMessage parse(StructNlMsgHdr header, ByteBuffer byteBuffer) { - final RtNetlinkNeighborMessage neighMsg = new RtNetlinkNeighborMessage(header); - - neighMsg.mNdmsg = StructNdMsg.parse(byteBuffer); - if (neighMsg.mNdmsg == null) { - return null; - } - - // Some of these are message-type dependent, and not always present. - final int baseOffset = byteBuffer.position(); - StructNlAttr nlAttr = findNextAttrOfType(NDA_DST, byteBuffer); - if (nlAttr != null) { - neighMsg.mDestination = nlAttr.getValueAsInetAddress(); - } - - byteBuffer.position(baseOffset); - nlAttr = findNextAttrOfType(NDA_LLADDR, byteBuffer); - if (nlAttr != null) { - neighMsg.mLinkLayerAddr = nlAttr.nla_value; - } - - byteBuffer.position(baseOffset); - nlAttr = findNextAttrOfType(NDA_PROBES, byteBuffer); - if (nlAttr != null) { - neighMsg.mNumProbes = nlAttr.getValueAsInt(0); - } - - byteBuffer.position(baseOffset); - nlAttr = findNextAttrOfType(NDA_CACHEINFO, byteBuffer); - if (nlAttr != null) { - neighMsg.mCacheInfo = StructNdaCacheInfo.parse(nlAttr.getValueAsByteBuffer()); - } - - final int kMinConsumed = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE; - final int kAdditionalSpace = NetlinkConstants.alignedLengthOf( - neighMsg.mHeader.nlmsg_len - kMinConsumed); - if (byteBuffer.remaining() < kAdditionalSpace) { - byteBuffer.position(byteBuffer.limit()); - } else { - byteBuffer.position(baseOffset + kAdditionalSpace); - } - - return neighMsg; - } - - /** - * A convenience method to create an RTM_GETNEIGH request message. - */ - public static byte[] newGetNeighborsRequest(int seqNo) { - final int length = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE; - final byte[] bytes = new byte[length]; - final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); - byteBuffer.order(ByteOrder.nativeOrder()); - - final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr(); - nlmsghdr.nlmsg_len = length; - nlmsghdr.nlmsg_type = NetlinkConstants.RTM_GETNEIGH; - nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; - nlmsghdr.nlmsg_seq = seqNo; - nlmsghdr.pack(byteBuffer); - - final StructNdMsg ndmsg = new StructNdMsg(); - ndmsg.pack(byteBuffer); - - return bytes; - } - - /** - * A convenience method to create an RTM_NEWNEIGH message, to modify - * the kernel's state information for a specific neighbor. - */ - public static byte[] newNewNeighborMessage( - int seqNo, InetAddress ip, short nudState, int ifIndex, byte[] llAddr) { - final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr(); - nlmsghdr.nlmsg_type = NetlinkConstants.RTM_NEWNEIGH; - nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE; - nlmsghdr.nlmsg_seq = seqNo; - - final RtNetlinkNeighborMessage msg = new RtNetlinkNeighborMessage(nlmsghdr); - msg.mNdmsg = new StructNdMsg(); - msg.mNdmsg.ndm_family = - (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET); - msg.mNdmsg.ndm_ifindex = ifIndex; - msg.mNdmsg.ndm_state = nudState; - msg.mDestination = ip; - msg.mLinkLayerAddr = llAddr; // might be null - - final byte[] bytes = new byte[msg.getRequiredSpace()]; - nlmsghdr.nlmsg_len = bytes.length; - final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); - byteBuffer.order(ByteOrder.nativeOrder()); - msg.pack(byteBuffer); - return bytes; - } - - private StructNdMsg mNdmsg; - private InetAddress mDestination; - private byte[] mLinkLayerAddr; - private int mNumProbes; - private StructNdaCacheInfo mCacheInfo; - - private RtNetlinkNeighborMessage(StructNlMsgHdr header) { - super(header); - mNdmsg = null; - mDestination = null; - mLinkLayerAddr = null; - mNumProbes = 0; - mCacheInfo = null; - } - - public StructNdMsg getNdHeader() { - return mNdmsg; - } - - public InetAddress getDestination() { - return mDestination; - } - - public byte[] getLinkLayerAddress() { - return mLinkLayerAddr; - } - - public int getProbes() { - return mNumProbes; - } - - public StructNdaCacheInfo getCacheInfo() { - return mCacheInfo; - } - - public int getRequiredSpace() { - int spaceRequired = StructNlMsgHdr.STRUCT_SIZE + StructNdMsg.STRUCT_SIZE; - if (mDestination != null) { - spaceRequired += NetlinkConstants.alignedLengthOf( - StructNlAttr.NLA_HEADERLEN + mDestination.getAddress().length); - } - if (mLinkLayerAddr != null) { - spaceRequired += NetlinkConstants.alignedLengthOf( - StructNlAttr.NLA_HEADERLEN + mLinkLayerAddr.length); - } - // Currently we don't write messages with NDA_PROBES nor NDA_CACHEINFO - // attributes appended. Fix later, if necessary. - return spaceRequired; - } - - private static void packNlAttr(short nlType, byte[] nlValue, ByteBuffer byteBuffer) { - final StructNlAttr nlAttr = new StructNlAttr(); - nlAttr.nla_type = nlType; - nlAttr.nla_value = nlValue; - nlAttr.nla_len = (short) (StructNlAttr.NLA_HEADERLEN + nlAttr.nla_value.length); - nlAttr.pack(byteBuffer); - } - - public void pack(ByteBuffer byteBuffer) { - getHeader().pack(byteBuffer) ; - mNdmsg.pack(byteBuffer); - - if (mDestination != null) { - packNlAttr(NDA_DST, mDestination.getAddress(), byteBuffer); - } - if (mLinkLayerAddr != null) { - packNlAttr(NDA_LLADDR, mLinkLayerAddr, byteBuffer); - } - } - - @Override - public String toString() { - final String ipLiteral = (mDestination == null) ? "" : mDestination.getHostAddress(); - return "RtNetlinkNeighborMessage{ " - + "nlmsghdr{" + (mHeader == null ? "" : mHeader.toString()) + "}, " - + "ndmsg{" + (mNdmsg == null ? "" : mNdmsg.toString()) + "}, " - + "destination{" + ipLiteral + "} " - + "linklayeraddr{" + NetlinkConstants.hexify(mLinkLayerAddr) + "} " - + "probes{" + mNumProbes + "} " - + "cacheinfo{" + (mCacheInfo == null ? "" : mCacheInfo.toString()) + "} " - + "}"; - } -} diff --git a/services/net/java/android/net/netlink/StructInetDiagMsg.java b/services/net/java/android/net/netlink/StructInetDiagMsg.java deleted file mode 100644 index da824ad01efa..000000000000 --- a/services/net/java/android/net/netlink/StructInetDiagMsg.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2018 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.netlink; - -import static java.nio.ByteOrder.BIG_ENDIAN; -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; - -import java.net.Inet4Address; -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import android.util.Log; - -/** - * struct inet_diag_msg - * - * see <linux_src>/include/uapi/linux/inet_diag.h - * - * struct inet_diag_msg { - * __u8 idiag_family; - * __u8 idiag_state; - * __u8 idiag_timer; - * __u8 idiag_retrans; - * struct inet_diag_sockid id; - * __u32 idiag_expires; - * __u32 idiag_rqueue; - * __u32 idiag_wqueue; - * __u32 idiag_uid; - * __u32 idiag_inode; - * }; - * - * @hide - */ -public class StructInetDiagMsg { - public static final int STRUCT_SIZE = 4 + StructInetDiagSockId.STRUCT_SIZE + 20; - private static final int IDIAG_UID_OFFSET = StructNlMsgHdr.STRUCT_SIZE + 4 + - StructInetDiagSockId.STRUCT_SIZE + 12; - public int idiag_uid; - - public static StructInetDiagMsg parse(ByteBuffer byteBuffer) { - StructInetDiagMsg struct = new StructInetDiagMsg(); - struct.idiag_uid = byteBuffer.getInt(IDIAG_UID_OFFSET); - return struct; - } - - @Override - public String toString() { - return "StructInetDiagMsg{ " - + "idiag_uid{" + idiag_uid + "}, " - + "}"; - } -} diff --git a/services/net/java/android/net/netlink/StructInetDiagReqV2.java b/services/net/java/android/net/netlink/StructInetDiagReqV2.java deleted file mode 100644 index 2268113044d5..000000000000 --- a/services/net/java/android/net/netlink/StructInetDiagReqV2.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2018 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.netlink; - -import android.annotation.Nullable; - -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; - -/** - * struct inet_diag_req_v2 - * - * see <linux_src>/include/uapi/linux/inet_diag.h - * - * struct inet_diag_req_v2 { - * __u8 sdiag_family; - * __u8 sdiag_protocol; - * __u8 idiag_ext; - * __u8 pad; - * __u32 idiag_states; - * struct inet_diag_sockid id; - * }; - * - * @hide - */ -public class StructInetDiagReqV2 { - public static final int STRUCT_SIZE = 8 + StructInetDiagSockId.STRUCT_SIZE; - - private final byte mSdiagFamily; - private final byte mSdiagProtocol; - private final byte mIdiagExt; - private final byte mPad; - private final StructInetDiagSockId mId; - private final int mState; - public static final int INET_DIAG_REQ_V2_ALL_STATES = (int) 0xffffffff; - - public StructInetDiagReqV2(int protocol, InetSocketAddress local, InetSocketAddress remote, - int family) { - this(protocol, local, remote, family, 0 /* pad */, 0 /* extension */, - INET_DIAG_REQ_V2_ALL_STATES); - } - - public StructInetDiagReqV2(int protocol, @Nullable InetSocketAddress local, - @Nullable InetSocketAddress remote, int family, int pad, int extension, int state) - throws NullPointerException { - mSdiagFamily = (byte) family; - mSdiagProtocol = (byte) protocol; - // Request for all sockets if no specific socket is requested. Specify the local and remote - // socket address information for target request socket. - if ((local == null) != (remote == null)) { - throw new NullPointerException("Local and remote must be both null or both non-null"); - } - mId = ((local != null && remote != null) ? new StructInetDiagSockId(local, remote) : null); - mPad = (byte) pad; - mIdiagExt = (byte) extension; - mState = state; - } - - public void pack(ByteBuffer byteBuffer) { - // The ByteOrder must have already been set by the caller. - byteBuffer.put((byte) mSdiagFamily); - byteBuffer.put((byte) mSdiagProtocol); - byteBuffer.put((byte) mIdiagExt); - byteBuffer.put((byte) mPad); - byteBuffer.putInt(mState); - if (mId != null) mId.pack(byteBuffer); - } - - @Override - public String toString() { - final String familyStr = NetlinkConstants.stringForAddressFamily(mSdiagFamily); - final String protocolStr = NetlinkConstants.stringForAddressFamily(mSdiagProtocol); - - return "StructInetDiagReqV2{ " - + "sdiag_family{" + familyStr + "}, " - + "sdiag_protocol{" + protocolStr + "}, " - + "idiag_ext{" + mIdiagExt + ")}, " - + "pad{" + mPad + "}, " - + "idiag_states{" + Integer.toHexString(mState) + "}, " - + ((mId != null) ? mId.toString() : "inet_diag_sockid=null") - + "}"; - } -} diff --git a/services/net/java/android/net/netlink/StructInetDiagSockId.java b/services/net/java/android/net/netlink/StructInetDiagSockId.java deleted file mode 100644 index 2e9fa253463d..000000000000 --- a/services/net/java/android/net/netlink/StructInetDiagSockId.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2018 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.netlink; - -import static java.nio.ByteOrder.BIG_ENDIAN; - -import java.net.Inet4Address; -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -/** - * struct inet_diag_req_v2 - * - * see <linux_src>/include/uapi/linux/inet_diag.h - * - * struct inet_diag_sockid { - * __be16 idiag_sport; - * __be16 idiag_dport; - * __be32 idiag_src[4]; - * __be32 idiag_dst[4]; - * __u32 idiag_if; - * __u32 idiag_cookie[2]; - * #define INET_DIAG_NOCOOKIE (~0U) - * }; - * - * @hide - */ -public class StructInetDiagSockId { - public static final int STRUCT_SIZE = 48; - - private final InetSocketAddress mLocSocketAddress; - private final InetSocketAddress mRemSocketAddress; - private final byte[] INET_DIAG_NOCOOKIE = new byte[]{ - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}; - private final byte[] IPV4_PADDING = new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - - public StructInetDiagSockId(InetSocketAddress loc, InetSocketAddress rem) { - mLocSocketAddress = loc; - mRemSocketAddress = rem; - } - - public void pack(ByteBuffer byteBuffer) { - byteBuffer.order(BIG_ENDIAN); - byteBuffer.putShort((short) mLocSocketAddress.getPort()); - byteBuffer.putShort((short) mRemSocketAddress.getPort()); - byteBuffer.put(mLocSocketAddress.getAddress().getAddress()); - if (mLocSocketAddress.getAddress() instanceof Inet4Address) { - byteBuffer.put(IPV4_PADDING); - } - byteBuffer.put(mRemSocketAddress.getAddress().getAddress()); - if (mRemSocketAddress.getAddress() instanceof Inet4Address) { - byteBuffer.put(IPV4_PADDING); - } - byteBuffer.order(ByteOrder.nativeOrder()); - byteBuffer.putInt(0); - byteBuffer.put(INET_DIAG_NOCOOKIE); - } - - @Override - public String toString() { - return "StructInetDiagSockId{ " - + "idiag_sport{" + mLocSocketAddress.getPort() + "}, " - + "idiag_dport{" + mRemSocketAddress.getPort() + "}, " - + "idiag_src{" + mLocSocketAddress.getAddress().getHostAddress() + "}, " - + "idiag_dst{" + mRemSocketAddress.getAddress().getHostAddress() + "}, " - + "idiag_if{" + 0 + "} " - + "idiag_cookie{INET_DIAG_NOCOOKIE}" - + "}"; - } -} diff --git a/services/net/java/android/net/netlink/StructNdMsg.java b/services/net/java/android/net/netlink/StructNdMsg.java deleted file mode 100644 index e34ec39ab99b..000000000000 --- a/services/net/java/android/net/netlink/StructNdMsg.java +++ /dev/null @@ -1,166 +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.net.netlink; - -import android.net.netlink.NetlinkConstants; -import android.system.OsConstants; -import java.nio.ByteBuffer; - - -/** - * struct ndmsg - * - * see: <linux_src>/include/uapi/linux/neighbour.h - * - * @hide - */ -public class StructNdMsg { - // Already aligned. - public static final int STRUCT_SIZE = 12; - - // Neighbor Cache Entry States - public static final short NUD_NONE = 0x00; - public static final short NUD_INCOMPLETE = 0x01; - public static final short NUD_REACHABLE = 0x02; - public static final short NUD_STALE = 0x04; - public static final short NUD_DELAY = 0x08; - public static final short NUD_PROBE = 0x10; - public static final short NUD_FAILED = 0x20; - public static final short NUD_NOARP = 0x40; - public static final short NUD_PERMANENT = 0x80; - - public static String stringForNudState(short nudState) { - switch (nudState) { - case NUD_NONE: return "NUD_NONE"; - case NUD_INCOMPLETE: return "NUD_INCOMPLETE"; - case NUD_REACHABLE: return "NUD_REACHABLE"; - case NUD_STALE: return "NUD_STALE"; - case NUD_DELAY: return "NUD_DELAY"; - case NUD_PROBE: return "NUD_PROBE"; - case NUD_FAILED: return "NUD_FAILED"; - case NUD_NOARP: return "NUD_NOARP"; - case NUD_PERMANENT: return "NUD_PERMANENT"; - default: - return "unknown NUD state: " + String.valueOf(nudState); - } - } - - public static boolean isNudStateConnected(short nudState) { - return ((nudState & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE)) != 0); - } - - public static boolean isNudStateValid(short nudState) { - return (isNudStateConnected(nudState) || - ((nudState & (NUD_PROBE|NUD_STALE|NUD_DELAY)) != 0)); - } - - // Neighbor Cache Entry Flags - public static byte NTF_USE = (byte) 0x01; - public static byte NTF_SELF = (byte) 0x02; - public static byte NTF_MASTER = (byte) 0x04; - public static byte NTF_PROXY = (byte) 0x08; - public static byte NTF_ROUTER = (byte) 0x80; - - public static String stringForNudFlags(byte flags) { - final StringBuilder sb = new StringBuilder(); - if ((flags & NTF_USE) != 0) { - sb.append("NTF_USE"); - } - if ((flags & NTF_SELF) != 0) { - if (sb.length() > 0) { sb.append("|"); } - sb.append("NTF_SELF"); - } - if ((flags & NTF_MASTER) != 0) { - if (sb.length() > 0) { sb.append("|"); } - sb.append("NTF_MASTER"); - } - if ((flags & NTF_PROXY) != 0) { - if (sb.length() > 0) { sb.append("|"); - } - sb.append("NTF_PROXY"); } - if ((flags & NTF_ROUTER) != 0) { - if (sb.length() > 0) { sb.append("|"); } - sb.append("NTF_ROUTER"); - } - return sb.toString(); - } - - private static boolean hasAvailableSpace(ByteBuffer byteBuffer) { - return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE; - } - - public static StructNdMsg parse(ByteBuffer byteBuffer) { - if (!hasAvailableSpace(byteBuffer)) { return null; } - - // The ByteOrder must have already been set by the caller. In most - // cases ByteOrder.nativeOrder() is correct, with the possible - // exception of usage within unittests. - final StructNdMsg struct = new StructNdMsg(); - struct.ndm_family = byteBuffer.get(); - final byte pad1 = byteBuffer.get(); - final short pad2 = byteBuffer.getShort(); - struct.ndm_ifindex = byteBuffer.getInt(); - struct.ndm_state = byteBuffer.getShort(); - struct.ndm_flags = byteBuffer.get(); - struct.ndm_type = byteBuffer.get(); - return struct; - } - - public byte ndm_family; - public int ndm_ifindex; - public short ndm_state; - public byte ndm_flags; - public byte ndm_type; - - public StructNdMsg() { - ndm_family = (byte) OsConstants.AF_UNSPEC; - } - - public void pack(ByteBuffer byteBuffer) { - // The ByteOrder must have already been set by the caller. In most - // cases ByteOrder.nativeOrder() is correct, with the exception - // of usage within unittests. - byteBuffer.put(ndm_family); - byteBuffer.put((byte) 0); // pad1 - byteBuffer.putShort((short) 0); // pad2 - byteBuffer.putInt(ndm_ifindex); - byteBuffer.putShort(ndm_state); - byteBuffer.put(ndm_flags); - byteBuffer.put(ndm_type); - } - - public boolean nudConnected() { - return isNudStateConnected(ndm_state); - } - - public boolean nudValid() { - return isNudStateValid(ndm_state); - } - - @Override - public String toString() { - final String stateStr = "" + ndm_state + " (" + stringForNudState(ndm_state) + ")"; - final String flagsStr = "" + ndm_flags + " (" + stringForNudFlags(ndm_flags) + ")"; - return "StructNdMsg{ " - + "family{" + NetlinkConstants.stringForAddressFamily((int) ndm_family) + "}, " - + "ifindex{" + ndm_ifindex + "}, " - + "state{" + stateStr + "}, " - + "flags{" + flagsStr + "}, " - + "type{" + ndm_type + "} " - + "}"; - } -} diff --git a/services/net/java/android/net/netlink/StructNdaCacheInfo.java b/services/net/java/android/net/netlink/StructNdaCacheInfo.java deleted file mode 100644 index 16cf56385eb8..000000000000 --- a/services/net/java/android/net/netlink/StructNdaCacheInfo.java +++ /dev/null @@ -1,117 +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.net.netlink; - -import android.system.Os; -import android.system.OsConstants; - -import java.nio.ByteBuffer; - - -/** - * struct nda_cacheinfo - * - * see: <linux_src>/include/uapi/linux/neighbour.h - * - * @hide - */ -public class StructNdaCacheInfo { - // Already aligned. - public static final int STRUCT_SIZE = 16; - - private static boolean hasAvailableSpace(ByteBuffer byteBuffer) { - return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE; - } - - public static StructNdaCacheInfo parse(ByteBuffer byteBuffer) { - if (!hasAvailableSpace(byteBuffer)) { return null; } - - // The ByteOrder must have already been set by the caller. In most - // cases ByteOrder.nativeOrder() is correct, with the possible - // exception of usage within unittests. - final StructNdaCacheInfo struct = new StructNdaCacheInfo(); - struct.ndm_used = byteBuffer.getInt(); - struct.ndm_confirmed = byteBuffer.getInt(); - struct.ndm_updated = byteBuffer.getInt(); - struct.ndm_refcnt = byteBuffer.getInt(); - return struct; - } - - // TODO: investigate whether this can change during device runtime and - // decide what (if anything) should be done about that. - private static final long CLOCK_TICKS_PER_SECOND = Os.sysconf(OsConstants._SC_CLK_TCK); - - private static long ticksToMilliSeconds(int intClockTicks) { - final long longClockTicks = (long) intClockTicks & 0xffffffff; - return (longClockTicks * 1000) / CLOCK_TICKS_PER_SECOND; - } - - /** - * Explanatory notes, for reference. - * - * Before being returned to user space, the neighbor entry times are - * converted to clock_t's like so: - * - * ndm_used = jiffies_to_clock_t(now - neigh->used); - * ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed); - * ndm_updated = jiffies_to_clock_t(now - neigh->updated); - * - * meaning that these values are expressed as "clock ticks ago". To - * convert these clock ticks to seconds divide by sysconf(_SC_CLK_TCK). - * When _SC_CLK_TCK is 100, for example, the ndm_* times are expressed - * in centiseconds. - * - * These values are unsigned, but fortunately being expressed as "some - * clock ticks ago", these values are typically very small (and - * 2^31 centiseconds = 248 days). - * - * By observation, it appears that: - * ndm_used: the last time ARP/ND took place for this neighbor - * ndm_confirmed: the last time ARP/ND succeeded for this neighbor OR - * higher layer confirmation (TCP or MSG_CONFIRM) - * was received - * ndm_updated: the time when the current NUD state was entered - */ - public int ndm_used; - public int ndm_confirmed; - public int ndm_updated; - public int ndm_refcnt; - - public StructNdaCacheInfo() {} - - public long lastUsed() { - return ticksToMilliSeconds(ndm_used); - } - - public long lastConfirmed() { - return ticksToMilliSeconds(ndm_confirmed); - } - - public long lastUpdated() { - return ticksToMilliSeconds(ndm_updated); - } - - @Override - public String toString() { - return "NdaCacheInfo{ " - + "ndm_used{" + lastUsed() + "}, " - + "ndm_confirmed{" + lastConfirmed() + "}, " - + "ndm_updated{" + lastUpdated() + "}, " - + "ndm_refcnt{" + ndm_refcnt + "} " - + "}"; - } -} diff --git a/services/net/java/android/net/netlink/StructNfGenMsg.java b/services/net/java/android/net/netlink/StructNfGenMsg.java deleted file mode 100644 index 8155977b6e6a..000000000000 --- a/services/net/java/android/net/netlink/StructNfGenMsg.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2017 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.netlink; - -import java.nio.ByteBuffer; - - -/** - * struct nfgenmsg - * - * see <linux_src>/include/uapi/linux/netfilter/nfnetlink.h - * - * @hide - */ -public class StructNfGenMsg { - public static final int STRUCT_SIZE = 2 + Short.BYTES; - - public static final int NFNETLINK_V0 = 0; - - final public byte nfgen_family; - final public byte version; - final public short res_id; // N.B.: this is big endian in the kernel - - public StructNfGenMsg(byte family) { - nfgen_family = family; - version = (byte) NFNETLINK_V0; - res_id = (short) 0; - } - - public void pack(ByteBuffer byteBuffer) { - byteBuffer.put(nfgen_family); - byteBuffer.put(version); - byteBuffer.putShort(res_id); - } -} diff --git a/services/net/java/android/net/netlink/StructNlAttr.java b/services/net/java/android/net/netlink/StructNlAttr.java deleted file mode 100644 index 28a4e883a316..000000000000 --- a/services/net/java/android/net/netlink/StructNlAttr.java +++ /dev/null @@ -1,210 +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.net.netlink; - -import android.net.netlink.NetlinkConstants; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.nio.ByteOrder; -import java.nio.ByteBuffer; - - -/** - * struct nlattr - * - * see: <linux_src>/include/uapi/linux/netlink.h - * - * @hide - */ -public class StructNlAttr { - // Already aligned. - public static final int NLA_HEADERLEN = 4; - public static final int NLA_F_NESTED = (1 << 15); - - public static short makeNestedType(short type) { - return (short) (type | NLA_F_NESTED); - } - - // Return a (length, type) object only, without consuming any bytes in - // |byteBuffer| and without copying or interpreting any value bytes. - // This is used for scanning over a packed set of struct nlattr's, - // looking for instances of a particular type. - public static StructNlAttr peek(ByteBuffer byteBuffer) { - if (byteBuffer == null || byteBuffer.remaining() < NLA_HEADERLEN) { - return null; - } - final int baseOffset = byteBuffer.position(); - - // Assume the byte order of the buffer is the expected byte order of the value. - final StructNlAttr struct = new StructNlAttr(byteBuffer.order()); - // The byte order of nla_len and nla_type is always native. - final ByteOrder originalOrder = byteBuffer.order(); - byteBuffer.order(ByteOrder.nativeOrder()); - try { - struct.nla_len = byteBuffer.getShort(); - struct.nla_type = byteBuffer.getShort(); - } finally { - byteBuffer.order(originalOrder); - } - - byteBuffer.position(baseOffset); - if (struct.nla_len < NLA_HEADERLEN) { - // Malformed. - return null; - } - return struct; - } - - public static StructNlAttr parse(ByteBuffer byteBuffer) { - final StructNlAttr struct = peek(byteBuffer); - if (struct == null || byteBuffer.remaining() < struct.getAlignedLength()) { - return null; - } - - final int baseOffset = byteBuffer.position(); - byteBuffer.position(baseOffset + NLA_HEADERLEN); - - int valueLen = ((int) struct.nla_len) & 0xffff; - valueLen -= NLA_HEADERLEN; - if (valueLen > 0) { - struct.nla_value = new byte[valueLen]; - byteBuffer.get(struct.nla_value, 0, valueLen); - byteBuffer.position(baseOffset + struct.getAlignedLength()); - } - return struct; - } - - public short nla_len = (short) NLA_HEADERLEN; - public short nla_type; - public byte[] nla_value; - - // The byte order used to read/write the value member. Netlink length and - // type members are always read/written in native order. - private ByteOrder mByteOrder = ByteOrder.nativeOrder(); - - public StructNlAttr() {} - - public StructNlAttr(ByteOrder byteOrder) { - mByteOrder = byteOrder; - } - - public StructNlAttr(short type, byte value) { - nla_type = type; - setValue(new byte[1]); - nla_value[0] = value; - } - - public StructNlAttr(short type, short value) { - this(type, value, ByteOrder.nativeOrder()); - } - - public StructNlAttr(short type, short value, ByteOrder order) { - this(order); - nla_type = type; - setValue(new byte[Short.BYTES]); - getValueAsByteBuffer().putShort(value); - } - - public StructNlAttr(short type, int value) { - this(type, value, ByteOrder.nativeOrder()); - } - - public StructNlAttr(short type, int value, ByteOrder order) { - this(order); - nla_type = type; - setValue(new byte[Integer.BYTES]); - getValueAsByteBuffer().putInt(value); - } - - public StructNlAttr(short type, InetAddress ip) { - nla_type = type; - setValue(ip.getAddress()); - } - - public StructNlAttr(short type, StructNlAttr... nested) { - this(); - nla_type = makeNestedType(type); - - int payloadLength = 0; - for (StructNlAttr nla : nested) payloadLength += nla.getAlignedLength(); - setValue(new byte[payloadLength]); - - final ByteBuffer buf = getValueAsByteBuffer(); - for (StructNlAttr nla : nested) { - nla.pack(buf); - } - } - - public int getAlignedLength() { - return NetlinkConstants.alignedLengthOf(nla_len); - } - - public ByteBuffer getValueAsByteBuffer() { - if (nla_value == null) { return null; } - final ByteBuffer byteBuffer = ByteBuffer.wrap(nla_value); - byteBuffer.order(mByteOrder); - return byteBuffer; - } - - public int getValueAsInt(int defaultValue) { - final ByteBuffer byteBuffer = getValueAsByteBuffer(); - if (byteBuffer == null || byteBuffer.remaining() != Integer.BYTES) { - return defaultValue; - } - return getValueAsByteBuffer().getInt(); - } - - public InetAddress getValueAsInetAddress() { - if (nla_value == null) { return null; } - - try { - return InetAddress.getByAddress(nla_value); - } catch (UnknownHostException ignored) { - return null; - } - } - - public void pack(ByteBuffer byteBuffer) { - final ByteOrder originalOrder = byteBuffer.order(); - final int originalPosition = byteBuffer.position(); - - byteBuffer.order(ByteOrder.nativeOrder()); - try { - byteBuffer.putShort(nla_len); - byteBuffer.putShort(nla_type); - if (nla_value != null) byteBuffer.put(nla_value); - } finally { - byteBuffer.order(originalOrder); - } - byteBuffer.position(originalPosition + getAlignedLength()); - } - - private void setValue(byte[] value) { - nla_value = value; - nla_len = (short) (NLA_HEADERLEN + ((nla_value != null) ? nla_value.length : 0)); - } - - @Override - public String toString() { - return "StructNlAttr{ " - + "nla_len{" + nla_len + "}, " - + "nla_type{" + nla_type + "}, " - + "nla_value{" + NetlinkConstants.hexify(nla_value) + "}, " - + "}"; - } -} diff --git a/services/net/java/android/net/netlink/StructNlMsgErr.java b/services/net/java/android/net/netlink/StructNlMsgErr.java deleted file mode 100644 index 6fcc6e69da5b..000000000000 --- a/services/net/java/android/net/netlink/StructNlMsgErr.java +++ /dev/null @@ -1,71 +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.net.netlink; - -import android.net.netlink.NetlinkConstants; -import android.net.netlink.StructNlMsgHdr; - -import java.nio.ByteBuffer; - - -/** - * struct nlmsgerr - * - * see <linux_src>/include/uapi/linux/netlink.h - * - * @hide - */ -public class StructNlMsgErr { - public static final int STRUCT_SIZE = Integer.BYTES + StructNlMsgHdr.STRUCT_SIZE; - - public static boolean hasAvailableSpace(ByteBuffer byteBuffer) { - return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE; - } - - public static StructNlMsgErr parse(ByteBuffer byteBuffer) { - if (!hasAvailableSpace(byteBuffer)) { return null; } - - // The ByteOrder must have already been set by the caller. In most - // cases ByteOrder.nativeOrder() is correct, with the exception - // of usage within unittests. - final StructNlMsgErr struct = new StructNlMsgErr(); - struct.error = byteBuffer.getInt(); - struct.msg = StructNlMsgHdr.parse(byteBuffer); - return struct; - } - - public int error; - public StructNlMsgHdr msg; - - public void pack(ByteBuffer byteBuffer) { - // The ByteOrder must have already been set by the caller. In most - // cases ByteOrder.nativeOrder() is correct, with the possible - // exception of usage within unittests. - byteBuffer.putInt(error); - if (msg != null) { - msg.pack(byteBuffer); - } - } - - @Override - public String toString() { - return "StructNlMsgErr{ " - + "error{" + error + "}, " - + "msg{" + (msg == null ? "" : msg.toString()) + "} " - + "}"; - } -} diff --git a/services/net/java/android/net/netlink/StructNlMsgHdr.java b/services/net/java/android/net/netlink/StructNlMsgHdr.java deleted file mode 100644 index 98ab5e719d69..000000000000 --- a/services/net/java/android/net/netlink/StructNlMsgHdr.java +++ /dev/null @@ -1,140 +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.net.netlink; - -import android.net.netlink.NetlinkConstants; -import java.nio.ByteBuffer; - - -/** - * struct nlmsghdr - * - * see <linux_src>/include/uapi/linux/netlink.h - * - * @hide - */ -public class StructNlMsgHdr { - // Already aligned. - public static final int STRUCT_SIZE = 16; - - public static final short NLM_F_REQUEST = 0x0001; - public static final short NLM_F_MULTI = 0x0002; - public static final short NLM_F_ACK = 0x0004; - public static final short NLM_F_ECHO = 0x0008; - // Flags for a GET request. - public static final short NLM_F_ROOT = 0x0100; - public static final short NLM_F_MATCH = 0x0200; - public static final short NLM_F_DUMP = NLM_F_ROOT|NLM_F_MATCH; - // Flags for a NEW request. - public static final short NLM_F_REPLACE = 0x100; - public static final short NLM_F_EXCL = 0x200; - public static final short NLM_F_CREATE = 0x400; - public static final short NLM_F_APPEND = 0x800; - - - public static String stringForNlMsgFlags(short flags) { - final StringBuilder sb = new StringBuilder(); - if ((flags & NLM_F_REQUEST) != 0) { - sb.append("NLM_F_REQUEST"); - } - if ((flags & NLM_F_MULTI) != 0) { - if (sb.length() > 0) { sb.append("|"); } - sb.append("NLM_F_MULTI"); - } - if ((flags & NLM_F_ACK) != 0) { - if (sb.length() > 0) { sb.append("|"); } - sb.append("NLM_F_ACK"); - } - if ((flags & NLM_F_ECHO) != 0) { - if (sb.length() > 0) { sb.append("|"); } - sb.append("NLM_F_ECHO"); - } - if ((flags & NLM_F_ROOT) != 0) { - if (sb.length() > 0) { sb.append("|"); } - sb.append("NLM_F_ROOT"); - } - if ((flags & NLM_F_MATCH) != 0) { - if (sb.length() > 0) { sb.append("|"); } - sb.append("NLM_F_MATCH"); - } - return sb.toString(); - } - - public static boolean hasAvailableSpace(ByteBuffer byteBuffer) { - return byteBuffer != null && byteBuffer.remaining() >= STRUCT_SIZE; - } - - public static StructNlMsgHdr parse(ByteBuffer byteBuffer) { - if (!hasAvailableSpace(byteBuffer)) { return null; } - - // The ByteOrder must have already been set by the caller. In most - // cases ByteOrder.nativeOrder() is correct, with the exception - // of usage within unittests. - final StructNlMsgHdr struct = new StructNlMsgHdr(); - struct.nlmsg_len = byteBuffer.getInt(); - struct.nlmsg_type = byteBuffer.getShort(); - struct.nlmsg_flags = byteBuffer.getShort(); - struct.nlmsg_seq = byteBuffer.getInt(); - struct.nlmsg_pid = byteBuffer.getInt(); - - if (struct.nlmsg_len < STRUCT_SIZE) { - // Malformed. - return null; - } - return struct; - } - - public int nlmsg_len; - public short nlmsg_type; - public short nlmsg_flags; - public int nlmsg_seq; - public int nlmsg_pid; - - public StructNlMsgHdr() { - nlmsg_len = 0; - nlmsg_type = 0; - nlmsg_flags = 0; - nlmsg_seq = 0; - nlmsg_pid = 0; - } - - public void pack(ByteBuffer byteBuffer) { - // The ByteOrder must have already been set by the caller. In most - // cases ByteOrder.nativeOrder() is correct, with the possible - // exception of usage within unittests. - byteBuffer.putInt(nlmsg_len); - byteBuffer.putShort(nlmsg_type); - byteBuffer.putShort(nlmsg_flags); - byteBuffer.putInt(nlmsg_seq); - byteBuffer.putInt(nlmsg_pid); - } - - @Override - public String toString() { - final String typeStr = "" + nlmsg_type - + "(" + NetlinkConstants.stringForNlMsgType(nlmsg_type) + ")"; - final String flagsStr = "" + nlmsg_flags - + "(" + stringForNlMsgFlags(nlmsg_flags) + ")"; - return "StructNlMsgHdr{ " - + "nlmsg_len{" + nlmsg_len + "}, " - + "nlmsg_type{" + typeStr + "}, " - + "nlmsg_flags{" + flagsStr + ")}, " - + "nlmsg_seq{" + nlmsg_seq + "}, " - + "nlmsg_pid{" + nlmsg_pid + "} " - + "}"; - } -} diff --git a/services/net/java/android/net/shared/InitialConfiguration.java b/services/net/java/android/net/shared/InitialConfiguration.java deleted file mode 100644 index 007c8ca93d5a..000000000000 --- a/services/net/java/android/net/shared/InitialConfiguration.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (C) 2019 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.shared; - -import static android.net.shared.ParcelableUtil.fromParcelableArray; -import static android.net.shared.ParcelableUtil.toParcelableArray; -import static android.text.TextUtils.join; - -import android.net.InetAddresses; -import android.net.InitialConfigurationParcelable; -import android.net.IpPrefix; -import android.net.LinkAddress; -import android.net.RouteInfo; - -import java.net.Inet4Address; -import java.net.InetAddress; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.function.Predicate; - -/** @hide */ -public class InitialConfiguration { - public final Set<LinkAddress> ipAddresses = new HashSet<>(); - public final Set<IpPrefix> directlyConnectedRoutes = new HashSet<>(); - public final Set<InetAddress> dnsServers = new HashSet<>(); - - private static final int RFC6177_MIN_PREFIX_LENGTH = 48; - private static final int RFC7421_PREFIX_LENGTH = 64; - - public static final InetAddress INET6_ANY = InetAddresses.parseNumericAddress("::"); - - /** - * Create a InitialConfiguration that is a copy of the specified configuration. - */ - public static InitialConfiguration copy(InitialConfiguration config) { - if (config == null) { - return null; - } - InitialConfiguration configCopy = new InitialConfiguration(); - configCopy.ipAddresses.addAll(config.ipAddresses); - configCopy.directlyConnectedRoutes.addAll(config.directlyConnectedRoutes); - configCopy.dnsServers.addAll(config.dnsServers); - return configCopy; - } - - @Override - public String toString() { - return String.format( - "InitialConfiguration(IPs: {%s}, prefixes: {%s}, DNS: {%s})", - join(", ", ipAddresses), join(", ", directlyConnectedRoutes), - join(", ", dnsServers)); - } - - /** - * Tests whether the contents of this IpConfiguration represent a valid configuration. - */ - public boolean isValid() { - if (ipAddresses.isEmpty()) { - return false; - } - - // For every IP address, there must be at least one prefix containing that address. - for (LinkAddress addr : ipAddresses) { - if (!any(directlyConnectedRoutes, (p) -> p.contains(addr.getAddress()))) { - return false; - } - } - // For every dns server, there must be at least one prefix containing that address. - for (InetAddress addr : dnsServers) { - if (!any(directlyConnectedRoutes, (p) -> p.contains(addr))) { - return false; - } - } - // All IPv6 LinkAddresses have an RFC7421-suitable prefix length - // (read: compliant with RFC4291#section2.5.4). - if (any(ipAddresses, not(InitialConfiguration::isPrefixLengthCompliant))) { - return false; - } - // If directlyConnectedRoutes contains an IPv6 default route - // then ipAddresses MUST contain at least one non-ULA GUA. - if (any(directlyConnectedRoutes, InitialConfiguration::isIPv6DefaultRoute) - && all(ipAddresses, not(InitialConfiguration::isIPv6GUA))) { - return false; - } - // The prefix length of routes in directlyConnectedRoutes be within reasonable - // bounds for IPv6: /48-/64 just as we’d accept in RIOs. - if (any(directlyConnectedRoutes, not(InitialConfiguration::isPrefixLengthCompliant))) { - return false; - } - // There no more than one IPv4 address - if (ipAddresses.stream().filter(InitialConfiguration::isIPv4).count() > 1) { - return false; - } - - return true; - } - - /** - * @return true if the given list of addressess and routes satisfies provisioning for this - * InitialConfiguration. LinkAddresses and RouteInfo objects are not compared with equality - * because addresses and routes seen by Netlink will contain additional fields like flags, - * interfaces, and so on. If this InitialConfiguration has no IP address specified, the - * provisioning check always fails. - * - * If the given list of routes is null, only addresses are taken into considerations. - */ - public boolean isProvisionedBy(List<LinkAddress> addresses, List<RouteInfo> routes) { - if (ipAddresses.isEmpty()) { - return false; - } - - for (LinkAddress addr : ipAddresses) { - if (!any(addresses, (addrSeen) -> addr.isSameAddressAs(addrSeen))) { - return false; - } - } - - if (routes != null) { - for (IpPrefix prefix : directlyConnectedRoutes) { - if (!any(routes, (routeSeen) -> isDirectlyConnectedRoute(routeSeen, prefix))) { - return false; - } - } - } - - return true; - } - - /** - * Convert this configuration to a {@link InitialConfigurationParcelable}. - */ - public InitialConfigurationParcelable toStableParcelable() { - final InitialConfigurationParcelable p = new InitialConfigurationParcelable(); - p.ipAddresses = ipAddresses.toArray(new LinkAddress[0]); - p.directlyConnectedRoutes = directlyConnectedRoutes.toArray(new IpPrefix[0]); - p.dnsServers = toParcelableArray( - dnsServers, IpConfigurationParcelableUtil::parcelAddress, String.class); - return p; - } - - /** - * Create an instance of {@link InitialConfiguration} based on the contents of the specified - * {@link InitialConfigurationParcelable}. - */ - public static InitialConfiguration fromStableParcelable(InitialConfigurationParcelable p) { - if (p == null) return null; - final InitialConfiguration config = new InitialConfiguration(); - config.ipAddresses.addAll(Arrays.asList(p.ipAddresses)); - config.directlyConnectedRoutes.addAll(Arrays.asList(p.directlyConnectedRoutes)); - config.dnsServers.addAll( - fromParcelableArray(p.dnsServers, IpConfigurationParcelableUtil::unparcelAddress)); - return config; - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof InitialConfiguration)) return false; - final InitialConfiguration other = (InitialConfiguration) obj; - return ipAddresses.equals(other.ipAddresses) - && directlyConnectedRoutes.equals(other.directlyConnectedRoutes) - && dnsServers.equals(other.dnsServers); - } - - private static boolean isDirectlyConnectedRoute(RouteInfo route, IpPrefix prefix) { - return !route.hasGateway() && prefix.equals(route.getDestination()); - } - - private static boolean isPrefixLengthCompliant(LinkAddress addr) { - return isIPv4(addr) || isCompliantIPv6PrefixLength(addr.getPrefixLength()); - } - - private static boolean isPrefixLengthCompliant(IpPrefix prefix) { - return isIPv4(prefix) || isCompliantIPv6PrefixLength(prefix.getPrefixLength()); - } - - private static boolean isCompliantIPv6PrefixLength(int prefixLength) { - return (RFC6177_MIN_PREFIX_LENGTH <= prefixLength) - && (prefixLength <= RFC7421_PREFIX_LENGTH); - } - - private static boolean isIPv4(IpPrefix prefix) { - return prefix.getAddress() instanceof Inet4Address; - } - - private static boolean isIPv4(LinkAddress addr) { - return addr.getAddress() instanceof Inet4Address; - } - - private static boolean isIPv6DefaultRoute(IpPrefix prefix) { - return prefix.getAddress().equals(INET6_ANY); - } - - private static boolean isIPv6GUA(LinkAddress addr) { - return addr.isIpv6() && addr.isGlobalPreferred(); - } - - // TODO: extract out into CollectionUtils. - - /** - * Indicate whether any element of the specified iterable verifies the specified predicate. - */ - public static <T> boolean any(Iterable<T> coll, Predicate<T> fn) { - for (T t : coll) { - if (fn.test(t)) { - return true; - } - } - return false; - } - - /** - * Indicate whether all elements of the specified iterable verifies the specified predicate. - */ - public static <T> boolean all(Iterable<T> coll, Predicate<T> fn) { - return !any(coll, not(fn)); - } - - /** - * Create a predicate that returns the opposite value of the specified predicate. - */ - public static <T> Predicate<T> not(Predicate<T> fn) { - return (t) -> !fn.test(t); - } -} diff --git a/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java b/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java deleted file mode 100644 index 172dc24df6b0..000000000000 --- a/services/net/java/android/net/shared/IpConfigurationParcelableUtil.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2019 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.shared; - -import android.annotation.Nullable; -import android.net.DhcpResults; -import android.net.DhcpResultsParcelable; -import android.net.InetAddresses; - -import java.net.Inet4Address; -import java.net.InetAddress; - -/** - * Collection of utility methods to convert to and from stable AIDL parcelables for IpClient - * configuration classes. - * @hide - */ -public final class IpConfigurationParcelableUtil { - /** - * Convert DhcpResults to a DhcpResultsParcelable. - */ - public static DhcpResultsParcelable toStableParcelable(@Nullable DhcpResults results) { - if (results == null) return null; - final DhcpResultsParcelable p = new DhcpResultsParcelable(); - p.baseConfiguration = results.toStaticIpConfiguration(); - p.leaseDuration = results.leaseDuration; - p.mtu = results.mtu; - p.serverAddress = parcelAddress(results.serverAddress); - p.vendorInfo = results.vendorInfo; - p.serverHostName = results.serverHostName; - return p; - } - - /** - * Convert a DhcpResultsParcelable to DhcpResults. - */ - public static DhcpResults fromStableParcelable(@Nullable DhcpResultsParcelable p) { - if (p == null) return null; - final DhcpResults results = new DhcpResults(p.baseConfiguration); - results.leaseDuration = p.leaseDuration; - results.mtu = p.mtu; - results.serverAddress = (Inet4Address) unparcelAddress(p.serverAddress); - results.vendorInfo = p.vendorInfo; - results.serverHostName = p.serverHostName; - return results; - } - - /** - * Convert InetAddress to String. - * TODO: have an InetAddressParcelable - */ - public static String parcelAddress(@Nullable InetAddress addr) { - if (addr == null) return null; - return addr.getHostAddress(); - } - - /** - * Convert String to InetAddress. - * TODO: have an InetAddressParcelable - */ - public static InetAddress unparcelAddress(@Nullable String addr) { - if (addr == null) return null; - return InetAddresses.parseNumericAddress(addr); - } -} diff --git a/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java b/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java deleted file mode 100644 index 1729da6eb141..000000000000 --- a/services/net/java/android/net/shared/LinkPropertiesParcelableUtil.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2019 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.shared; - -import android.annotation.Nullable; -import android.net.LinkProperties; -import android.net.ProxyInfo; - -/** - * Collection of utility methods to convert to and from stable AIDL parcelables for LinkProperties - * and its attributes. - * @hide - */ -public final class LinkPropertiesParcelableUtil { - // Temporary methods to facilitate migrating clients away from LinkPropertiesParcelable - // TODO: remove the following methods after migrating clients. - - /** - * @deprecated conversion to stable parcelable is no longer necessary. - */ - @Deprecated - public static LinkProperties toStableParcelable(@Nullable LinkProperties lp) { - return lp; - } - - /** - * @deprecated conversion to stable parcelable is no longer necessary. - */ - @Deprecated - public static ProxyInfo toStableParcelable(@Nullable ProxyInfo info) { - return info; - } -} diff --git a/services/net/java/android/net/shared/NetworkMonitorUtils.java b/services/net/java/android/net/shared/NetworkMonitorUtils.java deleted file mode 100644 index 46e9c7373f97..000000000000 --- a/services/net/java/android/net/shared/NetworkMonitorUtils.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2018 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.shared; - -import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; -import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; -import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED; - -import android.net.NetworkCapabilities; - -/** @hide */ -public class NetworkMonitorUtils { - - // Network conditions broadcast constants - public static final String ACTION_NETWORK_CONDITIONS_MEASURED = - "android.net.conn.NETWORK_CONDITIONS_MEASURED"; - public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type"; - public static final String EXTRA_NETWORK_TYPE = "extra_network_type"; - public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received"; - public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal"; - public static final String EXTRA_CELL_ID = "extra_cellid"; - public static final String EXTRA_SSID = "extra_ssid"; - public static final String EXTRA_BSSID = "extra_bssid"; - /** real time since boot */ - public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms"; - public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms"; - public static final String PERMISSION_ACCESS_NETWORK_CONDITIONS = - "android.permission.ACCESS_NETWORK_CONDITIONS"; - - /** - * Return whether validation is required for private DNS in strict mode. - * @param nc Network capabilities of the network to test. - */ - public static boolean isPrivateDnsValidationRequired(NetworkCapabilities nc) { - // TODO: Consider requiring validation for DUN networks. - return nc != null - && nc.hasCapability(NET_CAPABILITY_INTERNET) - && nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) - && nc.hasCapability(NET_CAPABILITY_TRUSTED); - } - - /** - * Return whether validation is required for a network. - * @param nc Network capabilities of the network to test. - */ - public static boolean isValidationRequired(NetworkCapabilities nc) { - // TODO: Consider requiring validation for DUN networks. - return isPrivateDnsValidationRequired(nc) && nc.hasCapability(NET_CAPABILITY_NOT_VPN); - } -} diff --git a/services/net/java/android/net/shared/ParcelableUtil.java b/services/net/java/android/net/shared/ParcelableUtil.java deleted file mode 100644 index 3f4030047938..000000000000 --- a/services/net/java/android/net/shared/ParcelableUtil.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2019 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.shared; - -import android.annotation.NonNull; - -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Collection; -import java.util.function.Function; - -/** - * Utility methods to help convert to/from stable parcelables. - * @hide - */ -public final class ParcelableUtil { - // Below methods could be implemented easily with streams, but streams are frowned upon in - // frameworks code. - - /** - * Convert a list of BaseType items to an array of ParcelableType items using the specified - * converter function. - */ - public static <ParcelableType, BaseType> ParcelableType[] toParcelableArray( - @NonNull Collection<BaseType> base, - @NonNull Function<BaseType, ParcelableType> conv, - @NonNull Class<ParcelableType> parcelClass) { - final ParcelableType[] out = (ParcelableType[]) Array.newInstance(parcelClass, base.size()); - int i = 0; - for (BaseType b : base) { - out[i] = conv.apply(b); - i++; - } - return out; - } - - /** - * Convert an array of ParcelableType items to a list of BaseType items using the specified - * converter function. - */ - public static <ParcelableType, BaseType> ArrayList<BaseType> fromParcelableArray( - @NonNull ParcelableType[] parceled, @NonNull Function<ParcelableType, BaseType> conv) { - final ArrayList<BaseType> out = new ArrayList<>(parceled.length); - for (ParcelableType t : parceled) { - out.add(conv.apply(t)); - } - return out; - } -} diff --git a/services/net/java/android/net/shared/PrivateDnsConfig.java b/services/net/java/android/net/shared/PrivateDnsConfig.java deleted file mode 100644 index c7dc5306b51b..000000000000 --- a/services/net/java/android/net/shared/PrivateDnsConfig.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2018 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.shared; - -import static android.net.shared.ParcelableUtil.fromParcelableArray; -import static android.net.shared.ParcelableUtil.toParcelableArray; - -import android.net.PrivateDnsConfigParcel; -import android.text.TextUtils; - -import java.net.InetAddress; -import java.util.Arrays; - -/** @hide */ -public class PrivateDnsConfig { - public final boolean useTls; - public final String hostname; - public final InetAddress[] ips; - - public PrivateDnsConfig() { - this(false); - } - - public PrivateDnsConfig(boolean useTls) { - this.useTls = useTls; - this.hostname = ""; - this.ips = new InetAddress[0]; - } - - public PrivateDnsConfig(String hostname, InetAddress[] ips) { - this.useTls = !TextUtils.isEmpty(hostname); - this.hostname = useTls ? hostname : ""; - this.ips = (ips != null) ? ips : new InetAddress[0]; - } - - public PrivateDnsConfig(PrivateDnsConfig cfg) { - useTls = cfg.useTls; - hostname = cfg.hostname; - ips = cfg.ips; - } - - /** - * Indicates whether this is a strict mode private DNS configuration. - */ - public boolean inStrictMode() { - return useTls && !TextUtils.isEmpty(hostname); - } - - @Override - public String toString() { - return PrivateDnsConfig.class.getSimpleName() - + "{" + useTls + ":" + hostname + "/" + Arrays.toString(ips) + "}"; - } - - /** - * Create a stable AIDL-compatible parcel from the current instance. - */ - public PrivateDnsConfigParcel toParcel() { - final PrivateDnsConfigParcel parcel = new PrivateDnsConfigParcel(); - parcel.hostname = hostname; - parcel.ips = toParcelableArray( - Arrays.asList(ips), IpConfigurationParcelableUtil::parcelAddress, String.class); - - return parcel; - } - - /** - * Build a configuration from a stable AIDL-compatible parcel. - */ - public static PrivateDnsConfig fromParcel(PrivateDnsConfigParcel parcel) { - InetAddress[] ips = new InetAddress[parcel.ips.length]; - ips = fromParcelableArray(parcel.ips, IpConfigurationParcelableUtil::unparcelAddress) - .toArray(ips); - return new PrivateDnsConfig(parcel.hostname, ips); - } -} diff --git a/services/net/java/android/net/shared/ProvisioningConfiguration.java b/services/net/java/android/net/shared/ProvisioningConfiguration.java deleted file mode 100644 index 6f9c2949d864..000000000000 --- a/services/net/java/android/net/shared/ProvisioningConfiguration.java +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright (C) 2019 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.shared; - -import android.annotation.Nullable; -import android.net.INetd; -import android.net.Network; -import android.net.ProvisioningConfigurationParcelable; -import android.net.StaticIpConfiguration; -import android.net.apf.ApfCapabilities; -import android.net.ip.IIpClient; - -import java.util.Objects; -import java.util.StringJoiner; - -/** - * This class encapsulates parameters to be passed to - * IpClient#startProvisioning(). A defensive copy is made by IpClient - * and the values specified herein are in force until IpClient#stop() - * is called. - * - * Example use: - * - * final ProvisioningConfiguration config = - * new ProvisioningConfiguration.Builder() - * .withPreDhcpAction() - * .withProvisioningTimeoutMs(36 * 1000) - * .build(); - * mIpClient.startProvisioning(config.toStableParcelable()); - * ... - * mIpClient.stop(); - * - * The specified provisioning configuration will only be active until - * IIpClient#stop() is called. Future calls to IIpClient#startProvisioning() - * must specify the configuration again. - * @hide - */ -public class ProvisioningConfiguration { - // TODO: Delete this default timeout once those callers that care are - // fixed to pass in their preferred timeout. - // - // We pick 36 seconds so we can send DHCP requests at - // - // t=0, t=2, t=6, t=14, t=30 - // - // allowing for 10% jitter. - private static final int DEFAULT_TIMEOUT_MS = 36 * 1000; - - /** - * Builder to create a {@link ProvisioningConfiguration}. - */ - public static class Builder { - protected ProvisioningConfiguration mConfig = new ProvisioningConfiguration(); - - /** - * Specify that the configuration should not enable IPv4. It is enabled by default. - */ - public Builder withoutIPv4() { - mConfig.mEnableIPv4 = false; - return this; - } - - /** - * Specify that the configuration should not enable IPv6. It is enabled by default. - */ - public Builder withoutIPv6() { - mConfig.mEnableIPv6 = false; - return this; - } - - /** - * Specify that the configuration should not use a MultinetworkPolicyTracker. It is used - * by default. - */ - public Builder withoutMultinetworkPolicyTracker() { - mConfig.mUsingMultinetworkPolicyTracker = false; - return this; - } - - /** - * Specify that the configuration should not use a IpReachabilityMonitor. It is used by - * default. - */ - public Builder withoutIpReachabilityMonitor() { - mConfig.mUsingIpReachabilityMonitor = false; - return this; - } - - /** - * Identical to {@link #withPreDhcpAction(int)}, using a default timeout. - * @see #withPreDhcpAction(int) - */ - public Builder withPreDhcpAction() { - mConfig.mRequestedPreDhcpActionMs = DEFAULT_TIMEOUT_MS; - return this; - } - - /** - * Specify that {@link IpClientCallbacks#onPreDhcpAction()} should be called. Clients must - * call {@link IIpClient#completedPreDhcpAction()} when the callback called. This behavior - * is disabled by default. - * @param dhcpActionTimeoutMs Timeout for clients to call completedPreDhcpAction(). - */ - public Builder withPreDhcpAction(int dhcpActionTimeoutMs) { - mConfig.mRequestedPreDhcpActionMs = dhcpActionTimeoutMs; - return this; - } - - /** - * Specify the initial provisioning configuration. - */ - public Builder withInitialConfiguration(InitialConfiguration initialConfig) { - mConfig.mInitialConfig = initialConfig; - return this; - } - - /** - * Specify a static configuration for provisioning. - */ - public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) { - mConfig.mStaticIpConfig = staticConfig; - return this; - } - - /** - * Specify ApfCapabilities. - */ - public Builder withApfCapabilities(ApfCapabilities apfCapabilities) { - mConfig.mApfCapabilities = apfCapabilities; - return this; - } - - /** - * Specify the timeout to use for provisioning. - */ - public Builder withProvisioningTimeoutMs(int timeoutMs) { - mConfig.mProvisioningTimeoutMs = timeoutMs; - return this; - } - - /** - * Specify that IPv6 address generation should use a random MAC address. - */ - public Builder withRandomMacAddress() { - mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_EUI64; - return this; - } - - /** - * Specify that IPv6 address generation should use a stable MAC address. - */ - public Builder withStableMacAddress() { - mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY; - return this; - } - - /** - * Specify the network to use for provisioning. - */ - public Builder withNetwork(Network network) { - mConfig.mNetwork = network; - return this; - } - - /** - * Specify the display name that the IpClient should use. - */ - public Builder withDisplayName(String displayName) { - mConfig.mDisplayName = displayName; - return this; - } - - /** - * Build the configuration using previously specified parameters. - */ - public ProvisioningConfiguration build() { - return new ProvisioningConfiguration(mConfig); - } - } - - public boolean mEnableIPv4 = true; - public boolean mEnableIPv6 = true; - public boolean mUsingMultinetworkPolicyTracker = true; - public boolean mUsingIpReachabilityMonitor = true; - public int mRequestedPreDhcpActionMs; - public InitialConfiguration mInitialConfig; - public StaticIpConfiguration mStaticIpConfig; - public ApfCapabilities mApfCapabilities; - public int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS; - public int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY; - public Network mNetwork = null; - public String mDisplayName = null; - - public ProvisioningConfiguration() {} // used by Builder - - public ProvisioningConfiguration(ProvisioningConfiguration other) { - mEnableIPv4 = other.mEnableIPv4; - mEnableIPv6 = other.mEnableIPv6; - mUsingMultinetworkPolicyTracker = other.mUsingMultinetworkPolicyTracker; - mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor; - mRequestedPreDhcpActionMs = other.mRequestedPreDhcpActionMs; - mInitialConfig = InitialConfiguration.copy(other.mInitialConfig); - mStaticIpConfig = other.mStaticIpConfig == null - ? null - : new StaticIpConfiguration(other.mStaticIpConfig); - mApfCapabilities = other.mApfCapabilities; - mProvisioningTimeoutMs = other.mProvisioningTimeoutMs; - mIPv6AddrGenMode = other.mIPv6AddrGenMode; - mNetwork = other.mNetwork; - mDisplayName = other.mDisplayName; - } - - /** - * Create a ProvisioningConfigurationParcelable from this ProvisioningConfiguration. - */ - public ProvisioningConfigurationParcelable toStableParcelable() { - final ProvisioningConfigurationParcelable p = new ProvisioningConfigurationParcelable(); - p.enableIPv4 = mEnableIPv4; - p.enableIPv6 = mEnableIPv6; - p.usingMultinetworkPolicyTracker = mUsingMultinetworkPolicyTracker; - p.usingIpReachabilityMonitor = mUsingIpReachabilityMonitor; - p.requestedPreDhcpActionMs = mRequestedPreDhcpActionMs; - p.initialConfig = mInitialConfig == null ? null : mInitialConfig.toStableParcelable(); - p.staticIpConfig = mStaticIpConfig == null - ? null - : new StaticIpConfiguration(mStaticIpConfig); - p.apfCapabilities = mApfCapabilities; // ApfCapabilities is immutable - p.provisioningTimeoutMs = mProvisioningTimeoutMs; - p.ipv6AddrGenMode = mIPv6AddrGenMode; - p.network = mNetwork; - p.displayName = mDisplayName; - return p; - } - - /** - * Create a ProvisioningConfiguration from a ProvisioningConfigurationParcelable. - */ - public static ProvisioningConfiguration fromStableParcelable( - @Nullable ProvisioningConfigurationParcelable p) { - if (p == null) return null; - final ProvisioningConfiguration config = new ProvisioningConfiguration(); - config.mEnableIPv4 = p.enableIPv4; - config.mEnableIPv6 = p.enableIPv6; - config.mUsingMultinetworkPolicyTracker = p.usingMultinetworkPolicyTracker; - config.mUsingIpReachabilityMonitor = p.usingIpReachabilityMonitor; - config.mRequestedPreDhcpActionMs = p.requestedPreDhcpActionMs; - config.mInitialConfig = InitialConfiguration.fromStableParcelable(p.initialConfig); - config.mStaticIpConfig = p.staticIpConfig == null - ? null - : new StaticIpConfiguration(p.staticIpConfig); - config.mApfCapabilities = p.apfCapabilities; // ApfCapabilities is immutable - config.mProvisioningTimeoutMs = p.provisioningTimeoutMs; - config.mIPv6AddrGenMode = p.ipv6AddrGenMode; - config.mNetwork = p.network; - config.mDisplayName = p.displayName; - return config; - } - - @Override - public String toString() { - return new StringJoiner(", ", getClass().getSimpleName() + "{", "}") - .add("mEnableIPv4: " + mEnableIPv4) - .add("mEnableIPv6: " + mEnableIPv6) - .add("mUsingMultinetworkPolicyTracker: " + mUsingMultinetworkPolicyTracker) - .add("mUsingIpReachabilityMonitor: " + mUsingIpReachabilityMonitor) - .add("mRequestedPreDhcpActionMs: " + mRequestedPreDhcpActionMs) - .add("mInitialConfig: " + mInitialConfig) - .add("mStaticIpConfig: " + mStaticIpConfig) - .add("mApfCapabilities: " + mApfCapabilities) - .add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs) - .add("mIPv6AddrGenMode: " + mIPv6AddrGenMode) - .add("mNetwork: " + mNetwork) - .add("mDisplayName: " + mDisplayName) - .toString(); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof ProvisioningConfiguration)) return false; - final ProvisioningConfiguration other = (ProvisioningConfiguration) obj; - return mEnableIPv4 == other.mEnableIPv4 - && mEnableIPv6 == other.mEnableIPv6 - && mUsingMultinetworkPolicyTracker == other.mUsingMultinetworkPolicyTracker - && mUsingIpReachabilityMonitor == other.mUsingIpReachabilityMonitor - && mRequestedPreDhcpActionMs == other.mRequestedPreDhcpActionMs - && Objects.equals(mInitialConfig, other.mInitialConfig) - && Objects.equals(mStaticIpConfig, other.mStaticIpConfig) - && Objects.equals(mApfCapabilities, other.mApfCapabilities) - && mProvisioningTimeoutMs == other.mProvisioningTimeoutMs - && mIPv6AddrGenMode == other.mIPv6AddrGenMode - && Objects.equals(mNetwork, other.mNetwork) - && Objects.equals(mDisplayName, other.mDisplayName); - } - - public boolean isValid() { - return (mInitialConfig == null) || mInitialConfig.isValid(); - } -} diff --git a/services/net/java/android/net/util/InterfaceParams.java b/services/net/java/android/net/util/InterfaceParams.java deleted file mode 100644 index f6bb87369cad..000000000000 --- a/services/net/java/android/net/util/InterfaceParams.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2017 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.util; - -import static com.android.internal.util.Preconditions.checkArgument; - -import android.net.MacAddress; -import android.text.TextUtils; - -import java.net.NetworkInterface; -import java.net.SocketException; - - -/** - * Encapsulate the interface parameters common to IpClient/IpServer components. - * - * Basically all java.net.NetworkInterface methods throw Exceptions. IpClient - * and IpServer (sub)components need most or all of this information at some - * point during their lifecycles, so pass only this simplified object around - * which can be created once when IpClient/IpServer are told to start. - * - * @hide - */ -public class InterfaceParams { - public final String name; - public final int index; - public final MacAddress macAddr; - public final int defaultMtu; - - // TODO: move the below to NetworkStackConstants when this class is moved to the NetworkStack. - private static final int ETHER_MTU = 1500; - private static final int IPV6_MIN_MTU = 1280; - - - public static InterfaceParams getByName(String name) { - final NetworkInterface netif = getNetworkInterfaceByName(name); - if (netif == null) return null; - - // Not all interfaces have MAC addresses, e.g. rmnet_data0. - final MacAddress macAddr = getMacAddress(netif); - - try { - return new InterfaceParams(name, netif.getIndex(), macAddr, netif.getMTU()); - } catch (IllegalArgumentException|SocketException e) { - return null; - } - } - - public InterfaceParams(String name, int index, MacAddress macAddr) { - this(name, index, macAddr, ETHER_MTU); - } - - public InterfaceParams(String name, int index, MacAddress macAddr, int defaultMtu) { - checkArgument((!TextUtils.isEmpty(name)), "impossible interface name"); - checkArgument((index > 0), "invalid interface index"); - this.name = name; - this.index = index; - this.macAddr = (macAddr != null) ? macAddr : MacAddress.fromBytes(new byte[] { - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }); - this.defaultMtu = (defaultMtu > IPV6_MIN_MTU) ? defaultMtu : IPV6_MIN_MTU; - } - - @Override - public String toString() { - return String.format("%s/%d/%s/%d", name, index, macAddr, defaultMtu); - } - - private static NetworkInterface getNetworkInterfaceByName(String name) { - try { - return NetworkInterface.getByName(name); - } catch (NullPointerException|SocketException e) { - return null; - } - } - - private static MacAddress getMacAddress(NetworkInterface netif) { - try { - return MacAddress.fromBytes(netif.getHardwareAddress()); - } catch (IllegalArgumentException|NullPointerException|SocketException e) { - return null; - } - } -} diff --git a/services/net/java/android/net/util/SharedLog.java b/services/net/java/android/net/util/SharedLog.java deleted file mode 100644 index 2cdb2b04f8f7..000000000000 --- a/services/net/java/android/net/util/SharedLog.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2017 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.util; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.text.TextUtils; -import android.util.LocalLog; -import android.util.Log; - -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.StringJoiner; - - -/** - * Class to centralize logging functionality for tethering. - * - * All access to class methods other than dump() must be on the same thread. - * - * TODO: this is a copy of SharedLog in the NetworkStack. Remove after Tethering is migrated. - * @hide - */ -public class SharedLog { - private static final int DEFAULT_MAX_RECORDS = 500; - private static final String COMPONENT_DELIMITER = "."; - - private enum Category { - NONE, - ERROR, - MARK, - WARN, - }; - - private final LocalLog mLocalLog; - // The tag to use for output to the system log. This is not output to the - // LocalLog because that would be redundant. - private final String mTag; - // The component (or subcomponent) of a system that is sharing this log. - // This can grow in depth if components call forSubComponent() to obtain - // their SharedLog instance. The tag is not included in the component for - // brevity. - private final String mComponent; - - public SharedLog(String tag) { - this(DEFAULT_MAX_RECORDS, tag); - } - - public SharedLog(int maxRecords, String tag) { - this(new LocalLog(maxRecords), tag, tag); - } - - private SharedLog(LocalLog localLog, String tag, String component) { - mLocalLog = localLog; - mTag = tag; - mComponent = component; - } - - public String getTag() { - return mTag; - } - - /** - * Create a SharedLog based on this log with an additional component prefix on each logged line. - */ - public SharedLog forSubComponent(String component) { - if (!isRootLogInstance()) { - component = mComponent + COMPONENT_DELIMITER + component; - } - return new SharedLog(mLocalLog, mTag, component); - } - - /** - * Dump the contents of this log. - * - * <p>This method may be called on any thread. - */ - public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { - mLocalLog.readOnlyLocalLog().dump(fd, writer, args); - } - - ////// - // Methods that both log an entry and emit it to the system log. - ////// - - /** - * Log an error due to an exception. This does not include the exception stacktrace. - * - * <p>The log entry will be also added to the system log. - * @see #e(String, Throwable) - */ - public void e(Exception e) { - Log.e(mTag, record(Category.ERROR, e.toString())); - } - - /** - * Log an error message. - * - * <p>The log entry will be also added to the system log. - */ - public void e(String msg) { - Log.e(mTag, record(Category.ERROR, msg)); - } - - /** - * Log an error due to an exception, with the exception stacktrace if provided. - * - * <p>The error and exception message appear in the shared log, but the stacktrace is only - * logged in general log output (logcat). The log entry will be also added to the system log. - */ - public void e(@NonNull String msg, @Nullable Throwable exception) { - if (exception == null) { - e(msg); - return; - } - Log.e(mTag, record(Category.ERROR, msg + ": " + exception.getMessage()), exception); - } - - /** - * Log an informational message. - * - * <p>The log entry will be also added to the system log. - */ - public void i(String msg) { - Log.i(mTag, record(Category.NONE, msg)); - } - - /** - * Log a warning message. - * - * <p>The log entry will be also added to the system log. - */ - public void w(String msg) { - Log.w(mTag, record(Category.WARN, msg)); - } - - ////// - // Methods that only log an entry (and do NOT emit to the system log). - ////// - - /** - * Log a general message to be only included in the in-memory log. - * - * <p>The log entry will *not* be added to the system log. - */ - public void log(String msg) { - record(Category.NONE, msg); - } - - /** - * Log a general, formatted message to be only included in the in-memory log. - * - * <p>The log entry will *not* be added to the system log. - * @see String#format(String, Object...) - */ - public void logf(String fmt, Object... args) { - log(String.format(fmt, args)); - } - - /** - * Log a message with MARK level. - * - * <p>The log entry will *not* be added to the system log. - */ - public void mark(String msg) { - record(Category.MARK, msg); - } - - private String record(Category category, String msg) { - final String entry = logLine(category, msg); - mLocalLog.log(entry); - return entry; - } - - private String logLine(Category category, String msg) { - final StringJoiner sj = new StringJoiner(" "); - if (!isRootLogInstance()) sj.add("[" + mComponent + "]"); - if (category != Category.NONE) sj.add(category.toString()); - return sj.add(msg).toString(); - } - - // Check whether this SharedLog instance is nominally the top level in - // a potential hierarchy of shared logs (the root of a tree), - // or is a subcomponent within the hierarchy. - private boolean isRootLogInstance() { - return TextUtils.isEmpty(mComponent) || mComponent.equals(mTag); - } -} diff --git a/services/print/Android.bp b/services/print/Android.bp index 80a8c7560de6..aad24d72345b 100644 --- a/services/print/Android.bp +++ b/services/print/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.print-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.print", - srcs: ["java/**/*.java"], + srcs: [":services.print-sources"], libs: ["services.core"], } diff --git a/services/restrictions/Android.bp b/services/restrictions/Android.bp index 979e891ada5f..805858f7f654 100644 --- a/services/restrictions/Android.bp +++ b/services/restrictions/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.restrictions-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.restrictions", - srcs: ["java/**/*.java"], + srcs: [":services.restrictions-sources"], libs: ["services.core"], } diff --git a/services/systemcaptions/Android.bp b/services/systemcaptions/Android.bp index 4e190b639b2c..1ce3e665c665 100644 --- a/services/systemcaptions/Android.bp +++ b/services/systemcaptions/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.systemcaptions-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.systemcaptions", - srcs: ["java/**/*.java"], + srcs: [":services.systemcaptions-sources"], libs: ["services.core"], } diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp index 8699669bf4a5..96fedf933a9c 100644 --- a/services/tests/mockingservicestests/Android.bp +++ b/services/tests/mockingservicestests/Android.bp @@ -20,7 +20,7 @@ android_test { static_libs: [ "services.core", "services.net", - "jobscheduler-service", + "service-jobscheduler", "androidx.test.runner", "mockito-target-extended-minus-junit4", "platform-test-annotations", diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java index e7f6a7484881..6c09239251bd 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java @@ -1027,11 +1027,28 @@ public class MockingOomAdjusterTests { bindService(client, client2, null, 0, mock(IBinder.class)); client2.setHasForegroundServices(true, 0); bindService(client2, app, null, 0, mock(IBinder.class)); + ArrayList<ProcessRecord> lru = sService.mProcessList.mLruProcesses; + lru.clear(); + lru.add(app); + lru.add(client); + lru.add(client2); sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE; - sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE); + sService.mOomAdjuster.updateOomAdjLocked(app, true, OomAdjuster.OOM_ADJ_REASON_NONE); assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ, SCHED_GROUP_DEFAULT); + assertProcStates(client, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ, + SCHED_GROUP_DEFAULT); + assertProcStates(client2, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ, + SCHED_GROUP_DEFAULT); + + client2.setHasForegroundServices(false, 0); + sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE; + sService.mOomAdjuster.updateOomAdjLocked(client2, true, OomAdjuster.OOM_ADJ_REASON_NONE); + + assertEquals(PROCESS_STATE_CACHED_EMPTY, client2.setProcState); + assertEquals(PROCESS_STATE_CACHED_EMPTY, client.setProcState); + assertEquals(PROCESS_STATE_CACHED_EMPTY, app.setProcState); } @SuppressWarnings("GuardedBy") diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp index 52fb69eb99be..0be5fe02f0fe 100644 --- a/services/tests/servicestests/Android.bp +++ b/services/tests/servicestests/Android.bp @@ -41,7 +41,7 @@ android_test { "hamcrest-library", "servicestests-utils", "xml-writer-device-lib", - "jobscheduler-service", + "service-jobscheduler", ], aidl: { diff --git a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java index 839b25f8491d..e18ff61e32dc 100644 --- a/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/CrossProfileAppsServiceImplTest.java @@ -509,7 +509,7 @@ public class CrossProfileAppsServiceImplTest { mActivityInfo = activityInfo; when(mPackageManagerInternal.queryIntentActivities( - any(Intent.class), anyInt(), anyInt(), anyInt())) + any(Intent.class), nullable(String.class), anyInt(), anyInt(), anyInt())) .thenReturn(Collections.singletonList(resolveInfo)); } diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java new file mode 100644 index 000000000000..1f312bf1296d --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2019 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.server.recoverysystem; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.os.Handler; +import android.os.IPowerManager; +import android.os.IRecoverySystemProgressListener; +import android.os.Looper; +import android.os.PowerManager; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.FileWriter; + +/** + * atest FrameworksServicesTests:RecoverySystemServiceTest + */ +@SmallTest +@RunWith(AndroidJUnit4.class) +public class RecoverySystemServiceTest { + private RecoverySystemService mRecoverySystemService; + private RecoverySystemServiceTestable.FakeSystemProperties mSystemProperties; + private RecoverySystemService.UncryptSocket mUncryptSocket; + private Context mContext; + private IPowerManager mIPowerManager; + private FileWriter mUncryptUpdateFileWriter; + + @Before + public void setup() { + mContext = mock(Context.class); + mSystemProperties = new RecoverySystemServiceTestable.FakeSystemProperties(); + mUncryptSocket = mock(RecoverySystemService.UncryptSocket.class); + mUncryptUpdateFileWriter = mock(FileWriter.class); + + Looper looper = InstrumentationRegistry.getContext().getMainLooper(); + mIPowerManager = mock(IPowerManager.class); + PowerManager powerManager = new PowerManager(mock(Context.class), mIPowerManager, + new Handler(looper)); + + mRecoverySystemService = new RecoverySystemServiceTestable(mContext, mSystemProperties, + powerManager, mUncryptUpdateFileWriter, mUncryptSocket); + } + + @Test + public void clearBcb_success() throws Exception { + doNothing().when(mContext).enforceCallingOrSelfPermission( + eq(android.Manifest.permission.RECOVERY), any()); + when(mUncryptSocket.getPercentageUncrypted()).thenReturn(100); + + assertThat(mRecoverySystemService.clearBcb(), is(true)); + + assertThat(mSystemProperties.getCtlStart(), is("clear-bcb")); + verify(mUncryptSocket).sendAck(); + verify(mUncryptSocket).close(); + } + + @Test + public void clearBcb_uncrypt_failure() throws Exception { + doNothing().when(mContext).enforceCallingOrSelfPermission( + eq(android.Manifest.permission.RECOVERY), any()); + when(mUncryptSocket.getPercentageUncrypted()).thenReturn(0); + + assertThat(mRecoverySystemService.clearBcb(), is(false)); + + assertThat(mSystemProperties.getCtlStart(), is("clear-bcb")); + verify(mUncryptSocket).sendAck(); + verify(mUncryptSocket).close(); + } + + @Test(expected = SecurityException.class) + public void clearBcb_noPerm() { + doThrow(SecurityException.class).when(mContext).enforceCallingOrSelfPermission( + eq(android.Manifest.permission.RECOVERY), any()); + mRecoverySystemService.clearBcb(); + } + + @Test + public void setupBcb_success() throws Exception { + doNothing().when(mContext).enforceCallingOrSelfPermission( + eq(android.Manifest.permission.RECOVERY), any()); + when(mUncryptSocket.getPercentageUncrypted()).thenReturn(100); + + assertThat(mRecoverySystemService.setupBcb("foo"), is(true)); + + assertThat(mSystemProperties.getCtlStart(), is("setup-bcb")); + verify(mUncryptSocket).sendCommand("foo"); + verify(mUncryptSocket).sendAck(); + verify(mUncryptSocket).close(); + } + + @Test + public void setupBcb_uncrypt_failure() throws Exception { + doNothing().when(mContext).enforceCallingOrSelfPermission( + eq(android.Manifest.permission.RECOVERY), any()); + when(mUncryptSocket.getPercentageUncrypted()).thenReturn(0); + + assertThat(mRecoverySystemService.setupBcb("foo"), is(false)); + + assertThat(mSystemProperties.getCtlStart(), is("setup-bcb")); + verify(mUncryptSocket).sendCommand("foo"); + verify(mUncryptSocket).sendAck(); + verify(mUncryptSocket).close(); + } + + @Test(expected = SecurityException.class) + public void setupBcb_noPerm() { + doThrow(SecurityException.class).when(mContext).enforceCallingOrSelfPermission( + eq(android.Manifest.permission.RECOVERY), any()); + mRecoverySystemService.setupBcb("foo"); + } + + @Test + public void rebootRecoveryWithCommand_success() throws Exception { + doNothing().when(mContext).enforceCallingOrSelfPermission( + eq(android.Manifest.permission.RECOVERY), any()); + when(mUncryptSocket.getPercentageUncrypted()).thenReturn(100); + + mRecoverySystemService.rebootRecoveryWithCommand("foo"); + + assertThat(mSystemProperties.getCtlStart(), is("setup-bcb")); + verify(mUncryptSocket).sendCommand("foo"); + verify(mUncryptSocket).sendAck(); + verify(mUncryptSocket).close(); + verify(mIPowerManager).reboot(anyBoolean(), eq("recovery"), anyBoolean()); + } + + @Test + public void rebootRecoveryWithCommand_failure() throws Exception { + doNothing().when(mContext).enforceCallingOrSelfPermission( + eq(android.Manifest.permission.RECOVERY), any()); + when(mUncryptSocket.getPercentageUncrypted()).thenReturn(0); + + mRecoverySystemService.rebootRecoveryWithCommand("foo"); + + assertThat(mSystemProperties.getCtlStart(), is("setup-bcb")); + verify(mUncryptSocket).sendCommand("foo"); + verify(mUncryptSocket).sendAck(); + verify(mUncryptSocket).close(); + verifyNoMoreInteractions(mIPowerManager); + } + + @Test(expected = SecurityException.class) + public void rebootRecoveryWithCommand_noPerm() { + doThrow(SecurityException.class).when(mContext).enforceCallingOrSelfPermission( + eq(android.Manifest.permission.RECOVERY), any()); + mRecoverySystemService.rebootRecoveryWithCommand("foo"); + } + + @Test + public void uncrypt_success() throws Exception { + doNothing().when(mContext).enforceCallingOrSelfPermission( + eq(android.Manifest.permission.RECOVERY), any()); + when(mUncryptSocket.getPercentageUncrypted()).thenReturn(0, 5, 25, 50, 90, 99, 100); + + IRecoverySystemProgressListener listener = mock(IRecoverySystemProgressListener.class); + assertThat(mRecoverySystemService.uncrypt("foo.zip", listener), is(true)); + + assertThat(mSystemProperties.getCtlStart(), is("uncrypt")); + verify(mUncryptSocket, times(7)).getPercentageUncrypted(); + verify(mUncryptSocket).sendAck(); + verify(mUncryptSocket).close(); + } +} diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java new file mode 100644 index 000000000000..a986b71d556f --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2019 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.server.recoverysystem; + +import android.content.Context; +import android.os.PowerManager; + +import java.io.FileWriter; + +public class RecoverySystemServiceTestable extends RecoverySystemService { + private static class MockInjector extends RecoverySystemService.Injector { + private final FakeSystemProperties mSystemProperties; + private final PowerManager mPowerManager; + private final FileWriter mUncryptPackageFileWriter; + private final UncryptSocket mUncryptSocket; + + MockInjector(Context context, FakeSystemProperties systemProperties, + PowerManager powerManager, FileWriter uncryptPackageFileWriter, + UncryptSocket uncryptSocket) { + super(context); + mSystemProperties = systemProperties; + mPowerManager = powerManager; + mUncryptPackageFileWriter = uncryptPackageFileWriter; + mUncryptSocket = uncryptSocket; + } + + @Override + public PowerManager getPowerManager() { + return mPowerManager; + } + + @Override + public String systemPropertiesGet(String key) { + return mSystemProperties.get(key); + } + + @Override + public void systemPropertiesSet(String key, String value) { + mSystemProperties.set(key, value); + } + + @Override + public boolean uncryptPackageFileDelete() { + return true; + } + + @Override + public String getUncryptPackageFileName() { + return "mock-file.txt"; + } + + @Override + public FileWriter getUncryptPackageFileWriter() { + return mUncryptPackageFileWriter; + } + + @Override + public UncryptSocket connectService() { + return mUncryptSocket; + } + + @Override + public void threadSleep(long millis) { + } + } + + RecoverySystemServiceTestable(Context context, FakeSystemProperties systemProperties, + PowerManager powerManager, FileWriter uncryptPackageFileWriter, + UncryptSocket uncryptSocket) { + super(new MockInjector(context, systemProperties, powerManager, uncryptPackageFileWriter, + uncryptSocket)); + } + + public static class FakeSystemProperties { + private String mCtlStart = null; + + public String get(String key) { + if (RecoverySystemService.INIT_SERVICE_UNCRYPT.equals(key) + || RecoverySystemService.INIT_SERVICE_SETUP_BCB.equals(key) + || RecoverySystemService.INIT_SERVICE_CLEAR_BCB.equals(key)) { + return null; + } else { + throw new IllegalArgumentException("unexpected test key: " + key); + } + } + + public void set(String key, String value) { + if ("ctl.start".equals(key)) { + mCtlStart = value; + } else { + throw new IllegalArgumentException("unexpected test key: " + key); + } + } + + public String getCtlStart() { + return mCtlStart; + } + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java index 24db657892df..53368111d151 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java @@ -134,10 +134,9 @@ public class ActivityDisplayTests extends ActivityTestsBase { public void testNotResumeHomeStackOnRemovingDisplay() { // Create a display which supports system decoration and allows reparenting stacks to // another display when the display is removed. - final ActivityDisplay display = createNewActivityDisplay(); + final ActivityDisplay display = new TestActivityDisplay.Builder( + mService, 1000, 1500).setSystemDecorations(true).build(); doReturn(false).when(display).shouldDestroyContentOnRemove(); - doReturn(true).when(display).supportsSystemDecorations(); - mRootActivityContainer.addChild(display, ActivityDisplay.POSITION_TOP); // Put home stack on the display. final ActivityStack homeStack = new StackBuilder(mRootActivityContainer) diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java index 3a6ed5400f61..ba5485904ee6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java @@ -1096,7 +1096,7 @@ public class ActivityStackTests extends ActivityTestsBase { taskTop.finishing = true; final ActivityRecord newR = new ActivityBuilder(mService).build(); - final ActivityRecord result = mStack.resetTaskIfNeededLocked(taskTop, newR); + final ActivityRecord result = mStack.resetTaskIfNeeded(taskTop, newR); assertThat(result).isEqualTo(taskTop); } @@ -1118,7 +1118,7 @@ public class ActivityStackTests extends ActivityTestsBase { r.setState(ActivityStack.ActivityState.INITIALIZING, "test"); // Ensure precondition that the activity is opaque. assertTrue(r.occludesParent()); - mSupervisor.startSpecificActivityLocked(r, false /* andResume */, + mSupervisor.startSpecificActivity(r, false /* andResume */, false /* checkConfig */); } mSupervisor.endDeferResume(); @@ -1145,12 +1145,12 @@ public class ActivityStackTests extends ActivityTestsBase { new ActivityBuilder(mService).setTask(mTask).build(); doReturn(false).when(nonTopVisibleActivity).attachedToProcess(); doReturn(true).when(nonTopVisibleActivity).shouldBeVisible(anyBoolean(), anyBoolean()); - doNothing().when(mSupervisor).startSpecificActivityLocked(any(), anyBoolean(), + doNothing().when(mSupervisor).startSpecificActivity(any(), anyBoolean(), anyBoolean()); - mStack.ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */, + mStack.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, false /* preserveWindows */); - verify(mSupervisor).startSpecificActivityLocked(any(), eq(false) /* andResume */, + verify(mSupervisor).startSpecificActivity(any(), eq(false) /* andResume */, anyBoolean()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 9af90e39da95..ae1bb8e57e56 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -760,8 +760,9 @@ public class ActivityStarterTests extends ActivityTestsBase { false /* mockGetLaunchStack */); // Create a secondary display at bottom. - final TestActivityDisplay secondaryDisplay = createNewActivityDisplay(); - mRootActivityContainer.addChild(secondaryDisplay, POSITION_BOTTOM); + final TestActivityDisplay secondaryDisplay = + new TestActivityDisplay.Builder(mService, 1000, 1500) + .setPosition(POSITION_BOTTOM).build(); final ActivityStack stack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); @@ -798,7 +799,8 @@ public class ActivityStarterTests extends ActivityTestsBase { false /* mockGetLaunchStack */); // Create a secondary display with an activity. - final TestActivityDisplay secondaryDisplay = createNewActivityDisplay(); + final TestActivityDisplay secondaryDisplay = + new TestActivityDisplay.Builder(mService, 1000, 1500).build(); mRootActivityContainer.addChild(secondaryDisplay, POSITION_TOP); final ActivityRecord singleTaskActivity = createSingleTaskActivityOn( secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN, diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java index e9546a2f9769..dae1052286f7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java @@ -26,7 +26,9 @@ import static org.junit.Assert.assertTrue; import android.app.Activity; import android.app.ActivityManager; +import android.content.res.Configuration; import android.graphics.Rect; +import android.view.IDisplayWindowListener; import android.view.WindowContainerTransaction; import androidx.test.filters.MediumTest; @@ -35,6 +37,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.ArrayList; + /** * Tests for the {@link ActivityTaskManagerService} class. * @@ -93,5 +97,56 @@ public class ActivityTaskManagerServiceTests extends ActivityTestsBase { mService.applyContainerTransaction(t); assertEquals(newBounds, stack.getBounds()); } + + @Test + public void testDisplayWindowListener() { + final ArrayList<Integer> added = new ArrayList<>(); + final ArrayList<Integer> changed = new ArrayList<>(); + final ArrayList<Integer> removed = new ArrayList<>(); + IDisplayWindowListener listener = new IDisplayWindowListener.Stub() { + @Override + public void onDisplayAdded(int displayId) { + added.add(displayId); + } + + @Override + public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) { + changed.add(displayId); + } + + @Override + public void onDisplayRemoved(int displayId) { + removed.add(displayId); + } + }; + mService.mWindowManager.registerDisplayWindowListener(listener); + // Check that existing displays call added + assertEquals(1, added.size()); + assertEquals(0, changed.size()); + assertEquals(0, removed.size()); + added.clear(); + // Check adding a display + ActivityDisplay newDisp1 = new TestActivityDisplay.Builder(mService, 600, 800).build(); + assertEquals(1, added.size()); + assertEquals(0, changed.size()); + assertEquals(0, removed.size()); + added.clear(); + // Check that changes are reported + Configuration c = new Configuration(newDisp1.getRequestedOverrideConfiguration()); + c.windowConfiguration.setBounds(new Rect(0, 0, 1000, 1300)); + newDisp1.onRequestedOverrideConfigurationChanged(c); + mService.mRootActivityContainer.ensureVisibilityAndConfig(null /* starting */, + newDisp1.mDisplayId, false /* markFrozenIfConfigChanged */, + false /* deferResume */); + assertEquals(0, added.size()); + assertEquals(1, changed.size()); + assertEquals(0, removed.size()); + changed.clear(); + // Check that removal is reported + newDisp1.remove(); + assertEquals(0, added.size()); + assertEquals(0, changed.size()); + assertEquals(1, removed.size()); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java index 47b39b042fb5..7322ac364e5d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java @@ -43,7 +43,6 @@ import android.content.res.Configuration; import android.os.Build; import android.os.UserHandle; import android.service.voice.IVoiceInteractionSession; -import android.view.DisplayInfo; import com.android.server.AttributeCache; @@ -78,27 +77,9 @@ class ActivityTestsBase extends SystemServiceTestsBase { mRootActivityContainer = mService.mRootActivityContainer; } - /** Creates a {@link TestActivityDisplay}. */ - TestActivityDisplay createNewActivityDisplay() { - return TestActivityDisplay.create(mSupervisor); - } - - TestActivityDisplay createNewActivityDisplay(DisplayInfo info) { - return TestActivityDisplay.create(mSupervisor, info); - } - /** Creates and adds a {@link TestActivityDisplay} to supervisor at the given position. */ TestActivityDisplay addNewActivityDisplayAt(int position) { - final TestActivityDisplay display = createNewActivityDisplay(); - mRootActivityContainer.addChild(display, position); - return display; - } - - /** Creates and adds a {@link TestActivityDisplay} to supervisor at the given position. */ - TestActivityDisplay addNewActivityDisplayAt(DisplayInfo info, int position) { - final TestActivityDisplay display = createNewActivityDisplay(info); - mRootActivityContainer.addChild(display, position); - return display; + return new TestActivityDisplay.Builder(mService, 1000, 1500).setPosition(position).build(); } /** Sets the default minimum task size to 1 so that tests can use small task sizes */ @@ -271,7 +252,7 @@ class ActivityTestsBase extends SystemServiceTestsBase { doReturn(true).when(activity).occludesParent(); mTask.addChild(activity); // Make visible by default... - activity.setHidden(false); + activity.setVisible(true); } final WindowProcessController wpc = new WindowProcessController(mService, diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java index 60204539d178..d415f25baab9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java @@ -62,7 +62,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { final ActivityRecord translucentOpening = createActivityRecord(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); translucentOpening.setOccludesParent(false); - translucentOpening.setHidden(true); + translucentOpening.setVisible(false); mDisplayContent.mOpeningApps.add(behind); mDisplayContent.mOpeningApps.add(translucentOpening); assertEquals(WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN, @@ -90,7 +90,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { final ActivityRecord translucentOpening = createActivityRecord(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); translucentOpening.setOccludesParent(false); - translucentOpening.setHidden(true); + translucentOpening.setVisible(false); mDisplayContent.mOpeningApps.add(behind); mDisplayContent.mOpeningApps.add(translucentOpening); assertEquals(TRANSIT_TASK_CHANGE_WINDOWING_MODE, diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index 1c150969144a..9f3bd75834f4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -252,7 +252,7 @@ public class AppWindowTokenTests extends WindowTestsBase { @Test @Presubmit public void testGetOrientation() { - mActivity.setHidden(false); + mActivity.setVisible(true); mActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); @@ -261,7 +261,7 @@ public class AppWindowTokenTests extends WindowTestsBase { assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mActivity.getOrientation()); mActivity.setOccludesParent(true); - mActivity.setHidden(true); + mActivity.setVisible(false); // Can not specify orientation if app isn't visible even though it occludes parent. assertEquals(SCREEN_ORIENTATION_UNSET, mActivity.getOrientation()); // Can specify orientation if the current orientation candidate is orientation behind. @@ -313,7 +313,7 @@ public class AppWindowTokenTests extends WindowTestsBase { @Test public void testSetOrientation() { - mActivity.setHidden(false); + mActivity.setVisible(true); // Assert orientation is unspecified to start. assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, mActivity.getOrientation()); diff --git a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java index 5fb6f45b400e..56cb447e65b0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java @@ -120,6 +120,23 @@ public class HighRefreshRateBlacklistTest { assertFalse(mBlacklist.isBlacklisted(APP3)); } + @Test + public void testOverriddenByDeviceConfigUnrelatedFlagChanged() { + final Resources r = createResources(APP1); + final FakeDeviceConfig config = new FakeDeviceConfig(); + mBlacklist = new HighRefreshRateBlacklist(r, config); + config.setBlacklist(APP2 + "," + APP3); + assertFalse(mBlacklist.isBlacklisted(APP1)); + assertTrue(mBlacklist.isBlacklisted(APP2)); + assertTrue(mBlacklist.isBlacklisted(APP3)); + + // Change an unrelated flag in our namespace and verify that the blacklist is intact + config.putPropertyAndNotify(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, "someKey", "someValue"); + assertFalse(mBlacklist.isBlacklisted(APP1)); + assertTrue(mBlacklist.isBlacklisted(APP2)); + assertTrue(mBlacklist.isBlacklisted(APP3)); + } + private Resources createResources(String... defaultBlacklist) { Resources r = mock(Resources.class); when(r.getStringArray(R.array.config_highRefreshRateBlacklist)) diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java index 0908f7193352..79ad0c45c01f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java @@ -36,7 +36,6 @@ import android.content.pm.PackageManagerInternal; import android.graphics.Rect; import android.os.UserHandle; import android.platform.test.annotations.Presubmit; -import android.view.DisplayInfo; import androidx.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; @@ -103,11 +102,8 @@ public class LaunchParamsPersisterTests extends ActivityTestsBase { deleteRecursively(mFolder); mDisplayUniqueId = "test:" + Integer.toString(sNextUniqueId++); - final DisplayInfo info = new DisplayInfo(); - mService.mContext.getDisplay().getDisplayInfo(info); - info.uniqueId = mDisplayUniqueId; - mTestDisplay = createNewActivityDisplay(info); - mRootActivityContainer.addChild(mTestDisplay, ActivityDisplay.POSITION_TOP); + mTestDisplay = new TestActivityDisplay.Builder(mService, 1000, 1500) + .setUniqueId(mDisplayUniqueId).build(); when(mRootActivityContainer.getActivityDisplay(eq(mDisplayUniqueId))) .thenReturn(mTestDisplay); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java index 702600402d8e..1abd3662165e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -149,7 +149,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); final ActivityRecord hiddenActivity = createActivityRecord(mDisplayContent, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); - hiddenActivity.setHidden(true); + hiddenActivity.setVisible(false); mDisplayContent.getConfiguration().windowConfiguration.setRotation( mDisplayContent.getRotation()); mController.initialize(ACTIVITY_TYPE_HOME, new SparseBooleanArray(), homeActivity); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java index d48b9d74c002..e67380c23056 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java @@ -200,7 +200,7 @@ public class RecentsAnimationTest extends ActivityTestsBase { startRecentsActivity(); // Recents activity must be restarted, but not be resumed while running recents animation. - verify(mRootActivityContainer.mStackSupervisor).startSpecificActivityLocked( + verify(mRootActivityContainer.mStackSupervisor).startSpecificActivity( eq(recentActivity), eq(false), anyBoolean()); assertThat(recentActivity.getState()).isEqualTo(PAUSED); } diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index 3cc781c2c2b2..e2bdf874c3e6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -35,7 +35,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; -import static com.android.server.wm.ActivityDisplay.POSITION_TOP; import static com.android.server.wm.ActivityStackSupervisor.ON_TOP; import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE; @@ -61,7 +60,6 @@ import android.content.res.Resources; import android.graphics.Rect; import android.platform.test.annotations.Presubmit; import android.util.Pair; -import android.view.DisplayInfo; import androidx.test.filters.MediumTest; @@ -518,9 +516,9 @@ public class RootActivityContainerTests extends ActivityTestsBase { mockResolveSecondaryHomeActivity(); // Create secondary displays. - final TestActivityDisplay secondDisplay = createNewActivityDisplay(); - mRootActivityContainer.addChild(secondDisplay, POSITION_TOP); - doReturn(true).when(secondDisplay).supportsSystemDecorations(); + final TestActivityDisplay secondDisplay = + new TestActivityDisplay.Builder(mService, 1000, 1500) + .setSystemDecorations(true).build(); doReturn(true).when(mRootActivityContainer) .ensureVisibilityAndConfig(any(), anyInt(), anyBoolean(), anyBoolean()); @@ -585,10 +583,10 @@ public class RootActivityContainerTests extends ActivityTestsBase { @Test public void testStartSecondaryHomeOnDisplayWithUserKeyLocked() { // Create secondary displays. - final TestActivityDisplay secondDisplay = createNewActivityDisplay(); - mRootActivityContainer.addChild(secondDisplay, POSITION_TOP); + final TestActivityDisplay secondDisplay = + new TestActivityDisplay.Builder(mService, 1000, 1500) + .setSystemDecorations(true).build(); - doReturn(true).when(secondDisplay).supportsSystemDecorations(); // Use invalid user id to let StorageManager.isUserKeyUnlocked() return false. final int currentUser = mRootActivityContainer.mCurrentUser; mRootActivityContainer.mCurrentUser = -1; @@ -611,9 +609,9 @@ public class RootActivityContainerTests extends ActivityTestsBase { @Test public void testStartSecondaryHomeOnDisplayWithoutSysDecorations() { // Create secondary displays. - final TestActivityDisplay secondDisplay = createNewActivityDisplay(); - mRootActivityContainer.addChild(secondDisplay, POSITION_TOP); - doReturn(false).when(secondDisplay).supportsSystemDecorations(); + final TestActivityDisplay secondDisplay = + new TestActivityDisplay.Builder(mService, 1000, 1500) + .setSystemDecorations(false).build(); mRootActivityContainer.startHomeOnDisplay(0 /* userId */, "testStartSecondaryHome", secondDisplay.mDisplayId, true /* allowInstrumenting */, true /* fromHomeKey */); @@ -834,12 +832,9 @@ public class RootActivityContainerTests extends ActivityTestsBase { @Test public void testGetLaunchStackWithRealCallerId() { // Create a non-system owned virtual display. - final DisplayInfo info = new DisplayInfo(); - mSupervisor.mService.mContext.getDisplay().getDisplayInfo(info); - info.type = TYPE_VIRTUAL; - info.ownerUid = 100; - final TestActivityDisplay secondaryDisplay = TestActivityDisplay.create(mSupervisor, info); - mRootActivityContainer.addChild(secondaryDisplay, POSITION_TOP); + final TestActivityDisplay secondaryDisplay = + new TestActivityDisplay.Builder(mService, 1000, 1500) + .setType(TYPE_VIRTUAL).setOwnerUid(100).build(); // Create an activity with specify the original launch pid / uid. final ActivityRecord r = new ActivityBuilder(mService).setLaunchedFromPid(200) diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java index 15dcbf5468c3..eba2bc899b57 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java @@ -18,7 +18,6 @@ package com.android.server.wm; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; -import static android.view.Display.DEFAULT_DISPLAY; import static com.google.common.truth.Truth.assertThat; @@ -59,13 +58,15 @@ public class RunningTasksTest extends ActivityTestsBase { public void testCollectTasksByLastActiveTime() { // Create a number of stacks with tasks (of incrementing active time) final ArrayList<ActivityDisplay> displays = new ArrayList<>(); - final ActivityDisplay display = TestActivityDisplay.create(mSupervisor, DEFAULT_DISPLAY); + final ActivityDisplay display = + new TestActivityDisplay.Builder(mService, 1000, 2500).build(); displays.add(display); final int numStacks = 2; for (int stackIndex = 0; stackIndex < numStacks; stackIndex++) { final ActivityStack stack = new StackBuilder(mRootActivityContainer) .setCreateActivity(false) + .setDisplay(display) .setOnTop(false) .build(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index b9e1d4b733b3..212931b76b88 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -290,10 +290,12 @@ public class SizeCompatTests extends ActivityTestsBase { public void testFixedScreenLayoutSizeBits() { setUpApp(new TestActivityDisplay.Builder(mService, 1000, 2500).build()); final int fixedScreenLayout = Configuration.SCREENLAYOUT_LONG_NO - | Configuration.SCREENLAYOUT_SIZE_NORMAL; + | Configuration.SCREENLAYOUT_SIZE_NORMAL + | Configuration.SCREENLAYOUT_COMPAT_NEEDED; final int layoutMask = Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK - | Configuration.SCREENLAYOUT_LAYOUTDIR_MASK; + | Configuration.SCREENLAYOUT_LAYOUTDIR_MASK + | Configuration.SCREENLAYOUT_COMPAT_NEEDED; Configuration c = new Configuration(mTask.getRequestedOverrideConfiguration()); c.screenLayout = fixedScreenLayout | Configuration.SCREENLAYOUT_LAYOUTDIR_LTR; mTask.onRequestedOverrideConfigurationChanged(c); diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java index d1b6f6f3f4cf..7e31895aa991 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServiceTestsBase.java @@ -40,6 +40,10 @@ class SystemServiceTestsBase { mLockRule.waitForLocked(mSystemServicesTestRule::waitUntilWindowManagerHandlersIdle); } + void cleanupWindowManagerHandlers() { + mLockRule.waitForLocked(mSystemServicesTestRule::cleanupWindowManagerHandlers); + } + boolean waitHandlerIdle(Handler handler) { return waitHandlerIdle(handler, 0 /* timeout */); } diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java index 2c34f331e965..d3b68e02cbf8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java +++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java @@ -355,6 +355,8 @@ public class SystemServicesTestRule implements TestRule { } wm.mH.removeCallbacksAndMessages(null); wm.mAnimationHandler.removeCallbacksAndMessages(null); + // This is a different handler object than the wm.mAnimationHandler above. + AnimationThread.getHandler().removeCallbacksAndMessages(null); SurfaceAnimationThread.getHandler().removeCallbacksAndMessages(null); } @@ -367,6 +369,8 @@ public class SystemServicesTestRule implements TestRule { wm.mH.removeMessages(WindowManagerService.H.FORCE_GC); waitHandlerIdle(wm.mH); waitHandlerIdle(wm.mAnimationHandler); + // This is a different handler object than the wm.mAnimationHandler above. + waitHandlerIdle(AnimationThread.getHandler()); waitHandlerIdle(SurfaceAnimationThread.getHandler()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java index b07a27b3495c..c8f81f4a84c2 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java @@ -37,7 +37,6 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.policy.WindowManagerPolicy.USER_ROTATION_FREE; import static com.android.server.wm.DisplayRotation.FIXED_TO_USER_ROTATION_ENABLED; -import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.google.common.truth.Truth.assertThat; @@ -266,11 +265,8 @@ public class TaskRecordTests extends ActivityTestsBase { public void testFullscreenBoundsForcedOrientation() { final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080); final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920); - DisplayInfo info = new DisplayInfo(); - mService.mContext.getDisplay().getDisplayInfo(info); - info.logicalWidth = fullScreenBounds.width(); - info.logicalHeight = fullScreenBounds.height(); - ActivityDisplay display = addNewActivityDisplayAt(info, POSITION_TOP); + ActivityDisplay display = new TestActivityDisplay.Builder( + mService, fullScreenBounds.width(), fullScreenBounds.height()).build(); assertTrue(mRootActivityContainer.getActivityDisplay(display.mDisplayId) != null); // Fix the display orientation to landscape which is the natural rotation (0) for the test // display. @@ -332,11 +328,8 @@ public class TaskRecordTests extends ActivityTestsBase { @Test public void testIgnoresForcedOrientationWhenParentHandles() { final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080); - DisplayInfo info = new DisplayInfo(); - mService.mContext.getDisplay().getDisplayInfo(info); - info.logicalWidth = fullScreenBounds.width(); - info.logicalHeight = fullScreenBounds.height(); - ActivityDisplay display = addNewActivityDisplayAt(info, POSITION_TOP); + ActivityDisplay display = new TestActivityDisplay.Builder( + mService, fullScreenBounds.width(), fullScreenBounds.height()).build(); display.getRequestedOverrideConfiguration().orientation = Configuration.ORIENTATION_LANDSCAPE; diff --git a/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java b/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java index 48ec261f88f6..247cd87f98b8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestActivityDisplay.java @@ -17,7 +17,6 @@ package com.android.server.wm; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; -import static android.view.Display.DEFAULT_DISPLAY; import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; @@ -39,36 +38,6 @@ import android.view.DisplayInfo; class TestActivityDisplay extends ActivityDisplay { private final ActivityStackSupervisor mSupervisor; - static TestActivityDisplay create(ActivityStackSupervisor supervisor) { - return create(supervisor, SystemServicesTestRule.sNextDisplayId++); - } - - static TestActivityDisplay create(ActivityStackSupervisor supervisor, DisplayInfo info) { - return create(supervisor, SystemServicesTestRule.sNextDisplayId++, info); - } - - static TestActivityDisplay create(ActivityStackSupervisor supervisor, int displayId) { - final DisplayInfo info = new DisplayInfo(); - supervisor.mService.mContext.getDisplay().getDisplayInfo(info); - return create(supervisor, displayId, info); - } - - static TestActivityDisplay create(ActivityStackSupervisor supervisor, int displayId, - DisplayInfo info) { - if (displayId == DEFAULT_DISPLAY) { - synchronized (supervisor.mService.mGlobalLock) { - return new TestActivityDisplay(supervisor, - supervisor.mRootActivityContainer.mDisplayManager.getDisplay(displayId)); - } - } - final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId, - info, DEFAULT_DISPLAY_ADJUSTMENTS); - - synchronized (supervisor.mService.mGlobalLock) { - return new TestActivityDisplay(supervisor, display); - } - } - private TestActivityDisplay(ActivityStackSupervisor supervisor, Display display) { super(supervisor.mService.mRootActivityContainer, display); // Normally this comes from display-properties as exposed by WM. Without that, just diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java index cc90ca1e2556..4d25a83155fd 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java @@ -18,8 +18,6 @@ package com.android.server.wm; import static android.view.Display.INVALID_DISPLAY; -import static com.android.server.wm.ActivityDisplay.POSITION_TOP; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -132,8 +130,6 @@ public class WindowProcessControllerTests extends ActivityTestsBase { } private TestActivityDisplay createTestActivityDisplayInContainer() { - final TestActivityDisplay testActivityDisplay = createNewActivityDisplay(); - mRootActivityContainer.addChild(testActivityDisplay, POSITION_TOP); - return testActivityDisplay; + return new TestActivityDisplay.Builder(mService, 1000, 1500).build(); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 8af47bc437c7..eed5ef52c8e1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -383,11 +383,11 @@ public class WindowStateTests extends WindowTestsBase { @Test public void testCanAffectSystemUiFlags() { final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); - app.mToken.setHidden(false); + app.mActivityRecord.setVisible(true); assertTrue(app.canAffectSystemUiFlags()); - app.mToken.setHidden(true); + app.mActivityRecord.setVisible(false); assertFalse(app.canAffectSystemUiFlags()); - app.mToken.setHidden(false); + app.mActivityRecord.setVisible(true); app.mAttrs.alpha = 0.0f; assertFalse(app.canAffectSystemUiFlags()); } @@ -395,7 +395,7 @@ public class WindowStateTests extends WindowTestsBase { @Test public void testCanAffectSystemUiFlags_disallow() { final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); - app.mToken.setHidden(false); + app.mActivityRecord.setVisible(true); assertTrue(app.canAffectSystemUiFlags()); app.getTask().setCanAffectSystemUiFlags(false); assertFalse(app.canAffectSystemUiFlags()); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java index 34a2369c67b3..26743c842122 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java @@ -74,7 +74,7 @@ class WindowTestUtils { private static void postCreateActivitySetup(ActivityRecord activity, DisplayContent dc) { activity.onDisplayChanged(dc); activity.setOccludesParent(true); - activity.setHidden(false); + activity.setVisible(true); activity.mVisibleRequested = true; } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 0da9dc40bb4d..437b84b42dae 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -36,8 +36,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; -import static com.android.server.wm.ActivityDisplay.POSITION_TOP; - import static org.mockito.Mockito.mock; import android.content.Context; @@ -175,7 +173,7 @@ class WindowTestsBase extends SystemServiceTestsBase { } // Cleaned up everything in Handler. - mSystemServicesTestRule.cleanupWindowManagerHandlers(); + cleanupWindowManagerHandlers(); } catch (Exception e) { Log.e(TAG, "Failed to tear down test", e); throw e; @@ -343,8 +341,7 @@ class WindowTestsBase extends SystemServiceTestsBase { /** Creates a {@link DisplayContent} and adds it to the system. */ DisplayContent createNewDisplay(DisplayInfo info) { final ActivityDisplay display = - TestActivityDisplay.create(mWm.mAtmService.mStackSupervisor, info); - mWm.mAtmService.mRootActivityContainer.addChild(display, POSITION_TOP); + new TestActivityDisplay.Builder(mWm.mAtmService, info).build(); return display.mDisplayContent; } diff --git a/services/usage/Android.bp b/services/usage/Android.bp index 1064b6ed802f..156bf330c128 100644 --- a/services/usage/Android.bp +++ b/services/usage/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.usage-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.usage", - srcs: ["java/**/*.java"], + srcs: [":services.usage-sources"], libs: ["services.core"], } diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index f9b365906c5b..63b062e91c98 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -347,7 +347,7 @@ public class UsageStatsService extends SystemService implements Slog.i(TAG, "Attempted to unlock stopped or removed user " + userId); return; } - userService.userUnlocked(System.currentTimeMillis()); + // Process all the pending reported events while (pendingEvents.peek() != null) { reportEvent(pendingEvents.poll(), userId); @@ -466,6 +466,7 @@ public class UsageStatsService extends SystemService implements if (mUserUnlockedStates.get(userId)) { try { service.init(currentTimeMillis); + mUserState.put(userId, service); } catch (Exception e) { if (mUserManager.isUserUnlocked(userId)) { throw e; // rethrow exception - user is unlocked @@ -476,7 +477,6 @@ public class UsageStatsService extends SystemService implements } } } - mUserState.put(userId, service); } return service; } diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java index 5783932db488..c6a5fcfa8d2c 100644 --- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java @@ -165,10 +165,6 @@ class UserUsageStatsService { } } - void userUnlocked(long currentTimeMillis) { - init(currentTimeMillis); - } - void userStopped() { // Flush events to disk immediately to guarantee persistence. persistActiveStats(); diff --git a/services/usb/Android.bp b/services/usb/Android.bp index 20855b70cabc..d2c973abbc74 100644 --- a/services/usb/Android.bp +++ b/services/usb/Android.bp @@ -1,6 +1,13 @@ +filegroup { + name: "services.usb-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.usb", - srcs: ["java/**/*.java"], + srcs: [":services.usb-sources"], libs: [ "services.core", diff --git a/services/voiceinteraction/Android.bp b/services/voiceinteraction/Android.bp index 390406f97264..85b96f34f4f6 100644 --- a/services/voiceinteraction/Android.bp +++ b/services/voiceinteraction/Android.bp @@ -1,5 +1,12 @@ +filegroup { + name: "services.voiceinteraction-sources", + srcs: ["java/**/*.java"], + path: "java", + visibility: ["//frameworks/base/services"], +} + java_library_static { name: "services.voiceinteraction", - srcs: ["java/**/*.java"], + srcs: [":services.voiceinteraction-sources"], libs: ["services.core"], } diff --git a/services/wifi/Android.bp b/services/wifi/Android.bp index 608fc2c7a55e..8a7f73fcf501 100644 --- a/services/wifi/Android.bp +++ b/services/wifi/Android.bp @@ -1,14 +1,16 @@ -// Interfaces between the core system and the wifi mainline module. -java_library_static { - name: "services.wifi", +filegroup { + name: "services.wifi-sources", srcs: [ "java/**/*.java", "java/**/*.aidl", ], - aidl: { - local_include_dirs: ["java"] - }, - libs: [ - "services.net", - ], + path: "java", + visibility: ["//frameworks/base/services"], +} + +// Interfaces between the core system and the wifi mainline module. +java_library_static { + name: "services.wifi", + srcs: [":services.wifi-sources"], + libs: ["services.net"], } diff --git a/startop/iorap/Android.bp b/startop/iorap/Android.bp index 59a80fbae792..993d1e1092b9 100644 --- a/startop/iorap/Android.bp +++ b/startop/iorap/Android.bp @@ -12,19 +12,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -java_library_static { - name: "services.startop.iorap", - - aidl: { - include_dirs: [ - "system/iorap/binder", - ], - }, - - libs: ["services.core"], +filegroup { + name: "services.startop.iorap-javasources", + srcs: ["src/**/*.java"], + path: "src", + visibility: ["//visibility:private"], +} +filegroup { + name: "services.startop.iorap-sources", srcs: [ - ":iorap-aidl", - "**/*.java", + ":services.startop.iorap-javasources", + ":iorap-aidl", ], + visibility: ["//frameworks/base/services:__subpackages__"], +} + +java_library_static { + name: "services.startop.iorap", + srcs: [":services.startop.iorap-sources"], + libs: ["services.core"], } diff --git a/telephony/java/com/android/internal/telephony/SmsConstants.java b/telephony/common/com/android/internal/telephony/SmsConstants.java index 19f52b0ef429..19f52b0ef429 100644 --- a/telephony/java/com/android/internal/telephony/SmsConstants.java +++ b/telephony/common/com/android/internal/telephony/SmsConstants.java diff --git a/telephony/common/com/android/internal/telephony/SmsNumberUtils.java b/telephony/common/com/android/internal/telephony/SmsNumberUtils.java index 0d33af639113..367aad1837ce 100644 --- a/telephony/common/com/android/internal/telephony/SmsNumberUtils.java +++ b/telephony/common/com/android/internal/telephony/SmsNumberUtils.java @@ -359,15 +359,41 @@ public class SmsNumberUtils { return NP_NONE; } + /** + * This function checks if the passed in string conforms to the NANP format + * i.e. NXX-NXX-XXXX, N is any digit 2-9 and X is any digit 0-9 + */ private static boolean isNANP(String number) { + boolean retVal = false; + if (number.length() == NANP_MEDIUM_LENGTH || (number.length() == NANP_LONG_LENGTH && number.startsWith(NANP_NDD))) { + if (number.length() == NANP_LONG_LENGTH) { number = number.substring(1); } - return (PhoneNumberUtils.isNanp(number)); + + if (isTwoToNine(number.charAt(0)) && + isTwoToNine(number.charAt(3))) { + retVal = true; + for (int i=1; i<NANP_MEDIUM_LENGTH; i++ ) { + char c=number.charAt(i); + if (!PhoneNumberUtils.isISODigit(c)) { + retVal = false; + break; + } + } + } + } + return retVal; + } + + private static boolean isTwoToNine (char c) { + if (c >= '2' && c <= '9') { + return true; + } else { + return false; } - return false; } /** @@ -573,9 +599,9 @@ public class SmsNumberUtils { int networkType = -1; int phoneType = telephonyManager.getPhoneType(); - if (phoneType == PhoneConstants.PHONE_TYPE_GSM) { + if (phoneType == TelephonyManager.PHONE_TYPE_GSM) { networkType = GSM_UMTS_NETWORK; - } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) { + } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) { if (isInternationalRoaming(telephonyManager)) { networkType = CDMA_ROAMING_NETWORK; } else { diff --git a/telephony/common/com/google/android/mms/pdu/PduPersister.java b/telephony/common/com/google/android/mms/pdu/PduPersister.java index 95ae4096ed86..b237705274da 100755 --- a/telephony/common/com/google/android/mms/pdu/PduPersister.java +++ b/telephony/common/com/google/android/mms/pdu/PduPersister.java @@ -291,15 +291,11 @@ public class PduPersister { @UnsupportedAppUsage private final ContentResolver mContentResolver; private final DrmManagerClient mDrmManagerClient; - @UnsupportedAppUsage - private final TelephonyManager mTelephonyManager; private PduPersister(Context context) { mContext = context; mContentResolver = context.getContentResolver(); mDrmManagerClient = new DrmManagerClient(context); - mTelephonyManager = (TelephonyManager)context - .getSystemService(Context.TELEPHONY_SERVICE); } /** Get(or create if not exist) an instance of PduPersister */ @@ -1453,7 +1449,8 @@ public class PduPersister { if (excludeMyNumber) { // Build a list of my phone numbers from the various sims. for (int subid : subscriptionManager.getActiveSubscriptionIdList()) { - final String myNumber = mTelephonyManager.getLine1Number(subid); + final String myNumber = mContext.getSystemService(TelephonyManager.class). + createForSubscriptionId(subid).getLine1Number(); if (myNumber != null) { myPhoneNumbers.add(myNumber); } diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java index 15bb00265b11..add03160bbe9 100644 --- a/telephony/java/android/provider/Telephony.java +++ b/telephony/java/android/provider/Telephony.java @@ -4090,9 +4090,7 @@ public final class Telephony { /** * The subscription which received this cell broadcast message. - * @deprecated use {@link #SLOT_INDEX} instead. * <P>Type: INTEGER</P> - * @hide */ public static final String SUB_ID = "sub_id"; @@ -4366,6 +4364,7 @@ public final class Telephony { public static final String[] QUERY_COLUMNS_FWK = { _ID, SLOT_INDEX, + SUB_ID, GEOGRAPHICAL_SCOPE, PLMN, LAC, diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index f94c8e39cb17..479b1442c788 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -1701,7 +1701,6 @@ public class CarrierConfigManager { /** * Determines whether the carrier app needed to be involved when users try to finish setting up * the SIM card to get network service. - * @hide */ public static final String KEY_CARRIER_APP_REQUIRED_DURING_SIM_SETUP_BOOL = "carrier_app_required_during_setup_bool"; diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java index 6df60ba0ca32..edc838c163db 100644 --- a/telephony/java/android/telephony/CellIdentityNr.java +++ b/telephony/java/android/telephony/CellIdentityNr.java @@ -62,6 +62,12 @@ public final class CellIdentityNr extends CellIdentity { } /** @hide */ + public CellIdentityNr(android.hardware.radio.V1_4.CellIdentityNr cid) { + this(cid.pci, cid.tac, cid.nrarfcn, cid.mcc, cid.mnc, cid.nci, cid.operatorNames.alphaLong, + cid.operatorNames.alphaShort); + } + + /** @hide */ public CellIdentityNr sanitizeLocationInfo() { return new CellIdentityNr(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mMccStr, mMncStr, CellInfo.UNAVAILABLE, mAlphaLong, mAlphaShort); diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java index 18687d400faf..ae45307f19f0 100644 --- a/telephony/java/android/telephony/CellInfo.java +++ b/telephony/java/android/telephony/CellInfo.java @@ -374,6 +374,7 @@ public abstract class CellInfo implements Parcelable { case Info.hidl_discriminator.lte: return new CellInfoLte(ci, timeStamp); case Info.hidl_discriminator.wcdma: return new CellInfoWcdma(ci, timeStamp); case Info.hidl_discriminator.tdscdma: return new CellInfoTdscdma(ci, timeStamp); + case Info.hidl_discriminator.nr: return new CellInfoNr(ci, timeStamp); default: return null; } } diff --git a/telephony/java/android/telephony/CellInfoNr.java b/telephony/java/android/telephony/CellInfoNr.java index cea83230391d..8b41b8be7137 100644 --- a/telephony/java/android/telephony/CellInfoNr.java +++ b/telephony/java/android/telephony/CellInfoNr.java @@ -45,6 +45,14 @@ public final class CellInfoNr extends CellInfo { mCellSignalStrength = other.mCellSignalStrength; } + /** @hide */ + public CellInfoNr(android.hardware.radio.V1_4.CellInfo ci, long timeStamp) { + super(ci, timeStamp); + final android.hardware.radio.V1_4.CellInfoNr cil = ci.info.nr(); + mCellIdentity = new CellIdentityNr(cil.cellidentity); + mCellSignalStrength = new CellSignalStrengthNr(cil.signalStrength); + } + /** * @return a {@link CellIdentityNr} instance. */ diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java index d105fe3ddc71..16fbae25199b 100644 --- a/telephony/java/android/telephony/ModemActivityInfo.java +++ b/telephony/java/android/telephony/ModemActivityInfo.java @@ -17,6 +17,7 @@ package android.telephony; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -59,7 +60,7 @@ public final class ModemActivityInfo implements Parcelable { private int mRxTimeMs; public ModemActivityInfo(long timestamp, int sleepTimeMs, int idleTimeMs, - @NonNull int[] txTimeMs, int rxTimeMs) { + @Nullable int[] txTimeMs, int rxTimeMs) { mTimestamp = timestamp; mSleepTimeMs = sleepTimeMs; mIdleTimeMs = idleTimeMs; @@ -68,10 +69,13 @@ public final class ModemActivityInfo implements Parcelable { } /** helper API to populate tx power range for each bucket **/ - private void populateTransmitPowerRange(@NonNull int[] transmitPowerMs) { + private void populateTransmitPowerRange(@Nullable int[] transmitPowerMs) { int i = 0; - for ( ; i < Math.min(transmitPowerMs.length, TX_POWER_LEVELS); i++) { - mTransmitPowerInfo.add(i, new TransmitPower(TX_POWER_RANGES[i], transmitPowerMs[i])); + if (transmitPowerMs != null) { + for ( ; i < Math.min(transmitPowerMs.length, TX_POWER_LEVELS); i++) { + mTransmitPowerInfo.add(i, + new TransmitPower(TX_POWER_RANGES[i], transmitPowerMs[i])); + } } // Make sure that mTransmitPowerInfo is fully initialized. for ( ; i < TX_POWER_LEVELS; i++) { @@ -94,7 +98,7 @@ public final class ModemActivityInfo implements Parcelable { return 0; } - public static final @android.annotation.NonNull Parcelable.Creator<ModemActivityInfo> CREATOR = + public static final @NonNull Parcelable.Creator<ModemActivityInfo> CREATOR = new Parcelable.Creator<ModemActivityInfo>() { public ModemActivityInfo createFromParcel(Parcel in) { long timestamp = in.readLong(); @@ -149,7 +153,7 @@ public final class ModemActivityInfo implements Parcelable { } /** @hide */ - public void setTransmitTimeMillis(int[] txTimeMs) { + public void setTransmitTimeMillis(@Nullable int[] txTimeMs) { populateTransmitPowerRange(txTimeMs); } diff --git a/telephony/java/android/telephony/SmsCbMessage.java b/telephony/java/android/telephony/SmsCbMessage.java index 737ead1f8131..fad70d2da8be 100644 --- a/telephony/java/android/telephony/SmsCbMessage.java +++ b/telephony/java/android/telephony/SmsCbMessage.java @@ -205,7 +205,9 @@ public final class SmsCbMessage implements Parcelable { /** CMAS warning area coordinates. */ private final List<Geometry> mGeometries; - private int mSlotIndex = 0; + private final int mSlotIndex; + + private final int mSubId; /** * Create a new SmsCbMessage with the specified data. @@ -214,11 +216,11 @@ public final class SmsCbMessage implements Parcelable { public SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber, @NonNull SmsCbLocation location, int serviceCategory, @Nullable String language, @Nullable String body, int priority, @Nullable SmsCbEtwsInfo etwsWarningInfo, - @Nullable SmsCbCmasInfo cmasWarningInfo, int slotIndex) { + @Nullable SmsCbCmasInfo cmasWarningInfo, int slotIndex, int subId) { this(messageFormat, geographicalScope, serialNumber, location, serviceCategory, language, body, priority, etwsWarningInfo, cmasWarningInfo, 0 /* maximumWaitingTime */, - null /* geometries */, System.currentTimeMillis(), slotIndex); + null /* geometries */, System.currentTimeMillis(), slotIndex, subId); } /** @@ -226,10 +228,12 @@ public final class SmsCbMessage implements Parcelable { * coordinates information. */ public SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber, - @NonNull SmsCbLocation location, int serviceCategory, @Nullable String language, - @Nullable String body, int priority, @Nullable SmsCbEtwsInfo etwsWarningInfo, - @Nullable SmsCbCmasInfo cmasWarningInfo, int maximumWaitTimeSec, - @Nullable List<Geometry> geometries, long receivedTimeMillis, int slotIndex) { + @NonNull SmsCbLocation location, int serviceCategory, + @Nullable String language, @Nullable String body, int priority, + @Nullable SmsCbEtwsInfo etwsWarningInfo, + @Nullable SmsCbCmasInfo cmasWarningInfo, int maximumWaitTimeSec, + @Nullable List<Geometry> geometries, long receivedTimeMillis, int slotIndex, + int subId) { mMessageFormat = messageFormat; mGeographicalScope = geographicalScope; mSerialNumber = serialNumber; @@ -244,6 +248,7 @@ public final class SmsCbMessage implements Parcelable { mGeometries = geometries; mMaximumWaitTimeSec = maximumWaitTimeSec; mSlotIndex = slotIndex; + mSubId = subId; } /** @@ -282,6 +287,7 @@ public final class SmsCbMessage implements Parcelable { mGeometries = geoStr != null ? CbGeoUtils.parseGeometriesFromString(geoStr) : null; mMaximumWaitTimeSec = in.readInt(); mSlotIndex = in.readInt(); + mSubId = in.readInt(); } /** @@ -317,6 +323,7 @@ public final class SmsCbMessage implements Parcelable { mGeometries != null ? CbGeoUtils.encodeGeometriesToString(mGeometries) : null); dest.writeInt(mMaximumWaitTimeSec); dest.writeInt(mSlotIndex); + dest.writeInt(mSubId); } @NonNull @@ -427,14 +434,22 @@ public final class SmsCbMessage implements Parcelable { } /** - * Get the slotIndex associated with this message. - * @return the slotIndex associated with this message + * Get the slot index associated with this message. + * @return the slot index associated with this message */ public int getSlotIndex() { return mSlotIndex; } /** + * Get the subscription id associated with this message. + * @return the subscription id associated with this message + */ + public int getSubscriptionId() { + return mSubId; + } + + /** * Get the message format ({@link #MESSAGE_FORMAT_3GPP} or {@link #MESSAGE_FORMAT_3GPP2}). * @return an integer representing 3GPP or 3GPP2 message format */ @@ -536,6 +551,7 @@ public final class SmsCbMessage implements Parcelable { public ContentValues getContentValues() { ContentValues cv = new ContentValues(16); cv.put(CellBroadcasts.SLOT_INDEX, mSlotIndex); + cv.put(CellBroadcasts.SUB_ID, mSubId); cv.put(CellBroadcasts.GEOGRAPHICAL_SCOPE, mGeographicalScope); if (mLocation.getPlmn() != null) { cv.put(CellBroadcasts.PLMN, mLocation.getPlmn()); @@ -577,7 +593,6 @@ public final class SmsCbMessage implements Parcelable { } cv.put(CellBroadcasts.MAXIMUM_WAIT_TIME, mMaximumWaitTimeSec); - cv.put(CellBroadcasts.SLOT_INDEX, mSlotIndex); return cv; } @@ -600,6 +615,7 @@ public final class SmsCbMessage implements Parcelable { int format = cursor.getInt(cursor.getColumnIndexOrThrow(CellBroadcasts.MESSAGE_FORMAT)); int priority = cursor.getInt(cursor.getColumnIndexOrThrow(CellBroadcasts.MESSAGE_PRIORITY)); int slotIndex = cursor.getInt(cursor.getColumnIndexOrThrow(CellBroadcasts.SLOT_INDEX)); + int subId = cursor.getInt(cursor.getColumnIndexOrThrow(CellBroadcasts.SUB_ID)); String plmn; int plmnColumn = cursor.getColumnIndex(CellBroadcasts.PLMN); @@ -697,7 +713,7 @@ public final class SmsCbMessage implements Parcelable { return new SmsCbMessage(format, geoScope, serialNum, location, category, language, body, priority, etwsInfo, cmasInfo, maximumWaitTimeSec, geometries, - receivedTimeMillis, slotIndex); + receivedTimeMillis, slotIndex, subId); } /** diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 1357e9c8e207..9f8a213600da 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -7747,20 +7747,20 @@ public class TelephonyManager { * {@link CarrierConfigManager#KEY_EMERGENCY_SMS_MODE_TIMER_MS_INT}. If * the carrier does not support this mode, this function will always return false. * - * @return true if this device is in emergency SMS mode, false otherwise. + * @return {@code true} if this device is in emergency SMS mode, {@code false} otherwise. * * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isInEmergencySmsMode() { - try { ITelephony telephony = getITelephony(); if (telephony != null) { return telephony.isInEmergencySmsMode(); } } catch (RemoteException ex) { - Rlog.e(TAG, "getNetworkSelectionMode RemoteException", ex); + Rlog.e(TAG, "isInEmergencySmsMode RemoteException", ex); } return false; } @@ -8988,7 +8988,10 @@ public class TelephonyManager { @Deprecated public boolean isTtyModeSupported() { try { - TelecomManager telecomManager = TelecomManager.from(mContext); + TelecomManager telecomManager = null; + if (mContext != null) { + telecomManager = mContext.getSystemService(TelecomManager.class); + } if (telecomManager != null) { return telecomManager.isTtySupported(); } @@ -11088,14 +11091,66 @@ public class TelephonyManager { } /** - * Broadcast intent action for Ota emergency number database installation complete. + * Indicates Emergency number database version is invalid. * * @hide */ - @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @TestApi + @SystemApi + public static final int INVALID_EMERGENCY_NUMBER_DB_VERSION = -1; + + /** + * Notify Telephony for OTA emergency number database installation complete. + * + * <p> Requires permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @SystemApi - public static final String ACTION_OTA_EMERGENCY_NUMBER_DB_INSTALLED = - "android.telephony.action.OTA_EMERGENCY_NUMBER_DB_INSTALLED"; + public void notifyOtaEmergencyNumberDbInstalled() { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + telephony.notifyOtaEmergencyNumberDbInstalled(); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + Log.e(TAG, "notifyOtaEmergencyNumberDatabaseInstalled RemoteException", ex); + ex.rethrowAsRuntimeException(); + } + } + + /** + * Override the file path for testing OTA emergency number database in a file partition. + * + * @param otaFilePath The test OTA emergency number database file path; + * if "RESET", recover the original database file partition. + * Format: <root file folder>@<file path> + * + * <p> Requires permission: + * {@link android.Manifest.permission#READ_ACTIVE_EMERGENCY_SESSION} + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) + @SystemApi + @TestApi + public void updateTestOtaEmergencyNumberDbFilePath(@NonNull String otaFilePath) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + telephony.updateTestOtaEmergencyNumberDbFilePath(otaFilePath); + } else { + throw new IllegalStateException("telephony service is null."); + } + } catch (RemoteException ex) { + Log.e(TAG, "notifyOtaEmergencyNumberDatabaseInstalled RemoteException", ex); + ex.rethrowAsRuntimeException(); + } + } /** * Returns whether {@link TelephonyManager#ACTION_EMERGENCY_ASSISTANCE emergency assistance} is @@ -11293,6 +11348,29 @@ public class TelephonyManager { return false; } + /** + * A test API to return the emergency number db version. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE} + * + * @hide + */ + @TestApi + @SystemApi + public int getEmergencyNumberDbVersion() { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.getEmergencyNumberDbVersion(getSubId()); + } + } catch (RemoteException ex) { + Log.e(TAG, "getEmergencyNumberDbVersion RemoteException", ex); + ex.rethrowAsRuntimeException(); + } + return INVALID_EMERGENCY_NUMBER_DB_VERSION; + } + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"SET_OPPORTUNISTIC_SUB"}, value = { diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index e895baecab73..0ec54ecf56df 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -2048,6 +2048,21 @@ interface ITelephony { List<String> getEmergencyNumberListTestMode(); /** + * A test API to return the emergency number db version. + */ + int getEmergencyNumberDbVersion(int subId); + + /** + * Notify Telephony for OTA emergency number database installation complete. + */ + void notifyOtaEmergencyNumberDbInstalled(); + + /** + * Override the file partition name for testing OTA emergency number database. + */ + void updateTestOtaEmergencyNumberDbFilePath(String otaFilePath); + + /** * Enable or disable a logical modem stack associated with the slotIndex. */ boolean enableModemForSlot(int slotIndex, boolean enable); diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java index f0687b4ae7be..a3efb75b2ee8 100644 --- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java +++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java @@ -20,7 +20,6 @@ import android.annotation.UnsupportedAppUsage; import android.os.Build; import android.provider.Telephony; import android.telephony.SmsMessage; -import android.text.Emoji; import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; @@ -403,9 +402,9 @@ public abstract class SmsMessageBase { if (!breakIterator.isBoundary(nextPos)) { int breakPos = breakIterator.preceding(nextPos); while (breakPos + 4 <= nextPos - && Emoji.isRegionalIndicatorSymbol( + && isRegionalIndicatorSymbol( Character.codePointAt(msgBody, breakPos)) - && Emoji.isRegionalIndicatorSymbol( + && isRegionalIndicatorSymbol( Character.codePointAt(msgBody, breakPos + 2))) { // skip forward over flags (pairs of Regional Indicator Symbol) breakPos += 4; @@ -421,6 +420,11 @@ public abstract class SmsMessageBase { return nextPos; } + private static boolean isRegionalIndicatorSymbol(int codePoint) { + /** Based on http://unicode.org/Public/emoji/3.0/emoji-sequences.txt */ + return 0x1F1E6 <= codePoint && codePoint <= 0x1F1FF; + } + /** * Calculate the TextEncodingDetails of a message encoded in Unicode. */ diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java index 6fc0228a12e4..1f7715b59aff 100644 --- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java +++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java @@ -875,9 +875,10 @@ public class SmsMessage extends SmsMessageBase { * Parses a broadcast SMS, possibly containing a CMAS alert. * * @param plmn the PLMN for a broadcast SMS - * @param subId + * @param slotIndex SIM slot index + * @param subId Subscription id */ - public SmsCbMessage parseBroadcastSms(String plmn, int subId) { + public SmsCbMessage parseBroadcastSms(String plmn, int slotIndex, int subId) { BearerData bData = BearerData.decode(mEnvelope.bearerData, mEnvelope.serviceCategory); if (bData == null) { Rlog.w(LOG_TAG, "BearerData.decode() returned null"); @@ -893,7 +894,7 @@ public class SmsMessage extends SmsMessageBase { return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP2, SmsCbMessage.GEOGRAPHICAL_SCOPE_PLMN_WIDE, bData.messageId, location, mEnvelope.serviceCategory, bData.getLanguage(), bData.userData.payloadStr, - bData.priority, null, bData.cmasWarningInfo, subId); + bData.priority, null, bData.cmasWarningInfo, slotIndex, subId); } /** diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java index d03419d22150..c16eafb41dde 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java @@ -33,6 +33,7 @@ import android.telephony.CbGeoUtils.Polygon; import android.telephony.Rlog; import android.telephony.SmsCbLocation; import android.telephony.SmsCbMessage; +import android.telephony.SubscriptionManager; import android.util.Pair; import com.android.internal.R; @@ -95,6 +96,14 @@ public class GsmSmsCbMessage { public static SmsCbMessage createSmsCbMessage(Context context, SmsCbHeader header, SmsCbLocation location, byte[][] pdus, int slotIndex) throws IllegalArgumentException { + SubscriptionManager sm = (SubscriptionManager) context.getSystemService( + Context.TELEPHONY_SUBSCRIPTION_SERVICE); + int subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; + int[] subIds = sm.getSubscriptionIds(slotIndex); + if (subIds != null && subIds.length > 0) { + subId = subIds[0]; + } + long receivedTimeMillis = System.currentTimeMillis(); if (header.isEtwsPrimaryNotification()) { // ETSI TS 23.041 ETWS Primary Notification message @@ -105,7 +114,8 @@ public class GsmSmsCbMessage { header.getSerialNumber(), location, header.getServiceCategory(), null, getEtwsPrimaryMessage(context, header.getEtwsInfo().getWarningType()), SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY, header.getEtwsInfo(), - header.getCmasInfo(), 0, null /* geometries */, receivedTimeMillis, slotIndex); + header.getCmasInfo(), 0, null /* geometries */, receivedTimeMillis, slotIndex, + subId); } else if (header.isUmtsFormat()) { // UMTS format has only 1 PDU byte[] pdu = pdus[0]; @@ -139,7 +149,7 @@ public class GsmSmsCbMessage { header.getGeographicalScope(), header.getSerialNumber(), location, header.getServiceCategory(), language, body, priority, header.getEtwsInfo(), header.getCmasInfo(), maximumWaitingTimeSec, geometries, - receivedTimeMillis, slotIndex); + receivedTimeMillis, slotIndex, subId); } else { String language = null; StringBuilder sb = new StringBuilder(); @@ -155,7 +165,7 @@ public class GsmSmsCbMessage { header.getGeographicalScope(), header.getSerialNumber(), location, header.getServiceCategory(), language, sb.toString(), priority, header.getEtwsInfo(), header.getCmasInfo(), 0, null /* geometries */, - receivedTimeMillis, slotIndex); + receivedTimeMillis, slotIndex, subId); } } diff --git a/tests/ApkVerityTest/block_device_writer/Android.bp b/tests/ApkVerityTest/block_device_writer/Android.bp index deed3a00d2fe..e7a63e414172 100644 --- a/tests/ApkVerityTest/block_device_writer/Android.bp +++ b/tests/ApkVerityTest/block_device_writer/Android.bp @@ -22,7 +22,13 @@ cc_test { stem: "block_device_writer", srcs: ["block_device_writer.cpp"], - cflags: ["-Wall", "-Werror", "-Wextra", "-g"], + cflags: [ + "-D_FILE_OFFSET_BITS=64", + "-Wall", + "-Werror", + "-Wextra", + "-g", + ], shared_libs: ["libbase", "libutils"], test_suites: ["general-tests"], diff --git a/tests/BackgroundDexOptServiceIntegrationTests/AndroidManifest.xml b/tests/BackgroundDexOptServiceIntegrationTests/AndroidManifest.xml index 7291dc729541..aec9f77cf922 100644 --- a/tests/BackgroundDexOptServiceIntegrationTests/AndroidManifest.xml +++ b/tests/BackgroundDexOptServiceIntegrationTests/AndroidManifest.xml @@ -28,8 +28,6 @@ <uses-permission android:name="android.permission.SET_TIME" /> <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> - <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" /> - <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" /> <application> <uses-library android:name="android.test.runner" /> diff --git a/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java b/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java index 4cd56c3c42be..7d826f7172da 100644 --- a/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java +++ b/tests/BackgroundDexOptServiceIntegrationTests/src/com/android/server/pm/BackgroundDexOptServiceIntegrationTests.java @@ -22,7 +22,6 @@ import android.os.Environment; import android.os.ParcelFileDescriptor; import android.os.SystemProperties; import android.os.storage.StorageManager; -import android.provider.DeviceConfig; import android.util.Log; import androidx.test.InstrumentationRegistry; @@ -31,9 +30,7 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -55,13 +52,6 @@ import java.util.concurrent.TimeUnit; * 3. Under low storage conditions and package is recently used, check * that dexopt upgrades test app to $(getprop pm.dexopt.bg-dexopt). * - * When downgrade feature is on (downgrade_unused_apps_enabled flag is set to true): - * 4 On low storage, check that the inactive packages are downgraded. - * 5. On low storage, check that used packages are upgraded. - * 6. On storage completely full, dexopt fails. - * 7. Not on low storage, unused packages are upgraded. - * 8. Low storage, unused app is downgraded. When app is used again, app is upgraded. - * * Each test case runs "cmd package bg-dexopt-job com.android.frameworks.bgdexopttest". * * The setup for these tests make sure this package has been configured to have been recently used @@ -69,10 +59,6 @@ import java.util.concurrent.TimeUnit; * recently used, it sets the time forward more than * `getprop pm.dexopt.downgrade_after_inactive_days` days. * - * For some of the tests, the DeviceConfig flags inactive_app_threshold_days and - * downgrade_unused_apps_enabled are set. These turn on/off the downgrade unused apps feature for - * all devices and set the time threshold for unused apps. - * * For tests that require low storage, the phone is filled up. * * Run with "atest BackgroundDexOptServiceIntegrationTests". @@ -94,14 +80,10 @@ public final class BackgroundDexOptServiceIntegrationTests { "pm.dexopt.downgrade_after_inactive_days", 0); // Needs to be between 1.0 and 2.0. private static final double LOW_STORAGE_MULTIPLIER = 1.5; - private static final int DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS = 15; // The file used to fill up storage. private File mBigFile; - @Rule - public ExpectedException mExpectedException = ExpectedException.none(); - // Remember start time. @BeforeClass public static void setUpAll() { @@ -214,27 +196,11 @@ public final class BackgroundDexOptServiceIntegrationTests { logSpaceRemaining(); } - private void fillUpStorageCompletely() throws IOException { - fillUpStorage((getStorageLowBytes())); - } - // Fill up storage so that device is in low storage condition. private void fillUpToLowStorage() throws IOException { fillUpStorage((long) (getStorageLowBytes() * LOW_STORAGE_MULTIPLIER)); } - private void setInactivePackageThreshold(int threshold) { - DeviceConfig.setProperty( - DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE, - "inactive_app_threshold_days", Integer.toString(threshold), false); - } - - private void enableDowngradeFeature(boolean enabled) { - DeviceConfig.setProperty( - DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE, - "downgrade_unused_apps_enabled", Boolean.toString(enabled), false); - } - // TODO(aeubanks): figure out how to get scheduled bg-dexopt to run private static void runBackgroundDexOpt() throws IOException { String result = runShellCommand("cmd package bg-dexopt-job " + PACKAGE_NAME); @@ -278,7 +244,7 @@ public final class BackgroundDexOptServiceIntegrationTests { // Test that background dexopt under normal conditions succeeds. @Test - public void testBackgroundDexOpt_normalConditions_dexOptSucceeds() throws IOException { + public void testBackgroundDexOpt() throws IOException { // Set filter to quicken. compilePackageWithFilter(PACKAGE_NAME, "verify"); Assert.assertEquals("verify", getCompilerFilter(PACKAGE_NAME)); @@ -291,16 +257,17 @@ public final class BackgroundDexOptServiceIntegrationTests { // Test that background dexopt under low storage conditions upgrades used packages. @Test - public void testBackgroundDexOpt_lowStorage_usedPkgsUpgraded() throws IOException { + public void testBackgroundDexOptDowngradeSkipRecentlyUsedPackage() throws IOException { // Should be less than DOWNGRADE_AFTER_DAYS. long deltaDays = DOWNGRADE_AFTER_DAYS - 1; try { - enableDowngradeFeature(false); // Set time to future. setTimeFutureDays(deltaDays); + // Set filter to quicken. compilePackageWithFilter(PACKAGE_NAME, "quicken"); Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME)); + // Fill up storage to trigger low storage threshold. fillUpToLowStorage(); @@ -315,161 +282,29 @@ public final class BackgroundDexOptServiceIntegrationTests { } // Test that background dexopt under low storage conditions downgrades unused packages. - // This happens if the system property pm.dexopt.downgrade_after_inactive_days is set - // (e.g. on Android Go devices). @Test - public void testBackgroundDexOpt_lowStorage_unusedPkgsDowngraded() - throws IOException { + public void testBackgroundDexOptDowngradeSuccessful() throws IOException { // Should be more than DOWNGRADE_AFTER_DAYS. long deltaDays = DOWNGRADE_AFTER_DAYS + 1; try { - enableDowngradeFeature(false); - // Set time to future. - setTimeFutureDays(deltaDays); - // Set filter to quicken. - compilePackageWithFilter(PACKAGE_NAME, "quicken"); - Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME)); - // Fill up storage to trigger low storage threshold. - fillUpToLowStorage(); - - runBackgroundDexOpt(); - - // Verify that downgrade is successful. - Assert.assertEquals(DOWNGRADE_COMPILER_FILTER, getCompilerFilter(PACKAGE_NAME)); - } finally { - // Reset time. - setTimeFutureDays(-deltaDays); - } - } - - // Test that the background dexopt downgrades inactive packages when the downgrade feature is - // enabled. - @Test - public void testBackgroundDexOpt_downgradeFeatureEnabled_lowStorage_inactivePkgsDowngraded() - throws IOException { - // Should be more than DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS. - long deltaDays = DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS + 1; - try { - enableDowngradeFeature(true); - setInactivePackageThreshold(DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS); // Set time to future. setTimeFutureDays(deltaDays); - // Set filter to quicken. - compilePackageWithFilter(PACKAGE_NAME, "quicken"); - Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME)); - // Fill up storage to trigger low storage threshold. - fillUpToLowStorage(); - - runBackgroundDexOpt(); - - // Verify that downgrade is successful. - Assert.assertEquals(DOWNGRADE_COMPILER_FILTER, getCompilerFilter(PACKAGE_NAME)); - } finally { - // Reset time. - setTimeFutureDays(-deltaDays); - } - } - - // Test that the background dexopt upgrades used packages when the downgrade feature is enabled. - // This test doesn't fill the device storage completely, but to a multiplier of the low storage - // threshold and this is why apps can still be optimized. - @Test - public void testBackgroundDexOpt_downgradeFeatureEnabled_lowStorage_usedPkgsUpgraded() - throws IOException { - enableDowngradeFeature(true); - // Set filter to quicken. - compilePackageWithFilter(PACKAGE_NAME, "quicken"); - Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME)); - // Fill up storage to trigger low storage threshold. - fillUpToLowStorage(); - - runBackgroundDexOpt(); - - /// Verify that bg-dexopt is successful in upgrading the used packages. - Assert.assertEquals(BG_DEXOPT_COMPILER_FILTER, getCompilerFilter(PACKAGE_NAME)); - } - - // Test that the background dexopt fails and doesn't change the compilation filter of used - // packages when the downgrade feature is enabled and the storage is filled up completely. - // The bg-dexopt shouldn't optimise nor downgrade these packages. - @Test - public void testBackgroundDexOpt_downgradeFeatureEnabled_fillUpStorageCompletely_dexOptFails() - throws IOException { - enableDowngradeFeature(true); - String previousCompilerFilter = getCompilerFilter(PACKAGE_NAME); - - // Fill up storage completely, without using a multiplier for the low storage threshold. - fillUpStorageCompletely(); - - // When the bg dexopt runs with the storage filled up completely, it will fail. - mExpectedException.expect(IllegalStateException.class); - runBackgroundDexOpt(); - - /// Verify that bg-dexopt doesn't change the compilation filter of used apps. - Assert.assertEquals(previousCompilerFilter, getCompilerFilter(PACKAGE_NAME)); - } - // Test that the background dexopt upgrades the unused packages when the downgrade feature is - // on if the device is not low on storage. - @Test - public void testBackgroundDexOpt_downgradeFeatureEnabled_notLowStorage_unusedPkgsUpgraded() - throws IOException { - // Should be more than DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS. - long deltaDays = DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS + 1; - try { - enableDowngradeFeature(true); - setInactivePackageThreshold(DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS); - // Set time to future. - setTimeFutureDays(deltaDays); // Set filter to quicken. compilePackageWithFilter(PACKAGE_NAME, "quicken"); Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME)); - runBackgroundDexOpt(); - - // Verify that bg-dexopt is successful in upgrading the unused packages when the device - // is not low on storage. - Assert.assertEquals(BG_DEXOPT_COMPILER_FILTER, getCompilerFilter(PACKAGE_NAME)); - } finally { - // Reset time. - setTimeFutureDays(-deltaDays); - } - } - - // Test that when an unused package (which was downgraded) is used again, it's re-optimized when - // bg-dexopt runs again. - @Test - public void testBackgroundDexOpt_downgradeFeatureEnabled_downgradedPkgsUpgradedAfterUse() - throws IOException { - // Should be more than DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS. - long deltaDays = DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS + 1; - try { - enableDowngradeFeature(true); - setInactivePackageThreshold(DOWNGRADE_FEATURE_PKG_INACTIVE_AFTER_DAYS); - // Set time to future. - setTimeFutureDays(deltaDays); // Fill up storage to trigger low storage threshold. fillUpToLowStorage(); - // Set filter to quicken. - compilePackageWithFilter(PACKAGE_NAME, "quicken"); - Assert.assertEquals("quicken", getCompilerFilter(PACKAGE_NAME)); runBackgroundDexOpt(); // Verify that downgrade is successful. Assert.assertEquals(DOWNGRADE_COMPILER_FILTER, getCompilerFilter(PACKAGE_NAME)); - - // Reset time. - setTimeFutureDays(-deltaDays); - deltaDays = 0; - runBackgroundDexOpt(); - - // Verify that bg-dexopt is successful in upgrading the unused packages that were used - // again. - Assert.assertEquals(BG_DEXOPT_COMPILER_FILTER, getCompilerFilter(PACKAGE_NAME)); } finally { // Reset time. setTimeFutureDays(-deltaDays); } } + } diff --git a/tests/JobSchedulerPerfTests/Android.bp b/tests/JobSchedulerPerfTests/Android.bp index c51b811f0735..2ae8c33b60a7 100644 --- a/tests/JobSchedulerPerfTests/Android.bp +++ b/tests/JobSchedulerPerfTests/Android.bp @@ -19,7 +19,7 @@ android_test { "androidx.test.rules", "apct-perftests-utils", "services", - "jobscheduler-service", + "service-jobscheduler", ], platform_apis: true, certificate: "platform", diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java index 599ee56afdb3..abe6c6152da5 100644 --- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java +++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java @@ -1054,4 +1054,48 @@ public class RollbackTest { InstallUtils.dropShellPermissionIdentity(); } } + + @Test + public void testEnableRollbackTimeoutFailsRollback_MultiPackage() throws Exception { + try { + InstallUtils.adoptShellPermissionIdentity( + Manifest.permission.INSTALL_PACKAGES, + Manifest.permission.DELETE_PACKAGES, + Manifest.permission.TEST_MANAGE_ROLLBACKS, + Manifest.permission.MANAGE_ROLLBACKS, + Manifest.permission.WRITE_DEVICE_CONFIG); + + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK, + PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS, + Long.toString(5000), false /* makeDefault*/); + RollbackManager rm = RollbackUtils.getRollbackManager(); + + Uninstall.packages(TestApp.A, TestApp.B); + Install.multi(TestApp.A1, TestApp.B1).commit(); + waitForUnavailableRollback(TestApp.A); + + // Block the 2nd session for 10s so it will not be able to enable the rollback in time. + rm.blockRollbackManager(TimeUnit.SECONDS.toMillis(0)); + rm.blockRollbackManager(TimeUnit.SECONDS.toMillis(10)); + Install.multi(TestApp.A2, TestApp.B2).setEnableRollback().commit(); + + assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(2); + assertThat(InstallUtils.getInstalledVersion(TestApp.B)).isEqualTo(2); + + // Give plenty of time for RollbackManager to unblock and attempt + // to make the rollback available before asserting that the + // rollback was not made available. + Thread.sleep(TimeUnit.SECONDS.toMillis(2)); + + List<RollbackInfo> available = rm.getAvailableRollbacks(); + assertThat(getUniqueRollbackInfoForPackage(available, TestApp.A)).isNull(); + assertThat(getUniqueRollbackInfoForPackage(available, TestApp.B)).isNull(); + } finally { + //setting the timeout back to default + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ROLLBACK, + PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS, + null, false /* makeDefault*/); + InstallUtils.dropShellPermissionIdentity(); + } + } } diff --git a/tests/net/java/android/net/ip/InterfaceControllerTest.java b/tests/net/java/android/net/ip/InterfaceControllerTest.java deleted file mode 100644 index 7a56b3aafee7..000000000000 --- a/tests/net/java/android/net/ip/InterfaceControllerTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2019 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.ip; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -import android.net.INetd; -import android.net.InetAddresses; -import android.net.InterfaceConfigurationParcel; -import android.net.LinkAddress; -import android.net.util.SharedLog; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class InterfaceControllerTest { - private static final String TEST_IFACE = "testif"; - private static final String TEST_IPV4_ADDR = "192.168.123.28"; - private static final int TEST_PREFIXLENGTH = 31; - - @Mock private INetd mNetd; - @Mock private SharedLog mLog; - @Captor private ArgumentCaptor<InterfaceConfigurationParcel> mConfigCaptor; - - private InterfaceController mController; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - mController = new InterfaceController(TEST_IFACE, mNetd, mLog); - - doNothing().when(mNetd).interfaceSetCfg(mConfigCaptor.capture()); - } - - @Test - public void testSetIPv4Address() throws Exception { - mController.setIPv4Address( - new LinkAddress(InetAddresses.parseNumericAddress(TEST_IPV4_ADDR), - TEST_PREFIXLENGTH)); - verify(mNetd, times(1)).interfaceSetCfg(any()); - final InterfaceConfigurationParcel parcel = mConfigCaptor.getValue(); - assertEquals(TEST_IFACE, parcel.ifName); - assertEquals(TEST_IPV4_ADDR, parcel.ipv4Addr); - assertEquals(TEST_PREFIXLENGTH, parcel.prefixLength); - assertEquals("", parcel.hwAddr); - assertArrayEquals(new String[0], parcel.flags); - } - - @Test - public void testClearIPv4Address() throws Exception { - mController.clearIPv4Address(); - verify(mNetd, times(1)).interfaceSetCfg(any()); - final InterfaceConfigurationParcel parcel = mConfigCaptor.getValue(); - assertEquals(TEST_IFACE, parcel.ifName); - assertEquals("0.0.0.0", parcel.ipv4Addr); - assertEquals(0, parcel.prefixLength); - assertEquals("", parcel.hwAddr); - assertArrayEquals(new String[0], parcel.flags); - } -} diff --git a/tests/net/java/android/net/netlink/ConntrackMessageTest.java b/tests/net/java/android/net/netlink/ConntrackMessageTest.java deleted file mode 100644 index 5c8675770d50..000000000000 --- a/tests/net/java/android/net/netlink/ConntrackMessageTest.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2017 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.netlink; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assume.assumeTrue; - -import android.system.OsConstants; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import libcore.util.HexEncoding; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.Inet4Address; -import java.net.InetAddress; -import java.nio.ByteOrder; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class ConntrackMessageTest { - private static final boolean USING_LE = (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN); - - // Example 1: TCP (192.168.43.209, 44333) -> (23.211.13.26, 443) - public static final String CT_V4UPDATE_TCP_HEX = - // struct nlmsghdr - "50000000" + // length = 80 - "0001" + // type = (1 << 8) | 0 - "0501" + // flags - "01000000" + // seqno = 1 - "00000000" + // pid = 0 - // struct nfgenmsg - "02" + // nfgen_family = AF_INET - "00" + // version = NFNETLINK_V0 - "0000" + // res_id - // struct nlattr - "3400" + // nla_len = 52 - "0180" + // nla_type = nested CTA_TUPLE_ORIG - // struct nlattr - "1400" + // nla_len = 20 - "0180" + // nla_type = nested CTA_TUPLE_IP - "0800 0100 C0A82BD1" + // nla_type=CTA_IP_V4_SRC, ip=192.168.43.209 - "0800 0200 17D30D1A" + // nla_type=CTA_IP_V4_DST, ip=23.211.13.26 - // struct nlattr - "1C00" + // nla_len = 28 - "0280" + // nla_type = nested CTA_TUPLE_PROTO - "0500 0100 06 000000" + // nla_type=CTA_PROTO_NUM, proto=6 - "0600 0200 AD2D 0000" + // nla_type=CTA_PROTO_SRC_PORT, port=44333 (big endian) - "0600 0300 01BB 0000" + // nla_type=CTA_PROTO_DST_PORT, port=443 (big endian) - // struct nlattr - "0800" + // nla_len = 8 - "0700" + // nla_type = CTA_TIMEOUT - "00069780"; // nla_value = 432000 (big endian) - public static final byte[] CT_V4UPDATE_TCP_BYTES = - HexEncoding.decode(CT_V4UPDATE_TCP_HEX.replaceAll(" ", "").toCharArray(), false); - - // Example 2: UDP (100.96.167.146, 37069) -> (216.58.197.10, 443) - public static final String CT_V4UPDATE_UDP_HEX = - // struct nlmsghdr - "50000000" + // length = 80 - "0001" + // type = (1 << 8) | 0 - "0501" + // flags - "01000000" + // seqno = 1 - "00000000" + // pid = 0 - // struct nfgenmsg - "02" + // nfgen_family = AF_INET - "00" + // version = NFNETLINK_V0 - "0000" + // res_id - // struct nlattr - "3400" + // nla_len = 52 - "0180" + // nla_type = nested CTA_TUPLE_ORIG - // struct nlattr - "1400" + // nla_len = 20 - "0180" + // nla_type = nested CTA_TUPLE_IP - "0800 0100 6460A792" + // nla_type=CTA_IP_V4_SRC, ip=100.96.167.146 - "0800 0200 D83AC50A" + // nla_type=CTA_IP_V4_DST, ip=216.58.197.10 - // struct nlattr - "1C00" + // nla_len = 28 - "0280" + // nla_type = nested CTA_TUPLE_PROTO - "0500 0100 11 000000" + // nla_type=CTA_PROTO_NUM, proto=17 - "0600 0200 90CD 0000" + // nla_type=CTA_PROTO_SRC_PORT, port=37069 (big endian) - "0600 0300 01BB 0000" + // nla_type=CTA_PROTO_DST_PORT, port=443 (big endian) - // struct nlattr - "0800" + // nla_len = 8 - "0700" + // nla_type = CTA_TIMEOUT - "000000B4"; // nla_value = 180 (big endian) - public static final byte[] CT_V4UPDATE_UDP_BYTES = - HexEncoding.decode(CT_V4UPDATE_UDP_HEX.replaceAll(" ", "").toCharArray(), false); - - @Test - public void testConntrackIPv4TcpTimeoutUpdate() throws Exception { - assumeTrue(USING_LE); - - final byte[] tcp = ConntrackMessage.newIPv4TimeoutUpdateRequest( - OsConstants.IPPROTO_TCP, - (Inet4Address) InetAddress.getByName("192.168.43.209"), 44333, - (Inet4Address) InetAddress.getByName("23.211.13.26"), 443, - 432000); - assertArrayEquals(CT_V4UPDATE_TCP_BYTES, tcp); - } - - @Test - public void testConntrackIPv4UdpTimeoutUpdate() throws Exception { - assumeTrue(USING_LE); - - final byte[] udp = ConntrackMessage.newIPv4TimeoutUpdateRequest( - OsConstants.IPPROTO_UDP, - (Inet4Address) InetAddress.getByName("100.96.167.146"), 37069, - (Inet4Address) InetAddress.getByName("216.58.197.10"), 443, - 180); - assertArrayEquals(CT_V4UPDATE_UDP_BYTES, udp); - } -} diff --git a/tests/net/java/android/net/netlink/InetDiagSocketTest.java b/tests/net/java/android/net/netlink/InetDiagSocketTest.java deleted file mode 100644 index 84c5784d3fa8..000000000000 --- a/tests/net/java/android/net/netlink/InetDiagSocketTest.java +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Copyright (C) 2018 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.netlink; - -import static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP; -import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST; -import static android.system.OsConstants.AF_INET; -import static android.system.OsConstants.AF_INET6; -import static android.system.OsConstants.IPPROTO_TCP; -import static android.system.OsConstants.IPPROTO_UDP; -import static android.system.OsConstants.SOCK_DGRAM; -import static android.system.OsConstants.SOCK_STREAM; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -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.app.Instrumentation; -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.netlink.StructNlMsgHdr; -import android.os.Process; -import android.system.Os; - -import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import libcore.util.HexEncoding; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.io.FileDescriptor; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class InetDiagSocketTest { - private final String TAG = "InetDiagSocketTest"; - private ConnectivityManager mCm; - private Context mContext; - private final static int SOCKET_TIMEOUT_MS = 100; - - @Before - public void setUp() throws Exception { - Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); - mContext = instrumentation.getTargetContext(); - mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); - } - - private class Connection { - public int socketDomain; - public int socketType; - public InetAddress localAddress; - public InetAddress remoteAddress; - public InetAddress localhostAddress; - public InetSocketAddress local; - public InetSocketAddress remote; - public int protocol; - public FileDescriptor localFd; - public FileDescriptor remoteFd; - - public FileDescriptor createSocket() throws Exception { - return Os.socket(socketDomain, socketType, protocol); - } - - public Connection(String to, String from) throws Exception { - remoteAddress = InetAddress.getByName(to); - if (from != null) { - localAddress = InetAddress.getByName(from); - } else { - localAddress = (remoteAddress instanceof Inet4Address) ? - Inet4Address.getByName("localhost") : Inet6Address.getByName("::"); - } - if ((localAddress instanceof Inet4Address) && (remoteAddress instanceof Inet4Address)) { - socketDomain = AF_INET; - localhostAddress = Inet4Address.getByName("localhost"); - } else { - socketDomain = AF_INET6; - localhostAddress = Inet6Address.getByName("::"); - } - } - - public void close() throws Exception { - Os.close(localFd); - } - } - - private class TcpConnection extends Connection { - public TcpConnection(String to, String from) throws Exception { - super(to, from); - protocol = IPPROTO_TCP; - socketType = SOCK_STREAM; - - remoteFd = createSocket(); - Os.bind(remoteFd, remoteAddress, 0); - Os.listen(remoteFd, 10); - int remotePort = ((InetSocketAddress) Os.getsockname(remoteFd)).getPort(); - - localFd = createSocket(); - Os.bind(localFd, localAddress, 0); - Os.connect(localFd, remoteAddress, remotePort); - - local = (InetSocketAddress) Os.getsockname(localFd); - remote = (InetSocketAddress) Os.getpeername(localFd); - } - - public void close() throws Exception { - super.close(); - Os.close(remoteFd); - } - } - private class UdpConnection extends Connection { - public UdpConnection(String to, String from) throws Exception { - super(to, from); - protocol = IPPROTO_UDP; - socketType = SOCK_DGRAM; - - remoteFd = null; - localFd = createSocket(); - Os.bind(localFd, localAddress, 0); - - Os.connect(localFd, remoteAddress, 7); - local = (InetSocketAddress) Os.getsockname(localFd); - remote = new InetSocketAddress(remoteAddress, 7); - } - } - - private void checkConnectionOwnerUid(int protocol, InetSocketAddress local, - InetSocketAddress remote, boolean expectSuccess) { - final int uid = mCm.getConnectionOwnerUid(protocol, local, remote); - - if (expectSuccess) { - assertEquals(Process.myUid(), uid); - } else { - assertNotEquals(Process.myUid(), uid); - } - } - - private int findLikelyFreeUdpPort(UdpConnection conn) throws Exception { - UdpConnection udp = new UdpConnection(conn.remoteAddress.getHostAddress(), - conn.localAddress.getHostAddress()); - final int localPort = udp.local.getPort(); - udp.close(); - return localPort; - } - - /** - * Create a test connection for UDP and TCP sockets and verify that this - * {protocol, local, remote} socket result in receiving a valid UID. - */ - public void checkGetConnectionOwnerUid(String to, String from) throws Exception { - TcpConnection tcp = new TcpConnection(to, from); - checkConnectionOwnerUid(tcp.protocol, tcp.local, tcp.remote, true); - checkConnectionOwnerUid(IPPROTO_UDP, tcp.local, tcp.remote, false); - checkConnectionOwnerUid(tcp.protocol, new InetSocketAddress(0), tcp.remote, false); - checkConnectionOwnerUid(tcp.protocol, tcp.local, new InetSocketAddress(0), false); - tcp.close(); - - UdpConnection udp = new UdpConnection(to,from); - checkConnectionOwnerUid(udp.protocol, udp.local, udp.remote, true); - checkConnectionOwnerUid(IPPROTO_TCP, udp.local, udp.remote, false); - checkConnectionOwnerUid(udp.protocol, new InetSocketAddress(findLikelyFreeUdpPort(udp)), - udp.remote, false); - udp.close(); - } - - @Test - public void testGetConnectionOwnerUid() throws Exception { - checkGetConnectionOwnerUid("::", null); - checkGetConnectionOwnerUid("::", "::"); - checkGetConnectionOwnerUid("0.0.0.0", null); - checkGetConnectionOwnerUid("0.0.0.0", "0.0.0.0"); - checkGetConnectionOwnerUid("127.0.0.1", null); - checkGetConnectionOwnerUid("127.0.0.1", "127.0.0.2"); - checkGetConnectionOwnerUid("::1", null); - checkGetConnectionOwnerUid("::1", "::1"); - } - - /* Verify fix for b/141603906 */ - @Test - public void testB141603906() throws Exception { - final InetSocketAddress src = new InetSocketAddress(0); - final InetSocketAddress dst = new InetSocketAddress(0); - final int numThreads = 8; - final int numSockets = 5000; - final Thread[] threads = new Thread[numThreads]; - - for (int i = 0; i < numThreads; i++) { - threads[i] = new Thread(() -> { - for (int j = 0; j < numSockets; j++) { - mCm.getConnectionOwnerUid(IPPROTO_TCP, src, dst); - } - }); - } - - for (Thread thread : threads) { - thread.start(); - } - - for (Thread thread : threads) { - thread.join(); - } - } - - // Hexadecimal representation of InetDiagReqV2 request. - private static final String INET_DIAG_REQ_V2_UDP_INET4_HEX = - // struct nlmsghdr - "48000000" + // length = 72 - "1400" + // type = SOCK_DIAG_BY_FAMILY - "0103" + // flags = NLM_F_REQUEST | NLM_F_DUMP - "00000000" + // seqno - "00000000" + // pid (0 == kernel) - // struct inet_diag_req_v2 - "02" + // family = AF_INET - "11" + // protcol = IPPROTO_UDP - "00" + // idiag_ext - "00" + // pad - "ffffffff" + // idiag_states - // inet_diag_sockid - "a5de" + // idiag_sport = 42462 - "b971" + // idiag_dport = 47473 - "0a006402000000000000000000000000" + // idiag_src = 10.0.100.2 - "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8 - "00000000" + // idiag_if - "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE - private static final byte[] INET_DIAG_REQ_V2_UDP_INET4_BYTES = - HexEncoding.decode(INET_DIAG_REQ_V2_UDP_INET4_HEX.toCharArray(), false); - - @Test - public void testInetDiagReqV2UdpInet4() throws Exception { - InetSocketAddress local = new InetSocketAddress(InetAddress.getByName("10.0.100.2"), - 42462); - InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"), - 47473); - final byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_UDP, local, remote, AF_INET, - (short) (NLM_F_REQUEST | NLM_F_DUMP)); - assertArrayEquals(INET_DIAG_REQ_V2_UDP_INET4_BYTES, msg); - } - - // Hexadecimal representation of InetDiagReqV2 request. - private static final String INET_DIAG_REQ_V2_TCP_INET6_HEX = - // struct nlmsghdr - "48000000" + // length = 72 - "1400" + // type = SOCK_DIAG_BY_FAMILY - "0100" + // flags = NLM_F_REQUEST - "00000000" + // seqno - "00000000" + // pid (0 == kernel) - // struct inet_diag_req_v2 - "0a" + // family = AF_INET6 - "06" + // protcol = IPPROTO_TCP - "00" + // idiag_ext - "00" + // pad - "ffffffff" + // idiag_states - // inet_diag_sockid - "a5de" + // idiag_sport = 42462 - "b971" + // idiag_dport = 47473 - "fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b - "08080808000000000000000000000000" + // idiag_dst = 8.8.8.8 - "00000000" + // idiag_if - "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE - private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_BYTES = - HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_HEX.toCharArray(), false); - - @Test - public void testInetDiagReqV2TcpInet6() throws Exception { - InetSocketAddress local = new InetSocketAddress( - InetAddress.getByName("fe80::86c9:b2ff:fe6a:ed4b"), 42462); - InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"), - 47473); - byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET6, - NLM_F_REQUEST); - - assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg); - } - - // Hexadecimal representation of InetDiagReqV2 request with extension, INET_DIAG_INFO. - private static final String INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_HEX = - // struct nlmsghdr - "48000000" + // length = 72 - "1400" + // type = SOCK_DIAG_BY_FAMILY - "0100" + // flags = NLM_F_REQUEST - "00000000" + // seqno - "00000000" + // pid (0 == kernel) - // struct inet_diag_req_v2 - "02" + // family = AF_INET - "06" + // protcol = IPPROTO_TCP - "02" + // idiag_ext = INET_DIAG_INFO - "00" + // pad - "ffffffff" + // idiag_states - // inet_diag_sockid - "3039" + // idiag_sport = 12345 - "d431" + // idiag_dport = 54321 - "01020304000000000000000000000000" + // idiag_src = 1.2.3.4 - "08080404000000000000000000000000" + // idiag_dst = 8.8.4.4 - "00000000" + // idiag_if - "ffffffffffffffff"; // idiag_cookie = INET_DIAG_NOCOOKIE - - private static final byte[] INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_BYTES = - HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_HEX.toCharArray(), false); - private static final int TCP_ALL_STATES = 0xffffffff; - @Test - public void testInetDiagReqV2TcpInetWithExt() throws Exception { - InetSocketAddress local = new InetSocketAddress( - InetAddress.getByName("1.2.3.4"), 12345); - InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.4.4"), - 54321); - byte[] msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET, - NLM_F_REQUEST, 0 /* pad */, 2 /* idiagExt */, TCP_ALL_STATES); - - assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET_INET_DIAG_BYTES, msg); - - local = new InetSocketAddress( - InetAddress.getByName("fe80::86c9:b2ff:fe6a:ed4b"), 42462); - remote = new InetSocketAddress(InetAddress.getByName("8.8.8.8"), - 47473); - msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, remote, AF_INET6, - NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES); - - assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_BYTES, msg); - } - - // Hexadecimal representation of InetDiagReqV2 request with no socket specified. - private static final String INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_HEX = - // struct nlmsghdr - "48000000" + // length = 72 - "1400" + // type = SOCK_DIAG_BY_FAMILY - "0100" + // flags = NLM_F_REQUEST - "00000000" + // seqno - "00000000" + // pid (0 == kernel) - // struct inet_diag_req_v2 - "0a" + // family = AF_INET6 - "06" + // protcol = IPPROTO_TCP - "00" + // idiag_ext - "00" + // pad - "ffffffff" + // idiag_states - // inet_diag_sockid - "0000" + // idiag_sport - "0000" + // idiag_dport - "00000000000000000000000000000000" + // idiag_src - "00000000000000000000000000000000" + // idiag_dst - "00000000" + // idiag_if - "0000000000000000"; // idiag_cookie - - private static final byte[] INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES = - HexEncoding.decode(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFIED_HEX.toCharArray(), false); - - @Test - public void testInetDiagReqV2TcpInet6NoIdSpecified() throws Exception { - InetSocketAddress local = new InetSocketAddress( - InetAddress.getByName("fe80::fe6a:ed4b"), 12345); - InetSocketAddress remote = new InetSocketAddress(InetAddress.getByName("8.8.4.4"), - 54321); - // Verify no socket specified if either local or remote socket address is null. - byte[] msgExt = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, null, AF_INET6, - NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES); - byte[] msg; - try { - msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, remote, AF_INET6, - NLM_F_REQUEST); - fail("Both remote and local should be null, expected UnknownHostException"); - } catch (NullPointerException e) { - } - - try { - msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, local, null, AF_INET6, - NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES); - fail("Both remote and local should be null, expected UnknownHostException"); - } catch (NullPointerException e) { - } - - msg = InetDiagMessage.InetDiagReqV2(IPPROTO_TCP, null, null, AF_INET6, - NLM_F_REQUEST, 0 /* pad */, 0 /* idiagExt */, TCP_ALL_STATES); - assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES, msg); - assertArrayEquals(INET_DIAG_REQ_V2_TCP_INET6_NO_ID_SPECIFED_BYTES, msgExt); - } - - // Hexadecimal representation of InetDiagReqV2 request. - private static final String INET_DIAG_MSG_HEX = - // struct nlmsghdr - "58000000" + // length = 88 - "1400" + // type = SOCK_DIAG_BY_FAMILY - "0200" + // flags = NLM_F_MULTI - "00000000" + // seqno - "f5220000" + // pid (0 == kernel) - // struct inet_diag_msg - "0a" + // family = AF_INET6 - "01" + // idiag_state - "00" + // idiag_timer - "00" + // idiag_retrans - // inet_diag_sockid - "a817" + // idiag_sport = 43031 - "960f" + // idiag_dport = 38415 - "fe8000000000000086c9b2fffe6aed4b" + // idiag_src = fe80::86c9:b2ff:fe6a:ed4b - "00000000000000000000ffff08080808" + // idiag_dst = 8.8.8.8 - "00000000" + // idiag_if - "ffffffffffffffff" + // idiag_cookie = INET_DIAG_NOCOOKIE - "00000000" + // idiag_expires - "00000000" + // idiag_rqueue - "00000000" + // idiag_wqueue - "a3270000" + // idiag_uid - "A57E1900"; // idiag_inode - private static final byte[] INET_DIAG_MSG_BYTES = - HexEncoding.decode(INET_DIAG_MSG_HEX.toCharArray(), false); - - @Test - public void testParseInetDiagResponse() throws Exception { - final ByteBuffer byteBuffer = ByteBuffer.wrap(INET_DIAG_MSG_BYTES); - byteBuffer.order(ByteOrder.LITTLE_ENDIAN); - final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer); - assertNotNull(msg); - - assertTrue(msg instanceof InetDiagMessage); - final InetDiagMessage inetDiagMsg = (InetDiagMessage) msg; - assertEquals(10147, inetDiagMsg.mStructInetDiagMsg.idiag_uid); - - final StructNlMsgHdr hdr = inetDiagMsg.getHeader(); - assertNotNull(hdr); - assertEquals(NetlinkConstants.SOCK_DIAG_BY_FAMILY, hdr.nlmsg_type); - assertEquals(StructNlMsgHdr.NLM_F_MULTI, hdr.nlmsg_flags); - assertEquals(0, hdr.nlmsg_seq); - assertEquals(8949, hdr.nlmsg_pid); - } -} diff --git a/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java b/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java deleted file mode 100644 index 44ab6051d5b3..000000000000 --- a/tests/net/java/android/net/netlink/NetlinkErrorMessageTest.java +++ /dev/null @@ -1,94 +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.net.netlink; - -import static android.net.netlink.StructNlMsgHdr.NLM_F_ACK; -import static android.net.netlink.StructNlMsgHdr.NLM_F_REPLACE; -import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import android.net.netlink.NetlinkConstants; -import android.net.netlink.NetlinkErrorMessage; -import android.net.netlink.NetlinkMessage; -import android.net.netlink.StructNlMsgErr; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import libcore.util.HexEncoding; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class NetlinkErrorMessageTest { - private final String TAG = "NetlinkErrorMessageTest"; - - // Hexadecimal representation of packet capture. - public static final String NLM_ERROR_OK_HEX = - // struct nlmsghdr - "24000000" + // length = 36 - "0200" + // type = 2 (NLMSG_ERROR) - "0000" + // flags - "26350000" + // seqno - "64100000" + // pid = userspace process - // error integer - "00000000" + // "errno" (0 == OK) - // struct nlmsghdr - "30000000" + // length (48) of original request - "1C00" + // type = 28 (RTM_NEWNEIGH) - "0501" + // flags (NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE) - "26350000" + // seqno - "00000000"; // pid = kernel - public static final byte[] NLM_ERROR_OK = - HexEncoding.decode(NLM_ERROR_OK_HEX.toCharArray(), false); - - @Test - public void testParseNlmErrorOk() { - final ByteBuffer byteBuffer = ByteBuffer.wrap(NLM_ERROR_OK); - byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. - final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer); - assertNotNull(msg); - assertTrue(msg instanceof NetlinkErrorMessage); - final NetlinkErrorMessage errorMsg = (NetlinkErrorMessage) msg; - - final StructNlMsgHdr hdr = errorMsg.getHeader(); - assertNotNull(hdr); - assertEquals(36, hdr.nlmsg_len); - assertEquals(NetlinkConstants.NLMSG_ERROR, hdr.nlmsg_type); - assertEquals(0, hdr.nlmsg_flags); - assertEquals(13606, hdr.nlmsg_seq); - assertEquals(4196, hdr.nlmsg_pid); - - final StructNlMsgErr err = errorMsg.getNlMsgError(); - assertNotNull(err); - assertEquals(0, err.error); - assertNotNull(err.msg); - assertEquals(48, err.msg.nlmsg_len); - assertEquals(NetlinkConstants.RTM_NEWNEIGH, err.msg.nlmsg_type); - assertEquals((NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE), err.msg.nlmsg_flags); - assertEquals(13606, err.msg.nlmsg_seq); - assertEquals(0, err.msg.nlmsg_pid); - } -} diff --git a/tests/net/java/android/net/netlink/NetlinkSocketTest.java b/tests/net/java/android/net/netlink/NetlinkSocketTest.java deleted file mode 100644 index 3916578a3405..000000000000 --- a/tests/net/java/android/net/netlink/NetlinkSocketTest.java +++ /dev/null @@ -1,106 +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.net.netlink; - -import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE; -import static android.system.OsConstants.NETLINK_ROUTE; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import android.net.netlink.NetlinkSocket; -import android.net.netlink.RtNetlinkNeighborMessage; -import android.net.netlink.StructNlMsgHdr; -import android.system.NetlinkSocketAddress; -import android.system.Os; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import libcore.io.IoUtils; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.io.FileDescriptor; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class NetlinkSocketTest { - private final String TAG = "NetlinkSocketTest"; - - @Test - public void testBasicWorkingGetNeighborsQuery() throws Exception { - final FileDescriptor fd = NetlinkSocket.forProto(NETLINK_ROUTE); - assertNotNull(fd); - - NetlinkSocket.connectToKernel(fd); - - final NetlinkSocketAddress localAddr = (NetlinkSocketAddress) Os.getsockname(fd); - assertNotNull(localAddr); - assertEquals(0, localAddr.getGroupsMask()); - assertTrue(0 != localAddr.getPortId()); - - final int TEST_SEQNO = 5; - final byte[] req = RtNetlinkNeighborMessage.newGetNeighborsRequest(TEST_SEQNO); - assertNotNull(req); - - final long TIMEOUT = 500; - assertEquals(req.length, NetlinkSocket.sendMessage(fd, req, 0, req.length, TIMEOUT)); - - int neighMessageCount = 0; - int doneMessageCount = 0; - - while (doneMessageCount == 0) { - ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT); - assertNotNull(response); - assertTrue(StructNlMsgHdr.STRUCT_SIZE <= response.limit()); - assertEquals(0, response.position()); - assertEquals(ByteOrder.nativeOrder(), response.order()); - - // Verify the messages at least appears minimally reasonable. - while (response.remaining() > 0) { - final NetlinkMessage msg = NetlinkMessage.parse(response); - assertNotNull(msg); - final StructNlMsgHdr hdr = msg.getHeader(); - assertNotNull(hdr); - - if (hdr.nlmsg_type == NetlinkConstants.NLMSG_DONE) { - doneMessageCount++; - continue; - } - - assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type); - assertTrue(msg instanceof RtNetlinkNeighborMessage); - assertTrue((hdr.nlmsg_flags & StructNlMsgHdr.NLM_F_MULTI) != 0); - assertEquals(TEST_SEQNO, hdr.nlmsg_seq); - assertEquals(localAddr.getPortId(), hdr.nlmsg_pid); - - neighMessageCount++; - } - } - - assertEquals(1, doneMessageCount); - // TODO: make sure this test passes sanely in airplane mode. - assertTrue(neighMessageCount > 0); - - IoUtils.closeQuietly(fd); - } -} diff --git a/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java b/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java deleted file mode 100644 index 81625227f36e..000000000000 --- a/tests/net/java/android/net/netlink/RtNetlinkNeighborMessageTest.java +++ /dev/null @@ -1,270 +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.net.netlink; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import android.net.netlink.NetlinkConstants; -import android.net.netlink.NetlinkMessage; -import android.net.netlink.RtNetlinkNeighborMessage; -import android.net.netlink.StructNdMsg; -import android.net.netlink.StructNlMsgHdr; -import android.system.OsConstants; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import libcore.util.HexEncoding; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.Inet4Address; -import java.net.InetAddress; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Arrays; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class RtNetlinkNeighborMessageTest { - private final String TAG = "RtNetlinkNeighborMessageTest"; - - // Hexadecimal representation of packet capture. - public static final String RTM_DELNEIGH_HEX = - // struct nlmsghdr - "4c000000" + // length = 76 - "1d00" + // type = 29 (RTM_DELNEIGH) - "0000" + // flags - "00000000" + // seqno - "00000000" + // pid (0 == kernel) - // struct ndmsg - "02" + // family - "00" + // pad1 - "0000" + // pad2 - "15000000" + // interface index (21 == wlan0, on test device) - "0400" + // NUD state (0x04 == NUD_STALE) - "00" + // flags - "01" + // type - // struct nlattr: NDA_DST - "0800" + // length = 8 - "0100" + // type (1 == NDA_DST, for neighbor messages) - "c0a89ffe" + // IPv4 address (== 192.168.159.254) - // struct nlattr: NDA_LLADDR - "0a00" + // length = 10 - "0200" + // type (2 == NDA_LLADDR, for neighbor messages) - "00005e000164" + // MAC Address (== 00:00:5e:00:01:64) - "0000" + // padding, for 4 byte alignment - // struct nlattr: NDA_PROBES - "0800" + // length = 8 - "0400" + // type (4 == NDA_PROBES, for neighbor messages) - "01000000" + // number of probes - // struct nlattr: NDA_CACHEINFO - "1400" + // length = 20 - "0300" + // type (3 == NDA_CACHEINFO, for neighbor messages) - "05190000" + // ndm_used, as "clock ticks ago" - "05190000" + // ndm_confirmed, as "clock ticks ago" - "190d0000" + // ndm_updated, as "clock ticks ago" - "00000000"; // ndm_refcnt - public static final byte[] RTM_DELNEIGH = - HexEncoding.decode(RTM_DELNEIGH_HEX.toCharArray(), false); - - // Hexadecimal representation of packet capture. - public static final String RTM_NEWNEIGH_HEX = - // struct nlmsghdr - "58000000" + // length = 88 - "1c00" + // type = 28 (RTM_NEWNEIGH) - "0000" + // flags - "00000000" + // seqno - "00000000" + // pid (0 == kernel) - // struct ndmsg - "0a" + // family - "00" + // pad1 - "0000" + // pad2 - "15000000" + // interface index (21 == wlan0, on test device) - "0400" + // NUD state (0x04 == NUD_STALE) - "80" + // flags - "01" + // type - // struct nlattr: NDA_DST - "1400" + // length = 20 - "0100" + // type (1 == NDA_DST, for neighbor messages) - "fe8000000000000086c9b2fffe6aed4b" + // IPv6 address (== fe80::86c9:b2ff:fe6a:ed4b) - // struct nlattr: NDA_LLADDR - "0a00" + // length = 10 - "0200" + // type (2 == NDA_LLADDR, for neighbor messages) - "84c9b26aed4b" + // MAC Address (== 84:c9:b2:6a:ed:4b) - "0000" + // padding, for 4 byte alignment - // struct nlattr: NDA_PROBES - "0800" + // length = 8 - "0400" + // type (4 == NDA_PROBES, for neighbor messages) - "01000000" + // number of probes - // struct nlattr: NDA_CACHEINFO - "1400" + // length = 20 - "0300" + // type (3 == NDA_CACHEINFO, for neighbor messages) - "eb0e0000" + // ndm_used, as "clock ticks ago" - "861f0000" + // ndm_confirmed, as "clock ticks ago" - "00000000" + // ndm_updated, as "clock ticks ago" - "05000000"; // ndm_refcnt - public static final byte[] RTM_NEWNEIGH = - HexEncoding.decode(RTM_NEWNEIGH_HEX.toCharArray(), false); - - // An example of the full response from an RTM_GETNEIGH query. - private static final String RTM_GETNEIGH_RESPONSE_HEX = - // <-- struct nlmsghr -->|<-- struct ndmsg -->|<-- struct nlattr: NDA_DST -->|<-- NDA_LLADDR -->|<-- NDA_PROBES -->|<-- NDA_CACHEINFO -->| - "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000001 0a00 0200 333300000001 0000 0800 0400 00000000 1400 0300 a2280000 32110000 32110000 01000000" + - "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff000001 0a00 0200 3333ff000001 0000 0800 0400 00000000 1400 0300 0d280000 9d100000 9d100000 00000000" + - "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 0400 80 01 1400 0100 20010db800040ca00000000000000001 0a00 0200 84c9b26aed4b 0000 0800 0400 04000000 1400 0300 90100000 90100000 90080000 01000000" + - "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff47da19 0a00 0200 3333ff47da19 0000 0800 0400 00000000 1400 0300 a1280000 31110000 31110000 01000000" + - "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff020000000000000000000000000016 0a00 0200 333300000016 0000 0800 0400 00000000 1400 0300 912a0000 21130000 21130000 00000000" + - "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff0200000000000000000001ffeace3b 0a00 0200 3333ffeace3b 0000 0800 0400 00000000 1400 0300 922a0000 22130000 22130000 00000000" + - "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ff5c2a83 0a00 0200 3333ff5c2a83 0000 0800 0400 00000000 1400 0300 391c0000 c9040000 c9040000 01000000" + - "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 01000000 4000 00 02 1400 0100 00000000000000000000000000000000 0a00 0200 000000000000 0000 0800 0400 00000000 1400 0300 cd180200 5d010200 5d010200 08000000" + - "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000002 0a00 0200 333300000002 0000 0800 0400 00000000 1400 0300 352a0000 c5120000 c5120000 00000000" + - "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff020000000000000000000000000016 0a00 0200 333300000016 0000 0800 0400 00000000 1400 0300 982a0000 28130000 28130000 00000000" + - "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 0800 80 01 1400 0100 fe8000000000000086c9b2fffe6aed4b 0a00 0200 84c9b26aed4b 0000 0800 0400 00000000 1400 0300 23000000 24000000 57000000 13000000" + - "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 15000000 4000 00 05 1400 0100 ff0200000000000000000001ffeace3b 0a00 0200 3333ffeace3b 0000 0800 0400 00000000 1400 0300 992a0000 29130000 29130000 01000000" + - "58000000 1c00 0200 00000000 3e2b0000 0a 00 0000 14000000 4000 00 05 1400 0100 ff020000000000000000000000000002 0a00 0200 333300000002 0000 0800 0400 00000000 1400 0300 2e2a0000 be120000 be120000 00000000" + - "44000000 1c00 0200 00000000 3e2b0000 02 00 0000 18000000 4000 00 03 0800 0100 00000000 0400 0200 0800 0400 00000000 1400 0300 75280000 05110000 05110000 22000000"; - public static final byte[] RTM_GETNEIGH_RESPONSE = - HexEncoding.decode(RTM_GETNEIGH_RESPONSE_HEX.replaceAll(" ", "").toCharArray(), false); - - @Test - public void testParseRtmDelNeigh() { - final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_DELNEIGH); - byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. - final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer); - assertNotNull(msg); - assertTrue(msg instanceof RtNetlinkNeighborMessage); - final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg; - - final StructNlMsgHdr hdr = neighMsg.getHeader(); - assertNotNull(hdr); - assertEquals(76, hdr.nlmsg_len); - assertEquals(NetlinkConstants.RTM_DELNEIGH, hdr.nlmsg_type); - assertEquals(0, hdr.nlmsg_flags); - assertEquals(0, hdr.nlmsg_seq); - assertEquals(0, hdr.nlmsg_pid); - - final StructNdMsg ndmsgHdr = neighMsg.getNdHeader(); - assertNotNull(ndmsgHdr); - assertEquals((byte) OsConstants.AF_INET, ndmsgHdr.ndm_family); - assertEquals(21, ndmsgHdr.ndm_ifindex); - assertEquals(StructNdMsg.NUD_STALE, ndmsgHdr.ndm_state); - final InetAddress destination = neighMsg.getDestination(); - assertNotNull(destination); - assertEquals(InetAddress.parseNumericAddress("192.168.159.254"), destination); - } - - @Test - public void testParseRtmNewNeigh() { - final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_NEWNEIGH); - byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. - final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer); - assertNotNull(msg); - assertTrue(msg instanceof RtNetlinkNeighborMessage); - final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg; - - final StructNlMsgHdr hdr = neighMsg.getHeader(); - assertNotNull(hdr); - assertEquals(88, hdr.nlmsg_len); - assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type); - assertEquals(0, hdr.nlmsg_flags); - assertEquals(0, hdr.nlmsg_seq); - assertEquals(0, hdr.nlmsg_pid); - - final StructNdMsg ndmsgHdr = neighMsg.getNdHeader(); - assertNotNull(ndmsgHdr); - assertEquals((byte) OsConstants.AF_INET6, ndmsgHdr.ndm_family); - assertEquals(21, ndmsgHdr.ndm_ifindex); - assertEquals(StructNdMsg.NUD_STALE, ndmsgHdr.ndm_state); - final InetAddress destination = neighMsg.getDestination(); - assertNotNull(destination); - assertEquals(InetAddress.parseNumericAddress("fe80::86c9:b2ff:fe6a:ed4b"), destination); - } - - @Test - public void testParseRtmGetNeighResponse() { - final ByteBuffer byteBuffer = ByteBuffer.wrap(RTM_GETNEIGH_RESPONSE); - byteBuffer.order(ByteOrder.LITTLE_ENDIAN); // For testing. - - int messageCount = 0; - while (byteBuffer.remaining() > 0) { - final NetlinkMessage msg = NetlinkMessage.parse(byteBuffer); - assertNotNull(msg); - assertTrue(msg instanceof RtNetlinkNeighborMessage); - final RtNetlinkNeighborMessage neighMsg = (RtNetlinkNeighborMessage) msg; - - final StructNlMsgHdr hdr = neighMsg.getHeader(); - assertNotNull(hdr); - assertEquals(NetlinkConstants.RTM_NEWNEIGH, hdr.nlmsg_type); - assertEquals(StructNlMsgHdr.NLM_F_MULTI, hdr.nlmsg_flags); - assertEquals(0, hdr.nlmsg_seq); - assertEquals(11070, hdr.nlmsg_pid); - - messageCount++; - } - // TODO: add more detailed spot checks. - assertEquals(14, messageCount); - } - - @Test - public void testCreateRtmNewNeighMessage() { - final int seqNo = 2635; - final int ifIndex = 14; - final byte[] llAddr = - new byte[] { (byte) 1, (byte) 2, (byte) 3, (byte) 4, (byte) 5, (byte) 6 }; - - // Hexadecimal representation of our created packet. - final String expectedNewNeighHex = - // struct nlmsghdr - "30000000" + // length = 48 - "1c00" + // type = 28 (RTM_NEWNEIGH) - "0501" + // flags (NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE) - "4b0a0000" + // seqno - "00000000" + // pid (0 == kernel) - // struct ndmsg - "02" + // family - "00" + // pad1 - "0000" + // pad2 - "0e000000" + // interface index (14) - "0800" + // NUD state (0x08 == NUD_DELAY) - "00" + // flags - "00" + // type - // struct nlattr: NDA_DST - "0800" + // length = 8 - "0100" + // type (1 == NDA_DST, for neighbor messages) - "7f000001" + // IPv4 address (== 127.0.0.1) - // struct nlattr: NDA_LLADDR - "0a00" + // length = 10 - "0200" + // type (2 == NDA_LLADDR, for neighbor messages) - "010203040506" + // MAC Address (== 01:02:03:04:05:06) - "0000"; // padding, for 4 byte alignment - final byte[] expectedNewNeigh = - HexEncoding.decode(expectedNewNeighHex.toCharArray(), false); - - final byte[] bytes = RtNetlinkNeighborMessage.newNewNeighborMessage( - seqNo, Inet4Address.LOOPBACK, StructNdMsg.NUD_DELAY, ifIndex, llAddr); - if (!Arrays.equals(expectedNewNeigh, bytes)) { - assertEquals(expectedNewNeigh.length, bytes.length); - for (int i = 0; i < Math.min(expectedNewNeigh.length, bytes.length); i++) { - assertEquals(expectedNewNeigh[i], bytes[i]); - } - } - } -} diff --git a/tests/net/java/android/net/shared/Inet4AddressUtilsTest.java b/tests/net/java/android/net/shared/Inet4AddressUtilsTest.java deleted file mode 100644 index 35f8c790ad42..000000000000 --- a/tests/net/java/android/net/shared/Inet4AddressUtilsTest.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2019 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.shared; - -import static android.net.shared.Inet4AddressUtils.getBroadcastAddress; -import static android.net.shared.Inet4AddressUtils.getImplicitNetmask; -import static android.net.shared.Inet4AddressUtils.getPrefixMaskAsInet4Address; -import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH; -import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTL; -import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; -import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTL; -import static android.net.shared.Inet4AddressUtils.netmaskToPrefixLength; -import static android.net.shared.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH; -import static android.net.shared.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTL; - -import static junit.framework.Assert.assertEquals; - -import static org.junit.Assert.fail; - -import android.net.InetAddresses; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.Inet4Address; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class Inet4AddressUtilsTest { - - @Test - public void testInet4AddressToIntHTL() { - assertEquals(0, inet4AddressToIntHTL(ipv4Address("0.0.0.0"))); - assertEquals(0x000080ff, inet4AddressToIntHTL(ipv4Address("255.128.0.0"))); - assertEquals(0x0080ff0a, inet4AddressToIntHTL(ipv4Address("10.255.128.0"))); - assertEquals(0x00feff0a, inet4AddressToIntHTL(ipv4Address("10.255.254.0"))); - assertEquals(0xfeffa8c0, inet4AddressToIntHTL(ipv4Address("192.168.255.254"))); - assertEquals(0xffffa8c0, inet4AddressToIntHTL(ipv4Address("192.168.255.255"))); - } - - @Test - public void testIntToInet4AddressHTL() { - assertEquals(ipv4Address("0.0.0.0"), intToInet4AddressHTL(0)); - assertEquals(ipv4Address("255.128.0.0"), intToInet4AddressHTL(0x000080ff)); - assertEquals(ipv4Address("10.255.128.0"), intToInet4AddressHTL(0x0080ff0a)); - assertEquals(ipv4Address("10.255.254.0"), intToInet4AddressHTL(0x00feff0a)); - assertEquals(ipv4Address("192.168.255.254"), intToInet4AddressHTL(0xfeffa8c0)); - assertEquals(ipv4Address("192.168.255.255"), intToInet4AddressHTL(0xffffa8c0)); - } - - @Test - public void testInet4AddressToIntHTH() { - assertEquals(0, inet4AddressToIntHTH(ipv4Address("0.0.0.0"))); - assertEquals(0xff800000, inet4AddressToIntHTH(ipv4Address("255.128.0.0"))); - assertEquals(0x0aff8000, inet4AddressToIntHTH(ipv4Address("10.255.128.0"))); - assertEquals(0x0afffe00, inet4AddressToIntHTH(ipv4Address("10.255.254.0"))); - assertEquals(0xc0a8fffe, inet4AddressToIntHTH(ipv4Address("192.168.255.254"))); - assertEquals(0xc0a8ffff, inet4AddressToIntHTH(ipv4Address("192.168.255.255"))); - } - - @Test - public void testIntToInet4AddressHTH() { - assertEquals(ipv4Address("0.0.0.0"), intToInet4AddressHTH(0)); - assertEquals(ipv4Address("255.128.0.0"), intToInet4AddressHTH(0xff800000)); - assertEquals(ipv4Address("10.255.128.0"), intToInet4AddressHTH(0x0aff8000)); - assertEquals(ipv4Address("10.255.254.0"), intToInet4AddressHTH(0x0afffe00)); - assertEquals(ipv4Address("192.168.255.254"), intToInet4AddressHTH(0xc0a8fffe)); - assertEquals(ipv4Address("192.168.255.255"), intToInet4AddressHTH(0xc0a8ffff)); - } - - - @Test - public void testPrefixLengthToV4NetmaskIntHTL() { - assertEquals(0, prefixLengthToV4NetmaskIntHTL(0)); - assertEquals(0x000080ff /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTL(9)); - assertEquals(0x0080ffff /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTL(17)); - assertEquals(0x00feffff /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTL(23)); - assertEquals(0xfeffffff /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTL(31)); - assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTL(32)); - } - - @Test - public void testPrefixLengthToV4NetmaskIntHTH() { - assertEquals(0, prefixLengthToV4NetmaskIntHTH(0)); - assertEquals(0xff800000 /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTH(9)); - assertEquals(0xffff8000 /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTH(17)); - assertEquals(0xfffffe00 /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTH(23)); - assertEquals(0xfffffffe /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTH(31)); - assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTH(32)); - } - - @Test(expected = IllegalArgumentException.class) - public void testPrefixLengthToV4NetmaskIntHTH_NegativeLength() { - prefixLengthToV4NetmaskIntHTH(-1); - } - - @Test(expected = IllegalArgumentException.class) - public void testPrefixLengthToV4NetmaskIntHTH_LengthTooLarge() { - prefixLengthToV4NetmaskIntHTH(33); - } - - private void checkAddressMasking(String expectedAddr, String addr, int prefixLength) { - final int prefix = prefixLengthToV4NetmaskIntHTH(prefixLength); - final int addrInt = inet4AddressToIntHTH(ipv4Address(addr)); - assertEquals(ipv4Address(expectedAddr), intToInet4AddressHTH(prefix & addrInt)); - } - - @Test - public void testPrefixLengthToV4NetmaskIntHTH_MaskAddr() { - checkAddressMasking("192.168.0.0", "192.168.128.1", 16); - checkAddressMasking("255.240.0.0", "255.255.255.255", 12); - checkAddressMasking("255.255.255.255", "255.255.255.255", 32); - checkAddressMasking("0.0.0.0", "255.255.255.255", 0); - } - - @Test - public void testGetImplicitNetmask() { - assertEquals(8, getImplicitNetmask(ipv4Address("4.2.2.2"))); - assertEquals(8, getImplicitNetmask(ipv4Address("10.5.6.7"))); - assertEquals(16, getImplicitNetmask(ipv4Address("173.194.72.105"))); - assertEquals(16, getImplicitNetmask(ipv4Address("172.23.68.145"))); - assertEquals(24, getImplicitNetmask(ipv4Address("192.0.2.1"))); - assertEquals(24, getImplicitNetmask(ipv4Address("192.168.5.1"))); - assertEquals(32, getImplicitNetmask(ipv4Address("224.0.0.1"))); - assertEquals(32, getImplicitNetmask(ipv4Address("255.6.7.8"))); - } - - private void assertInvalidNetworkMask(Inet4Address addr) { - try { - netmaskToPrefixLength(addr); - fail("Invalid netmask " + addr.getHostAddress() + " did not cause exception"); - } catch (IllegalArgumentException expected) { - } - } - - @Test - public void testNetmaskToPrefixLength() { - assertEquals(0, netmaskToPrefixLength(ipv4Address("0.0.0.0"))); - assertEquals(9, netmaskToPrefixLength(ipv4Address("255.128.0.0"))); - assertEquals(17, netmaskToPrefixLength(ipv4Address("255.255.128.0"))); - assertEquals(23, netmaskToPrefixLength(ipv4Address("255.255.254.0"))); - assertEquals(31, netmaskToPrefixLength(ipv4Address("255.255.255.254"))); - assertEquals(32, netmaskToPrefixLength(ipv4Address("255.255.255.255"))); - - assertInvalidNetworkMask(ipv4Address("0.0.0.1")); - assertInvalidNetworkMask(ipv4Address("255.255.255.253")); - assertInvalidNetworkMask(ipv4Address("255.255.0.255")); - } - - @Test - public void testGetPrefixMaskAsAddress() { - assertEquals("255.255.240.0", getPrefixMaskAsInet4Address(20).getHostAddress()); - assertEquals("255.0.0.0", getPrefixMaskAsInet4Address(8).getHostAddress()); - assertEquals("0.0.0.0", getPrefixMaskAsInet4Address(0).getHostAddress()); - assertEquals("255.255.255.255", getPrefixMaskAsInet4Address(32).getHostAddress()); - } - - @Test - public void testGetBroadcastAddress() { - assertEquals("192.168.15.255", - getBroadcastAddress(ipv4Address("192.168.0.123"), 20).getHostAddress()); - assertEquals("192.255.255.255", - getBroadcastAddress(ipv4Address("192.168.0.123"), 8).getHostAddress()); - assertEquals("192.168.0.123", - getBroadcastAddress(ipv4Address("192.168.0.123"), 32).getHostAddress()); - assertEquals("255.255.255.255", - getBroadcastAddress(ipv4Address("192.168.0.123"), 0).getHostAddress()); - } - - @Test(expected = IllegalArgumentException.class) - public void testGetBroadcastAddress_PrefixTooLarge() { - getBroadcastAddress(ipv4Address("192.168.0.123"), 33); - } - - @Test(expected = IllegalArgumentException.class) - public void testGetBroadcastAddress_NegativePrefix() { - getBroadcastAddress(ipv4Address("192.168.0.123"), -1); - } - - @Test(expected = IllegalArgumentException.class) - public void testGetPrefixMaskAsAddress_PrefixTooLarge() { - getPrefixMaskAsInet4Address(33); - } - - @Test(expected = IllegalArgumentException.class) - public void testGetPrefixMaskAsAddress_NegativePrefix() { - getPrefixMaskAsInet4Address(-1); - } - - private Inet4Address ipv4Address(String addr) { - return (Inet4Address) InetAddresses.parseNumericAddress(addr); - } -} diff --git a/tests/net/java/android/net/shared/InitialConfigurationTest.java b/tests/net/java/android/net/shared/InitialConfigurationTest.java deleted file mode 100644 index 17f8324ed36f..000000000000 --- a/tests/net/java/android/net/shared/InitialConfigurationTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2019 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.shared; - -import static android.net.InetAddresses.parseNumericAddress; - -import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; - -import android.net.IpPrefix; -import android.net.LinkAddress; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.Arrays; -import java.util.function.Consumer; - -/** - * Tests for {@link InitialConfiguration} - */ -@RunWith(AndroidJUnit4.class) -@SmallTest -public class InitialConfigurationTest { - private InitialConfiguration mConfig; - - @Before - public void setUp() { - mConfig = new InitialConfiguration(); - mConfig.ipAddresses.addAll(Arrays.asList( - new LinkAddress(parseNumericAddress("192.168.45.45"), 16), - new LinkAddress(parseNumericAddress("2001:db8::45"), 33))); - mConfig.directlyConnectedRoutes.addAll(Arrays.asList( - new IpPrefix(parseNumericAddress("192.168.46.46"), 17), - new IpPrefix(parseNumericAddress("2001:db8::46"), 34))); - mConfig.dnsServers.addAll(Arrays.asList( - parseNumericAddress("192.168.47.47"), - parseNumericAddress("2001:db8::47"))); - // Any added InitialConfiguration field must be included in equals() to be tested properly - assertFieldCountEquals(3, InitialConfiguration.class); - } - - @Test - public void testParcelUnparcelInitialConfiguration() { - final InitialConfiguration unparceled = - InitialConfiguration.fromStableParcelable(mConfig.toStableParcelable()); - assertEquals(mConfig, unparceled); - } - - @Test - public void testEquals() { - assertEquals(mConfig, InitialConfiguration.copy(mConfig)); - - assertNotEqualsAfterChange(c -> c.ipAddresses.add( - new LinkAddress(parseNumericAddress("192.168.47.47"), 24))); - assertNotEqualsAfterChange(c -> c.directlyConnectedRoutes.add( - new IpPrefix(parseNumericAddress("192.168.46.46"), 32))); - assertNotEqualsAfterChange(c -> c.dnsServers.add(parseNumericAddress("2001:db8::49"))); - assertFieldCountEquals(3, InitialConfiguration.class); - } - - private void assertNotEqualsAfterChange(Consumer<InitialConfiguration> mutator) { - final InitialConfiguration newConfig = InitialConfiguration.copy(mConfig); - mutator.accept(newConfig); - assertNotEquals(mConfig, newConfig); - } -} diff --git a/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java b/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java deleted file mode 100644 index f9873895e4aa..000000000000 --- a/tests/net/java/android/net/shared/IpConfigurationParcelableUtilTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2019 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.shared; - -import static android.net.InetAddresses.parseNumericAddress; -import static android.net.shared.IpConfigurationParcelableUtil.fromStableParcelable; -import static android.net.shared.IpConfigurationParcelableUtil.toStableParcelable; - -import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals; - -import static org.junit.Assert.assertEquals; - -import android.net.DhcpResults; -import android.net.LinkAddress; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.net.Inet4Address; - -/** - * Tests for {@link IpConfigurationParcelableUtil}. - */ -@RunWith(AndroidJUnit4.class) -@SmallTest -public class IpConfigurationParcelableUtilTest { - private DhcpResults mDhcpResults; - - @Before - public void setUp() { - mDhcpResults = new DhcpResults(); - mDhcpResults.ipAddress = new LinkAddress(parseNumericAddress("2001:db8::42"), 64); - mDhcpResults.gateway = parseNumericAddress("192.168.42.42"); - mDhcpResults.dnsServers.add(parseNumericAddress("2001:db8::43")); - mDhcpResults.dnsServers.add(parseNumericAddress("192.168.43.43")); - mDhcpResults.domains = "example.com"; - mDhcpResults.serverAddress = (Inet4Address) parseNumericAddress("192.168.44.44"); - mDhcpResults.vendorInfo = "TEST_VENDOR_INFO"; - mDhcpResults.leaseDuration = 3600; - mDhcpResults.serverHostName = "dhcp.example.com"; - mDhcpResults.mtu = 1450; - // Any added DhcpResults field must be included in equals() to be tested properly - assertFieldCountEquals(9, DhcpResults.class); - } - - @Test - public void testParcelUnparcelDhcpResults() { - doDhcpResultsParcelUnparcelTest(); - } - - @Test - public void testParcelUnparcelDhcpResults_NullIpAddress() { - mDhcpResults.ipAddress = null; - doDhcpResultsParcelUnparcelTest(); - } - - @Test - public void testParcelUnparcelDhcpResults_NullGateway() { - mDhcpResults.gateway = null; - doDhcpResultsParcelUnparcelTest(); - } - - @Test - public void testParcelUnparcelDhcpResults_NullDomains() { - mDhcpResults.domains = null; - doDhcpResultsParcelUnparcelTest(); - } - - @Test - public void testParcelUnparcelDhcpResults_EmptyDomains() { - mDhcpResults.domains = ""; - doDhcpResultsParcelUnparcelTest(); - } - - @Test - public void testParcelUnparcelDhcpResults_NullServerAddress() { - mDhcpResults.serverAddress = null; - doDhcpResultsParcelUnparcelTest(); - } - - @Test - public void testParcelUnparcelDhcpResults_NullVendorInfo() { - mDhcpResults.vendorInfo = null; - doDhcpResultsParcelUnparcelTest(); - } - - @Test - public void testParcelUnparcelDhcpResults_NullServerHostName() { - mDhcpResults.serverHostName = null; - doDhcpResultsParcelUnparcelTest(); - } - - private void doDhcpResultsParcelUnparcelTest() { - final DhcpResults unparceled = fromStableParcelable(toStableParcelable(mDhcpResults)); - assertEquals(mDhcpResults, unparceled); - } -} diff --git a/tests/net/java/android/net/shared/ProvisioningConfigurationTest.java b/tests/net/java/android/net/shared/ProvisioningConfigurationTest.java deleted file mode 100644 index 7079a28dce03..000000000000 --- a/tests/net/java/android/net/shared/ProvisioningConfigurationTest.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) 2019 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.shared; - -import static android.net.InetAddresses.parseNumericAddress; -import static android.net.shared.ProvisioningConfiguration.fromStableParcelable; - -import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; - -import android.net.LinkAddress; -import android.net.Network; -import android.net.StaticIpConfiguration; -import android.net.apf.ApfCapabilities; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.function.Consumer; - -/** - * Tests for {@link ProvisioningConfiguration}. - */ -@RunWith(AndroidJUnit4.class) -@SmallTest -public class ProvisioningConfigurationTest { - private ProvisioningConfiguration mConfig; - - @Before - public void setUp() { - mConfig = new ProvisioningConfiguration(); - mConfig.mEnableIPv4 = true; - mConfig.mEnableIPv6 = true; - mConfig.mUsingMultinetworkPolicyTracker = true; - mConfig.mUsingIpReachabilityMonitor = true; - mConfig.mRequestedPreDhcpActionMs = 42; - mConfig.mInitialConfig = new InitialConfiguration(); - mConfig.mInitialConfig.ipAddresses.add( - new LinkAddress(parseNumericAddress("192.168.42.42"), 24)); - mConfig.mStaticIpConfig = new StaticIpConfiguration(); - mConfig.mStaticIpConfig.ipAddress = - new LinkAddress(parseNumericAddress("2001:db8::42"), 90); - // Not testing other InitialConfig or StaticIpConfig members: they have their own unit tests - mConfig.mApfCapabilities = new ApfCapabilities(1, 2, 3); - mConfig.mProvisioningTimeoutMs = 4200; - mConfig.mIPv6AddrGenMode = 123; - mConfig.mNetwork = new Network(321); - mConfig.mDisplayName = "test_config"; - // Any added field must be included in equals() to be tested properly - assertFieldCountEquals(12, ProvisioningConfiguration.class); - } - - @Test - public void testParcelUnparcel() { - doParcelUnparcelTest(); - } - - @Test - public void testParcelUnparcel_NullInitialConfiguration() { - mConfig.mInitialConfig = null; - doParcelUnparcelTest(); - } - - @Test - public void testParcelUnparcel_NullStaticConfiguration() { - mConfig.mStaticIpConfig = null; - doParcelUnparcelTest(); - } - - @Test - public void testParcelUnparcel_NullApfCapabilities() { - mConfig.mApfCapabilities = null; - doParcelUnparcelTest(); - } - - @Test - public void testParcelUnparcel_NullNetwork() { - mConfig.mNetwork = null; - doParcelUnparcelTest(); - } - - private void doParcelUnparcelTest() { - final ProvisioningConfiguration unparceled = - fromStableParcelable(mConfig.toStableParcelable()); - assertEquals(mConfig, unparceled); - } - - @Test - public void testEquals() { - assertEquals(mConfig, new ProvisioningConfiguration(mConfig)); - - assertNotEqualsAfterChange(c -> c.mEnableIPv4 = false); - assertNotEqualsAfterChange(c -> c.mEnableIPv6 = false); - assertNotEqualsAfterChange(c -> c.mUsingMultinetworkPolicyTracker = false); - assertNotEqualsAfterChange(c -> c.mUsingIpReachabilityMonitor = false); - assertNotEqualsAfterChange(c -> c.mRequestedPreDhcpActionMs++); - assertNotEqualsAfterChange(c -> c.mInitialConfig.ipAddresses.add( - new LinkAddress(parseNumericAddress("192.168.47.47"), 16))); - assertNotEqualsAfterChange(c -> c.mInitialConfig = null); - assertNotEqualsAfterChange(c -> c.mStaticIpConfig.ipAddress = - new LinkAddress(parseNumericAddress("2001:db8::47"), 64)); - assertNotEqualsAfterChange(c -> c.mStaticIpConfig = null); - assertNotEqualsAfterChange(c -> c.mApfCapabilities = new ApfCapabilities(4, 5, 6)); - assertNotEqualsAfterChange(c -> c.mApfCapabilities = null); - assertNotEqualsAfterChange(c -> c.mProvisioningTimeoutMs++); - assertNotEqualsAfterChange(c -> c.mIPv6AddrGenMode++); - assertNotEqualsAfterChange(c -> c.mNetwork = new Network(123)); - assertNotEqualsAfterChange(c -> c.mNetwork = null); - assertNotEqualsAfterChange(c -> c.mDisplayName = "other_test"); - assertNotEqualsAfterChange(c -> c.mDisplayName = null); - assertFieldCountEquals(12, ProvisioningConfiguration.class); - } - - private void assertNotEqualsAfterChange(Consumer<ProvisioningConfiguration> mutator) { - final ProvisioningConfiguration newConfig = new ProvisioningConfiguration(mConfig); - mutator.accept(newConfig); - assertNotEquals(mConfig, newConfig); - } -} diff --git a/tests/net/java/android/net/util/InterfaceParamsTest.java b/tests/net/java/android/net/util/InterfaceParamsTest.java deleted file mode 100644 index 141455cb179a..000000000000 --- a/tests/net/java/android/net/util/InterfaceParamsTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2017 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.util; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class InterfaceParamsTest { - @Test - public void testNullInterfaceReturnsNull() { - assertNull(InterfaceParams.getByName(null)); - } - - @Test - public void testNonExistentInterfaceReturnsNull() { - assertNull(InterfaceParams.getByName("doesnotexist0")); - } - - @Test - public void testLoopback() { - final InterfaceParams ifParams = InterfaceParams.getByName("lo"); - assertNotNull(ifParams); - assertEquals("lo", ifParams.name); - assertTrue(ifParams.index > 0); - assertNotNull(ifParams.macAddr); - assertTrue(ifParams.defaultMtu >= NetworkConstants.ETHER_MTU); - } -} diff --git a/tests/net/java/android/net/util/SharedLogTest.java b/tests/net/java/android/net/util/SharedLogTest.java deleted file mode 100644 index e1dba3677121..000000000000 --- a/tests/net/java/android/net/util/SharedLogTest.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2017 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.util; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.io.ByteArrayOutputStream; -import java.io.PrintWriter; - -@RunWith(AndroidJUnit4.class) -@SmallTest -public class SharedLogTest { - private static final String TIMESTAMP_PATTERN = "\\d{2}:\\d{2}:\\d{2}"; - private static final String TIMESTAMP = "HH:MM:SS"; - - @Test - public void testBasicOperation() { - final SharedLog logTop = new SharedLog("top"); - logTop.mark("first post!"); - - final SharedLog logLevel2a = logTop.forSubComponent("twoA"); - final SharedLog logLevel2b = logTop.forSubComponent("twoB"); - logLevel2b.e("2b or not 2b"); - logLevel2b.e("No exception", null); - logLevel2b.e("Wait, here's one", new Exception("Test")); - logLevel2a.w("second post?"); - - final SharedLog logLevel3 = logLevel2a.forSubComponent("three"); - logTop.log("still logging"); - logLevel3.log("3 >> 2"); - logLevel2a.mark("ok: last post"); - - final String[] expected = { - " - MARK first post!", - " - [twoB] ERROR 2b or not 2b", - " - [twoB] ERROR No exception", - // No stacktrace in shared log, only in logcat - " - [twoB] ERROR Wait, here's one: Test", - " - [twoA] WARN second post?", - " - still logging", - " - [twoA.three] 3 >> 2", - " - [twoA] MARK ok: last post", - }; - // Verify the logs are all there and in the correct order. - verifyLogLines(expected, logTop); - - // In fact, because they all share the same underlying LocalLog, - // every subcomponent SharedLog's dump() is identical. - verifyLogLines(expected, logLevel2a); - verifyLogLines(expected, logLevel2b); - verifyLogLines(expected, logLevel3); - } - - private static void verifyLogLines(String[] expected, SharedLog log) { - final ByteArrayOutputStream ostream = new ByteArrayOutputStream(); - final PrintWriter pw = new PrintWriter(ostream, true); - log.dump(null, pw, null); - - final String dumpOutput = ostream.toString(); - assertTrue(dumpOutput != null); - assertTrue(!"".equals(dumpOutput)); - - final String[] lines = dumpOutput.split("\n"); - assertEquals(expected.length, lines.length); - - for (int i = 0; i < expected.length; i++) { - String got = lines[i]; - String want = expected[i]; - assertTrue(String.format("'%s' did not contain '%s'", got, want), got.endsWith(want)); - assertTrue(String.format("'%s' did not contain a %s timestamp", got, TIMESTAMP), - got.replaceFirst(TIMESTAMP_PATTERN, TIMESTAMP).contains(TIMESTAMP)); - } - } -} diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index aad2f3da40f2..7ea9bcf36f91 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -16,6 +16,9 @@ package com.android.server; +import static android.Manifest.permission.CHANGE_NETWORK_STATE; +import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; +import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.MATCH_ANY_USER; import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN; @@ -2000,9 +2003,17 @@ public class ConnectivityServiceTest { mCm.unregisterNetworkCallback(trackDefaultCallback); } + private void grantUsingBackgroundNetworksPermissionForUid(final int uid) throws Exception { + final String testPackageName = mContext.getPackageName(); + when(mPackageManager.getPackageInfo(eq(testPackageName), eq(GET_PERMISSIONS))) + .thenReturn(buildPackageInfo(true, uid)); + mService.mPermissionMonitor.onPackageAdded(testPackageName, uid); + } + @Test public void testNetworkGoesIntoBackgroundAfterLinger() throws Exception { setAlwaysOnNetworks(true); + grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid()); NetworkRequest request = new NetworkRequest.Builder() .clearCapabilities() .build(); @@ -3077,6 +3088,7 @@ public class ConnectivityServiceTest { // Create a background request. We can't do this ourselves because ConnectivityService // doesn't have an API for it. So just turn on mobile data always on. setAlwaysOnNetworks(true); + grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid()); final NetworkRequest request = new NetworkRequest.Builder().build(); final NetworkRequest fgRequest = new NetworkRequest.Builder() .addCapability(NET_CAPABILITY_FOREGROUND).build(); @@ -3223,6 +3235,7 @@ public class ConnectivityServiceTest { @Test public void testMobileDataAlwaysOn() throws Exception { + grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid()); final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback(); final NetworkRequest cellRequest = new NetworkRequest.Builder() .addTransportType(TRANSPORT_CELLULAR).build(); @@ -6176,7 +6189,14 @@ public class ConnectivityServiceTest { private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid) { final PackageInfo packageInfo = new PackageInfo(); - packageInfo.requestedPermissions = new String[0]; + if (hasSystemPermission) { + packageInfo.requestedPermissions = new String[] { + CHANGE_NETWORK_STATE, CONNECTIVITY_USE_RESTRICTED_NETWORKS }; + packageInfo.requestedPermissionsFlags = new int[] { + REQUESTED_PERMISSION_GRANTED, REQUESTED_PERMISSION_GRANTED }; + } else { + packageInfo.requestedPermissions = new String[0]; + } packageInfo.applicationInfo = new ApplicationInfo(); packageInfo.applicationInfo.privateFlags = 0; packageInfo.applicationInfo.uid = UserHandle.getUid(UserHandle.USER_SYSTEM, diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java index 95807638f6c4..d57f2250fc5c 100644 --- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java +++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java @@ -20,6 +20,7 @@ import static com.android.server.connectivity.NetworkNotificationManager.Notific import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -40,6 +41,7 @@ import android.telephony.TelephonyManager; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.internal.R; import com.android.server.connectivity.NetworkNotificationManager.NotificationType; import org.junit.Before; @@ -60,12 +62,19 @@ public class NetworkNotificationManagerTest { static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities(); static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities(); + static final NetworkCapabilities VPN_CAPABILITIES = new NetworkCapabilities(); static { CELL_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); CELL_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); WIFI_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); WIFI_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + + // Set the underyling network to wifi. + VPN_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); + VPN_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_VPN); + VPN_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + VPN_CAPABILITIES.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); } @Mock Context mCtx; @@ -75,6 +84,7 @@ public class NetworkNotificationManagerTest { @Mock NotificationManager mNotificationManager; @Mock NetworkAgentInfo mWifiNai; @Mock NetworkAgentInfo mCellNai; + @Mock NetworkAgentInfo mVpnNai; @Mock NetworkInfo mNetworkInfo; ArgumentCaptor<Notification> mCaptor; @@ -88,6 +98,9 @@ public class NetworkNotificationManagerTest { mWifiNai.networkInfo = mNetworkInfo; mCellNai.networkCapabilities = CELL_CAPABILITIES; mCellNai.networkInfo = mNetworkInfo; + mVpnNai.networkCapabilities = VPN_CAPABILITIES; + mVpnNai.networkInfo = mNetworkInfo; + doReturn(true).when(mVpnNai).isVPN(); when(mCtx.getResources()).thenReturn(mResources); when(mCtx.getPackageManager()).thenReturn(mPm); when(mCtx.getApplicationInfo()).thenReturn(new ApplicationInfo()); @@ -97,6 +110,35 @@ public class NetworkNotificationManagerTest { mManager = new NetworkNotificationManager(mCtx, mTelephonyManager, mNotificationManager); } + private void verifyTitleByNetwork(final int id, final NetworkAgentInfo nai, final int title) { + final String tag = NetworkNotificationManager.tagFor(id); + mManager.showNotification(id, PRIVATE_DNS_BROKEN, nai, null, null, true); + verify(mNotificationManager, times(1)) + .notifyAsUser(eq(tag), eq(PRIVATE_DNS_BROKEN.eventId), any(), any()); + final int transportType = NetworkNotificationManager.approximateTransportType(nai); + if (transportType == NetworkCapabilities.TRANSPORT_WIFI) { + verify(mResources, times(1)).getString(title, eq(any())); + } else { + verify(mResources, times(1)).getString(title); + } + verify(mResources, times(1)).getString(R.string.private_dns_broken_detailed); + } + + @Test + public void testTitleOfPrivateDnsBroken() { + // Test the title of mobile data. + verifyTitleByNetwork(100, mCellNai, R.string.mobile_no_internet); + reset(mResources); + + // Test the title of wifi. + verifyTitleByNetwork(101, mWifiNai, R.string.wifi_no_internet); + reset(mResources); + + // Test the title of other networks. + verifyTitleByNetwork(102, mVpnNai, R.string.other_networks_no_internet); + reset(mResources); + } + @Test public void testNotificationsShownAndCleared() { final int NETWORK_ID_BASE = 100; diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java index 3fdba6eac55d..2738daaa53a8 100644 --- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java @@ -27,6 +27,7 @@ import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_OEM; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR; import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; +import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_REQUIRED; import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.MATCH_ANY_USER; import static android.os.Process.SYSTEM_UID; @@ -36,6 +37,7 @@ import static com.android.server.connectivity.PermissionMonitor.SYSTEM; import static junit.framework.Assert.fail; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -102,7 +104,6 @@ public class PermissionMonitorTest { private static final String MOCK_PACKAGE2 = "appName2"; private static final String SYSTEM_PACKAGE1 = "sysName1"; private static final String SYSTEM_PACKAGE2 = "sysName2"; - private static final String VPN_PACKAGE = "vpnApp"; private static final String PARTITION_SYSTEM = "system"; private static final String PARTITION_OEM = "oem"; private static final String PARTITION_PRODUCT = "product"; @@ -145,28 +146,31 @@ public class PermissionMonitorTest { mObserver = observerCaptor.getValue(); } - private boolean hasBgPermission(String partition, int targetSdkVersion, int uid, - String... permission) throws Exception { - final PackageInfo packageInfo = packageInfoWithPermissions(permission, partition); + private boolean hasRestrictedNetworkPermission(String partition, int targetSdkVersion, int uid, + String... permissions) { + final PackageInfo packageInfo = + packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, permissions, partition); packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion; packageInfo.applicationInfo.uid = uid; - when(mPackageManager.getPackageInfoAsUser( - eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS), anyInt())).thenReturn(packageInfo); - when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[] {MOCK_PACKAGE1}); - return mPermissionMonitor.hasUseBackgroundNetworksPermission(uid); + return mPermissionMonitor.hasRestrictedNetworkPermission(packageInfo); } - private static PackageInfo packageInfoWithPermissions(String[] permissions, String partition) { + private static PackageInfo systemPackageInfoWithPermissions(String... permissions) { + return packageInfoWithPermissions( + REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM); + } + + private static PackageInfo vendorPackageInfoWithPermissions(String... permissions) { + return packageInfoWithPermissions( + REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_VENDOR); + } + + private static PackageInfo packageInfoWithPermissions(int permissionsFlags, + String[] permissions, String partition) { int[] requestedPermissionsFlags = new int[permissions.length]; for (int i = 0; i < permissions.length; i++) { - requestedPermissionsFlags[i] = REQUESTED_PERMISSION_GRANTED; + requestedPermissionsFlags[i] = permissionsFlags; } - return packageInfoWithPermissions(permissions, partition, - requestedPermissionsFlags); - } - - private static PackageInfo packageInfoWithPermissions(String[] permissions, String partition, - int[] requestedPermissionsFlags) { final PackageInfo packageInfo = new PackageInfo(); packageInfo.requestedPermissions = permissions; packageInfo.applicationInfo = new ApplicationInfo(); @@ -190,12 +194,10 @@ public class PermissionMonitorTest { private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid, int userId) { final PackageInfo pkgInfo; if (hasSystemPermission) { - final String[] systemPermissions = new String[]{ - CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS - }; - pkgInfo = packageInfoWithPermissions(systemPermissions, PARTITION_SYSTEM); + pkgInfo = systemPackageInfoWithPermissions( + CHANGE_NETWORK_STATE, NETWORK_STACK, CONNECTIVITY_USE_RESTRICTED_NETWORKS); } else { - pkgInfo = packageInfoWithPermissions(new String[] {}, ""); + pkgInfo = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, new String[] {}, ""); } pkgInfo.applicationInfo.uid = UserHandle.getUid(userId, UserHandle.getAppId(uid)); return pkgInfo; @@ -203,82 +205,151 @@ public class PermissionMonitorTest { @Test public void testHasPermission() { - PackageInfo app = packageInfoWithPermissions(new String[] {}, PARTITION_SYSTEM); + PackageInfo app = systemPackageInfoWithPermissions(); assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE)); assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK)); assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL)); - app = packageInfoWithPermissions(new String[] { - CHANGE_NETWORK_STATE, NETWORK_STACK - }, PARTITION_SYSTEM); + app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE, NETWORK_STACK); assertTrue(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE)); assertTrue(mPermissionMonitor.hasPermission(app, NETWORK_STACK)); assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL)); - app = packageInfoWithPermissions(new String[] { - CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL - }, PARTITION_SYSTEM); + app = systemPackageInfoWithPermissions( + CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL); assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE)); assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK)); assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL)); + + app = packageInfoWithPermissions(REQUESTED_PERMISSION_REQUIRED, new String[] { + CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL, NETWORK_STACK }, + PARTITION_SYSTEM); + assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE)); + assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK)); + assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); + assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL)); + + app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE); + app.requestedPermissions = null; + assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE)); + + app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE); + app.requestedPermissionsFlags = null; + assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE)); } @Test public void testIsVendorApp() { - PackageInfo app = packageInfoWithPermissions(new String[] {}, PARTITION_SYSTEM); + PackageInfo app = systemPackageInfoWithPermissions(); assertFalse(mPermissionMonitor.isVendorApp(app.applicationInfo)); - app = packageInfoWithPermissions(new String[] {}, PARTITION_OEM); + app = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, + new String[] {}, PARTITION_OEM); assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo)); - app = packageInfoWithPermissions(new String[] {}, PARTITION_PRODUCT); + app = packageInfoWithPermissions(REQUESTED_PERMISSION_GRANTED, + new String[] {}, PARTITION_PRODUCT); assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo)); - app = packageInfoWithPermissions(new String[] {}, PARTITION_VENDOR); + app = vendorPackageInfoWithPermissions(); assertTrue(mPermissionMonitor.isVendorApp(app.applicationInfo)); } @Test - public void testHasUseBackgroundNetworksPermission() throws Exception { - assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1)); - assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE)); - assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, NETWORK_STACK)); - assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL)); - assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, - CONNECTIVITY_USE_RESTRICTED_NETWORKS)); - assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE)); - - assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1)); - assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE)); + public void testHasNetworkPermission() { + PackageInfo app = systemPackageInfoWithPermissions(); + assertFalse(mPermissionMonitor.hasNetworkPermission(app)); + app = systemPackageInfoWithPermissions(CHANGE_NETWORK_STATE); + assertTrue(mPermissionMonitor.hasNetworkPermission(app)); + app = systemPackageInfoWithPermissions(NETWORK_STACK); + assertFalse(mPermissionMonitor.hasNetworkPermission(app)); + app = systemPackageInfoWithPermissions(CONNECTIVITY_USE_RESTRICTED_NETWORKS); + assertFalse(mPermissionMonitor.hasNetworkPermission(app)); } @Test - public void testHasUseBackgroundNetworksPermissionSystemUid() throws Exception { + public void testHasRestrictedNetworkPermission() { + assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1)); + assertFalse(hasRestrictedNetworkPermission( + PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE)); + assertTrue(hasRestrictedNetworkPermission( + PARTITION_SYSTEM, VERSION_P, MOCK_UID1, NETWORK_STACK)); + assertTrue(hasRestrictedNetworkPermission( + PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL)); + assertTrue(hasRestrictedNetworkPermission( + PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); + assertFalse(hasRestrictedNetworkPermission( + PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE)); + + assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1)); + assertFalse(hasRestrictedNetworkPermission( + PARTITION_SYSTEM, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE)); + } + + @Test + public void testHasRestrictedNetworkPermissionSystemUid() { doReturn(VERSION_P).when(mPermissionMonitor).getDeviceFirstSdkInt(); - assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID)); - assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CHANGE_WIFI_STATE)); - assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, - CONNECTIVITY_USE_RESTRICTED_NETWORKS)); + assertTrue(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID)); + assertTrue(hasRestrictedNetworkPermission( + PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CHANGE_WIFI_STATE)); + assertTrue(hasRestrictedNetworkPermission( + PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); doReturn(VERSION_Q).when(mPermissionMonitor).getDeviceFirstSdkInt(); - assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID)); - assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CHANGE_WIFI_STATE)); - assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, - CONNECTIVITY_USE_RESTRICTED_NETWORKS)); + assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID)); + assertFalse(hasRestrictedNetworkPermission( + PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CHANGE_WIFI_STATE)); + assertTrue(hasRestrictedNetworkPermission( + PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); } @Test - public void testHasUseBackgroundNetworksPermissionVendorApp() throws Exception { - assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1)); - assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE)); - assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, NETWORK_STACK)); - assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL)); - assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, - CONNECTIVITY_USE_RESTRICTED_NETWORKS)); - assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE)); - - assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1)); - assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE)); + public void testHasRestrictedNetworkPermissionVendorApp() { + assertTrue(hasRestrictedNetworkPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1)); + assertTrue(hasRestrictedNetworkPermission( + PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE)); + assertTrue(hasRestrictedNetworkPermission( + PARTITION_VENDOR, VERSION_P, MOCK_UID1, NETWORK_STACK)); + assertTrue(hasRestrictedNetworkPermission( + PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL)); + assertTrue(hasRestrictedNetworkPermission( + PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); + assertTrue(hasRestrictedNetworkPermission( + PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE)); + + assertFalse(hasRestrictedNetworkPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1)); + assertFalse(hasRestrictedNetworkPermission( + PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE)); + assertFalse(hasRestrictedNetworkPermission( + PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_NETWORK_STATE)); + } + + private void assertBackgroundPermission(boolean hasPermission, String name, int uid, + String... permissions) throws Exception { + when(mPackageManager.getPackageInfo(eq(name), anyInt())) + .thenReturn(packageInfoWithPermissions( + REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM)); + mPermissionMonitor.onPackageAdded(name, uid); + assertEquals(hasPermission, mPermissionMonitor.hasUseBackgroundNetworksPermission(uid)); + } + + @Test + public void testHasUseBackgroundNetworksPermission() throws Exception { + assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(SYSTEM_UID)); + assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID); + assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID, CHANGE_WIFI_STATE); + assertBackgroundPermission(true, SYSTEM_PACKAGE1, SYSTEM_UID, CHANGE_NETWORK_STATE); + assertBackgroundPermission(true, SYSTEM_PACKAGE1, SYSTEM_UID, NETWORK_STACK); + + assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID1)); + assertBackgroundPermission(false, MOCK_PACKAGE1, MOCK_UID1); + assertBackgroundPermission(true, MOCK_PACKAGE1, MOCK_UID1, + CONNECTIVITY_USE_RESTRICTED_NETWORKS); + + assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID2)); + assertBackgroundPermission(false, MOCK_PACKAGE2, MOCK_UID2); + assertBackgroundPermission(true, MOCK_PACKAGE2, MOCK_UID2, + CONNECTIVITY_INTERNAL); } private class NetdMonitor { @@ -563,7 +634,8 @@ public class PermissionMonitorTest { private PackageInfo setPackagePermissions(String packageName, int uid, String[] permissions) throws Exception { - PackageInfo packageInfo = packageInfoWithPermissions(permissions, PARTITION_SYSTEM); + PackageInfo packageInfo = packageInfoWithPermissions( + REQUESTED_PERMISSION_GRANTED, permissions, PARTITION_SYSTEM); when(mPackageManager.getPackageInfo(eq(packageName), anyInt())).thenReturn(packageInfo); when(mPackageManager.getPackagesForUid(eq(uid))).thenReturn(new String[]{packageName}); return packageInfo; @@ -599,7 +671,7 @@ public class PermissionMonitorTest { // Install another package with the same uid and no permissions should not cause the UID to // lose permissions. - PackageInfo packageInfo2 = packageInfoWithPermissions(new String[]{}, PARTITION_SYSTEM); + PackageInfo packageInfo2 = systemPackageInfoWithPermissions(); when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2); when(mPackageManager.getPackagesForUid(MOCK_UID1)) .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2}); @@ -660,8 +732,7 @@ public class PermissionMonitorTest { | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1}); // Mock another package with the same uid but different permissions. - PackageInfo packageInfo2 = packageInfoWithPermissions(new String[] {INTERNET}, - PARTITION_SYSTEM); + PackageInfo packageInfo2 = systemPackageInfoWithPermissions(INTERNET); when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2); when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{ MOCK_PACKAGE2}); diff --git a/wifi/java/android/net/wifi/IScanResultsCallback.aidl b/wifi/java/android/net/wifi/IScanResultsCallback.aidl new file mode 100644 index 000000000000..56f602510fd9 --- /dev/null +++ b/wifi/java/android/net/wifi/IScanResultsCallback.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2019 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; + +/** + * Interface for Wi-Fi scan result available callback. + * + * @hide + */ +oneway interface IScanResultsCallback +{ + void onScanResultsAvailable(); +} diff --git a/wifi/java/android/net/wifi/IScanResultsListener.aidl b/wifi/java/android/net/wifi/IScanResultsListener.aidl index bec74a620380..e7eaddd712c9 100644 --- a/wifi/java/android/net/wifi/IScanResultsListener.aidl +++ b/wifi/java/android/net/wifi/IScanResultsListener.aidl @@ -16,11 +16,8 @@ package android.net.wifi; -/** - * Interface for Wi-Fi scan result available callback. - * - * @hide - */ +/** @hide */ + oneway interface IScanResultsListener { void onScanResultsAvailable(); diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index bbb85440f729..4a89c66dd0a0 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -28,7 +28,7 @@ import android.net.wifi.IActionListener; import android.net.wifi.IDppCallback; import android.net.wifi.ILocalOnlyHotspotCallback; import android.net.wifi.INetworkRequestMatchCallback; -import android.net.wifi.IScanResultsListener; +import android.net.wifi.IScanResultsCallback; import android.net.wifi.ISoftApCallback; import android.net.wifi.ISuggestionConnectionStatusListener; import android.net.wifi.ITrafficStateCallback; @@ -161,8 +161,6 @@ interface IWifiManager boolean setWifiApConfiguration(in WifiConfiguration wifiConfig, String packageName); - void notifyUserOfApBandConversion(String packageName); - void enableTdls(String remoteIPAddress, boolean enable); void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable); @@ -235,11 +233,13 @@ interface IWifiManager oneway void getTxPacketCount(String packageName, in IBinder binder, in ITxPacketCountListener listener, int callbackIdentifier); - void registerScanResultsListener(in IBinder binder, in IScanResultsListener Listener, int listenerIdentifier); + void registerScanResultsCallback(in IScanResultsCallback callback); - void unregisterScanResultsListener(int listenerIdentifier); + void unregisterScanResultsCallback(in IScanResultsCallback callback); void registerSuggestionConnectionStatusListener(in IBinder binder, in ISuggestionConnectionStatusListener listener, int listenerIdentifier, String packageName, String featureId); void unregisterSuggestionConnectionStatusListener(int listenerIdentifier, String packageName); + + int calculateSignalLevel(int rssi); } diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java index 6a03c73bc3f9..73c52ab0ab1b 100644 --- a/wifi/java/android/net/wifi/RttManager.java +++ b/wifi/java/android/net/wifi/RttManager.java @@ -1212,7 +1212,7 @@ public class RttManager { * * @hide */ - public RttManager(Context context, WifiRttManager service) { + public RttManager(@NonNull Context context, @NonNull WifiRttManager service) { mNewService = service; mContext = context; diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index f7d2b40e1ea0..dfdc075043f6 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -38,6 +38,7 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.BackupUtils; import android.util.Log; +import android.util.SparseArray; import android.util.TimeUtils; import java.io.ByteArrayOutputStream; @@ -86,7 +87,12 @@ public class WifiConfiguration implements Parcelable { public static final String pmfVarName = "ieee80211w"; /** {@hide} */ public static final String updateIdentiferVarName = "update_identifier"; - /** {@hide} */ + /** + * The network ID for an invalid network. + * + * @hide + */ + @SystemApi public static final int INVALID_NETWORK_ID = -1; /** {@hide} */ public static final int LOCAL_ONLY_NETWORK_ID = -2; @@ -102,20 +108,41 @@ public class WifiConfiguration implements Parcelable { public static class KeyMgmt { private KeyMgmt() { } + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + NONE, + WPA_PSK, + WPA_EAP, + IEEE8021X, + WPA2_PSK, + OSEN, + FT_PSK, + FT_EAP, + SAE, + OWE, + SUITE_B_192, + WPA_PSK_SHA256, + WPA_EAP_SHA256}) + public @interface KeyMgmtScheme {} + /** WPA is not used; plaintext or static WEP could be used. */ public static final int NONE = 0; /** WPA pre-shared key (requires {@code preSharedKey} to be specified). */ public static final int WPA_PSK = 1; /** WPA using EAP authentication. Generally used with an external authentication server. */ public static final int WPA_EAP = 2; - /** IEEE 802.1X using EAP authentication and (optionally) dynamically - * generated WEP keys. */ + /** + * IEEE 802.1X using EAP authentication and (optionally) dynamically + * generated WEP keys. + */ public static final int IEEE8021X = 3; - /** WPA2 pre-shared key for use with soft access point - * (requires {@code preSharedKey} to be specified). - * @hide - */ + /** + * WPA2 pre-shared key for use with soft access point + * (requires {@code preSharedKey} to be specified). + * @hide + */ @SystemApi public static final int WPA2_PSK = 4; /** @@ -384,7 +411,12 @@ public class WifiConfiguration implements Parcelable { public void setSecurityParams(@SecurityType int securityType) { // Clear all the bitsets. allowedKeyManagement.clear(); + allowedProtocols.clear(); allowedAuthAlgorithms.clear(); + allowedPairwiseCiphers.clear(); + allowedGroupCiphers.clear(); + allowedGroupManagementCiphers.clear(); + allowedSuiteBCiphers.clear(); switch (securityType) { case SECURITY_TYPE_OPEN: @@ -407,9 +439,6 @@ public class WifiConfiguration implements Parcelable { requirePMF = true; break; case SECURITY_TYPE_EAP_SUITE_B: - allowedGroupCiphers.clear(); - allowedGroupManagementCiphers.clear(); - allowedSuiteBCiphers.clear(); allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192); allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256); allowedGroupManagementCiphers.set(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256); @@ -460,16 +489,26 @@ public class WifiConfiguration implements Parcelable { */ public String BSSID; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"AP_BAND_"}, value = { + AP_BAND_2GHZ, + AP_BAND_5GHZ, + AP_BAND_ANY}) + public @interface ApBand {} + /** * 2GHz band. * @hide */ + @SystemApi public static final int AP_BAND_2GHZ = 0; /** * 5GHz band. * @hide */ + @SystemApi public static final int AP_BAND_5GHZ = 1; /** @@ -477,15 +516,18 @@ public class WifiConfiguration implements Parcelable { * operating country code and current radio conditions. * @hide */ + @SystemApi public static final int AP_BAND_ANY = -1; /** - * The band which AP resides on - * -1:Any 0:2G 1:5G - * By default, 2G is chosen + * The band which the AP resides on. + * One of {@link #AP_BAND_2GHZ}, {@link #AP_BAND_5GHZ}, or {@link #AP_BAND_ANY}. + * By default, {@link #AP_BAND_2GHZ} is chosen. + * * @hide */ - @UnsupportedAppUsage + @SystemApi + @ApBand public int apBand = AP_BAND_2GHZ; /** @@ -513,6 +555,7 @@ public class WifiConfiguration implements Parcelable { * Optional SAE Password Id for use with WPA3-SAE. It is an ASCII string. * @hide */ + @SystemApi public @Nullable String saePasswordId; /** @@ -551,9 +594,10 @@ public class WifiConfiguration implements Parcelable { public boolean hiddenSSID; /** - * This is a network that requries Protected Management Frames (PMF). + * True if the network requires Protected Management Frames (PMF), false otherwise. * @hide */ + @SystemApi public boolean requirePMF; /** @@ -641,11 +685,12 @@ public class WifiConfiguration implements Parcelable { public long[] roamingConsortiumIds; /** + * True if this network configuration is visible to and usable by other users on the + * same device, false otherwise. + * * @hide - * This network configuration is visible to and usable by other users on the - * same device. */ - @UnsupportedAppUsage + @SystemApi public boolean shared; /** @@ -738,54 +783,16 @@ public class WifiConfiguration implements Parcelable { /** * @hide - * Status of user approval for connection - */ - public int userApproved = USER_UNSPECIFIED; - - /** - * @hide * Auto-join is allowed by user for this network. * Default true. */ @SystemApi public boolean allowAutojoin = true; - /** The Below RSSI thresholds are used to configure AutoJoin - * - GOOD/LOW/BAD thresholds are used so as to calculate link score - * - UNWANTED_SOFT are used by the blacklisting logic so as to handle - * the unwanted network message coming from CS - * - UNBLACKLIST thresholds are used so as to tweak the speed at which - * the network is unblacklisted (i.e. if - * it is seen with good RSSI, it is blacklisted faster) - * - INITIAL_AUTOJOIN_ATTEMPT, used to determine how close from - * the network we need to be before autojoin kicks in - */ /** @hide **/ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public static int INVALID_RSSI = -127; - // States for the userApproved field - /** - * @hide - * User hasn't specified if connection is okay - */ - public static final int USER_UNSPECIFIED = 0; - /** - * @hide - * User has approved this for connection - */ - public static final int USER_APPROVED = 1; - /** - * @hide - * User has banned this from connection - */ - public static final int USER_BANNED = 2; - /** - * @hide - * Waiting for user input - */ - public static final int USER_PENDING = 3; - /** * @hide * Number of reports indicating no Internet Access @@ -859,21 +866,13 @@ public class WifiConfiguration implements Parcelable { * This boolean is cleared if we get a connect/save/ update or * any wifiManager command that indicate the user interacted with the configuration * since we will now consider that the configuration belong to him. + * @deprecated only kept for @UnsupportedAppUsage * @hide */ @UnsupportedAppUsage public boolean selfAdded; /** - * Set if the configuration was self added by the framework - * This boolean is set once and never cleared. It is used - * so as we never loose track of who created the - * configuration in the first place. - * @hide - */ - public boolean didSelfAdd; - - /** * Peer WifiConfiguration this WifiConfiguration was added for * @hide */ @@ -904,59 +903,87 @@ public class WifiConfiguration implements Parcelable { public boolean trusted; /** - * This Wifi configuration is created from a {@link WifiNetworkSuggestion} + * True if this Wifi configuration is created from a {@link WifiNetworkSuggestion}, + * false otherwise. + * * @hide */ + @SystemApi public boolean fromWifiNetworkSuggestion; /** - * This Wifi configuration is created from a {@link WifiNetworkSpecifier} + * True if this Wifi configuration is created from a {@link WifiNetworkSpecifier}, + * false otherwise. + * * @hide */ + @SystemApi public boolean fromWifiNetworkSpecifier; /** - * Indicates if the creator of this configuration has expressed that it - * should be considered metered. + * True if the creator of this configuration has expressed that it + * should be considered metered, false otherwise. * * @see #isMetered(WifiConfiguration, WifiInfo) + * * @hide */ @SystemApi public boolean meteredHint; - /** {@hide} */ + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"METERED_OVERRIDE_"}, value = { + METERED_OVERRIDE_NONE, + METERED_OVERRIDE_METERED, + METERED_OVERRIDE_NOT_METERED}) + public @interface MeteredOverride {} + + /** + * No metered override. + * @hide + */ + @SystemApi public static final int METERED_OVERRIDE_NONE = 0; - /** {@hide} */ + /** + * Override network to be metered. + * @hide + */ + @SystemApi public static final int METERED_OVERRIDE_METERED = 1; - /** {@hide} */ + /** + * Override network to be unmetered. + * @hide + */ + @SystemApi public static final int METERED_OVERRIDE_NOT_METERED = 2; /** * Indicates if the end user has expressed an explicit opinion about the * meteredness of this network, such as through the Settings app. + * This value is one of {@link #METERED_OVERRIDE_NONE}, {@link #METERED_OVERRIDE_METERED}, + * or {@link #METERED_OVERRIDE_NOT_METERED}. * <p> * This should always override any values from {@link #meteredHint} or * {@link WifiInfo#getMeteredHint()}. * + * By default this field is set to {@link #METERED_OVERRIDE_NONE}. + * * @see #isMetered(WifiConfiguration, WifiInfo) * @hide */ + @SystemApi + @MeteredOverride public int meteredOverride = METERED_OVERRIDE_NONE; /** - * This Wifi configuration is a clone of another network with lower security - * @hide - */ - public String clonedNetworkConfigKey; - - /** * Blend together all the various opinions to decide if the given network * should be considered metered or not. * * @hide */ - public static boolean isMetered(WifiConfiguration config, WifiInfo info) { + @SystemApi + public static boolean isMetered(@Nullable WifiConfiguration config, @Nullable WifiInfo info) { boolean metered = false; if (info != null && info.getMeteredHint()) { metered = true; @@ -1033,21 +1060,34 @@ public class WifiConfiguration implements Parcelable { @SystemApi public int numAssociation; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"RANDOMIZATION_"}, value = { + RANDOMIZATION_NONE, + RANDOMIZATION_PERSISTENT}) + public @interface MacRandomizationSetting {} + /** - * @hide * Use factory MAC when connecting to this network + * @hide */ + @SystemApi public static final int RANDOMIZATION_NONE = 0; /** - * @hide * Generate a randomized MAC once and reuse it for all connections to this network + * @hide */ + @SystemApi public static final int RANDOMIZATION_PERSISTENT = 1; /** + * Level of MAC randomization for this network. + * One of {@link #RANDOMIZATION_NONE} or {@link #RANDOMIZATION_PERSISTENT}. + * By default this field is set to {@link #RANDOMIZATION_PERSISTENT}. * @hide - * Level of MAC randomization for this network */ + @SystemApi + @MacRandomizationSetting public int macRandomizationSetting = RANDOMIZATION_PERSISTENT; /** @@ -1111,145 +1151,250 @@ public class WifiConfiguration implements Parcelable { public static final int HOME_NETWORK_RSSI_BOOST = 5; /** + * This class is used to contain all the information and API used for quality network selection. * @hide - * This class is used to contain all the information and API used for quality network selection */ + @SystemApi public static class NetworkSelectionStatus { - /** - * Quality Network Selection Status enable, temporary disabled, permanently disabled - */ + // Quality Network Selection Status enable, temporary disabled, permanently disabled /** * This network is allowed to join Quality Network Selection + * @hide */ public static final int NETWORK_SELECTION_ENABLED = 0; /** * network was temporary disabled. Can be re-enabled after a time period expire + * @hide */ public static final int NETWORK_SELECTION_TEMPORARY_DISABLED = 1; /** * network was permanently disabled. + * @hide */ public static final int NETWORK_SELECTION_PERMANENTLY_DISABLED = 2; /** * Maximum Network selection status + * @hide */ public static final int NETWORK_SELECTION_STATUS_MAX = 3; /** * Quality network selection status String (for debug purpose). Use Quality network * selection status value as index to extec the corresponding debug string + * @hide */ public static final String[] QUALITY_NETWORK_SELECTION_STATUS = { "NETWORK_SELECTION_ENABLED", "NETWORK_SELECTION_TEMPORARY_DISABLED", "NETWORK_SELECTION_PERMANENTLY_DISABLED"}; - //Quality Network disabled reasons - /** - * Default value. Means not disabled - */ + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + NETWORK_SELECTION_ENABLE, + DISABLED_ASSOCIATION_REJECTION, + DISABLED_AUTHENTICATION_FAILURE, + DISABLED_DHCP_FAILURE, + DISABLED_NO_INTERNET_TEMPORARY, + DISABLED_AUTHENTICATION_NO_CREDENTIALS, + DISABLED_NO_INTERNET_PERMANENT, + DISABLED_BY_WIFI_MANAGER, + DISABLED_BY_WRONG_PASSWORD, + DISABLED_AUTHENTICATION_NO_SUBSCRIPTION}) + public @interface NetworkSelectionDisableReason {} + + // Quality Network disabled reasons + /** Default value. Means not disabled. */ public static final int NETWORK_SELECTION_ENABLE = 0; /** - * The starting index for network selection disabled reasons + * The starting index for network selection disabled reasons. + * @hide */ public static final int NETWORK_SELECTION_DISABLED_STARTING_INDEX = 1; /** - * @deprecated it is not used any more. - * This network is disabled because higher layer (>2) network is bad - */ - public static final int DISABLED_BAD_LINK = 1; - /** - * This network is disabled because multiple association rejects - */ - public static final int DISABLED_ASSOCIATION_REJECTION = 2; - /** - * This network is disabled because multiple authentication failure - */ - public static final int DISABLED_AUTHENTICATION_FAILURE = 3; - /** - * This network is disabled because multiple DHCP failure - */ - public static final int DISABLED_DHCP_FAILURE = 4; - /** - * This network is disabled because of security network but no credentials - */ - public static final int DISABLED_DNS_FAILURE = 5; - /** - * This network is temporarily disabled because it has no Internet access. - */ - public static final int DISABLED_NO_INTERNET_TEMPORARY = 6; - /** - * This network is disabled because we started WPS - */ - public static final int DISABLED_WPS_START = 7; - /** - * This network is disabled because EAP-TLS failure - */ - public static final int DISABLED_TLS_VERSION_MISMATCH = 8; - // Values above are for temporary disablement; values below are for permanent disablement. - /** - * This network is disabled due to absence of user credentials - */ - public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 9; - /** - * This network is permanently disabled because it has no Internet access and user does not - * want to stay connected. - */ - public static final int DISABLED_NO_INTERNET_PERMANENT = 10; - /** - * This network is disabled due to WifiManager disable it explicitly - */ - public static final int DISABLED_BY_WIFI_MANAGER = 11; - /** - * This network is disabled due to user switching + * The starting index for network selection temporarily disabled reasons. + * @hide */ - public static final int DISABLED_DUE_TO_USER_SWITCH = 12; - /** - * This network is disabled due to wrong password + public static final int TEMPORARILY_DISABLED_STARTING_INDEX = 1; + /** This network is disabled because of multiple association rejections. */ + public static final int DISABLED_ASSOCIATION_REJECTION = 1; + /** This network is disabled because of multiple authentication failure. */ + public static final int DISABLED_AUTHENTICATION_FAILURE = 2; + /** This network is disabled because of multiple DHCP failure. */ + public static final int DISABLED_DHCP_FAILURE = 3; + /** This network is temporarily disabled because it has no Internet access. */ + public static final int DISABLED_NO_INTERNET_TEMPORARY = 4; + /** + * The starting index for network selection permanently disabled reasons. + * @hide */ - public static final int DISABLED_BY_WRONG_PASSWORD = 13; + public static final int PERMANENTLY_DISABLED_STARTING_INDEX = 5; + /** This network is disabled due to absence of user credentials */ + public static final int DISABLED_AUTHENTICATION_NO_CREDENTIALS = 5; /** - * This network is disabled because service is not subscribed + * This network is permanently disabled because it has no Internet access and the user does + * not want to stay connected. */ - public static final int DISABLED_AUTHENTICATION_NO_SUBSCRIPTION = 14; + public static final int DISABLED_NO_INTERNET_PERMANENT = 6; + /** This network is disabled due to WifiManager disabling it explicitly. */ + public static final int DISABLED_BY_WIFI_MANAGER = 7; + /** This network is disabled due to wrong password. */ + public static final int DISABLED_BY_WRONG_PASSWORD = 8; + /** This network is disabled because service is not subscribed. */ + public static final int DISABLED_AUTHENTICATION_NO_SUBSCRIPTION = 9; + /** All other disable reasons should be strictly less than this value. */ + public static final int NETWORK_SELECTION_DISABLED_MAX = 10; + /** - * This Maximum disable reason value + * Contains info about disable reasons. + * @hide */ - public static final int NETWORK_SELECTION_DISABLED_MAX = 15; + public static final class DisableReasonInfo { + /** + * String representation for the disable reason. + * Note that these strings are persisted in + * {@link + * com.android.server.wifi.util.XmlUtil.NetworkSelectionStatusXmlUtil#writeToXml}, + * so do not change the string values to maintain backwards compatibility. + */ + public final String mReasonStr; + /** + * Network Selection disable reason threshold, used to debounce network failures before + * we disable them. + */ + public final int mDisableThreshold; + /** + * Network Selection disable timeout for the error. After the timeout milliseconds, + * enable the network again. + */ + public final int mDisableTimeoutMillis; + + /** + * Constructor + * @param reasonStr string representation of the error + * @param disableThreshold number of failures before we disable the network + * @param disableTimeoutMillis the timeout, in milliseconds, before we re-enable the + * network after disabling it + */ + public DisableReasonInfo(String reasonStr, int disableThreshold, + int disableTimeoutMillis) { + mReasonStr = reasonStr; + mDisableThreshold = disableThreshold; + mDisableTimeoutMillis = disableTimeoutMillis; + } + } /** - * Quality network selection disable reason String (for debug purpose) + * Quality network selection disable reason infos. + * @hide */ - public static final String[] QUALITY_NETWORK_SELECTION_DISABLE_REASON = { - "NETWORK_SELECTION_ENABLE", - "NETWORK_SELECTION_DISABLED_BAD_LINK", // deprecated - "NETWORK_SELECTION_DISABLED_ASSOCIATION_REJECTION ", - "NETWORK_SELECTION_DISABLED_AUTHENTICATION_FAILURE", - "NETWORK_SELECTION_DISABLED_DHCP_FAILURE", - "NETWORK_SELECTION_DISABLED_DNS_FAILURE", - "NETWORK_SELECTION_DISABLED_NO_INTERNET_TEMPORARY", - "NETWORK_SELECTION_DISABLED_WPS_START", - "NETWORK_SELECTION_DISABLED_TLS_VERSION", - "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_CREDENTIALS", - "NETWORK_SELECTION_DISABLED_NO_INTERNET_PERMANENT", - "NETWORK_SELECTION_DISABLED_BY_WIFI_MANAGER", - "NETWORK_SELECTION_DISABLED_BY_USER_SWITCH", - "NETWORK_SELECTION_DISABLED_BY_WRONG_PASSWORD", - "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_SUBSCRIPTION" - }; + public static final SparseArray<DisableReasonInfo> DISABLE_REASON_INFOS = + buildDisableReasonInfos(); + + private static SparseArray<DisableReasonInfo> buildDisableReasonInfos() { + SparseArray<DisableReasonInfo> reasons = new SparseArray<>(); + + reasons.append(NETWORK_SELECTION_ENABLE, + new DisableReasonInfo( + // Note that these strings are persisted in + // XmlUtil.NetworkSelectionStatusXmlUtil#writeToXml, + // so do not change the string values to maintain backwards + // compatibility. + "NETWORK_SELECTION_ENABLE", + -1, + Integer.MAX_VALUE)); + + reasons.append(DISABLED_ASSOCIATION_REJECTION, + new DisableReasonInfo( + // Note that there is a space at the end of this string. Cannot fix + // since this string is persisted. + "NETWORK_SELECTION_DISABLED_ASSOCIATION_REJECTION ", + 5, + 5 * 60 * 1000)); + + reasons.append(DISABLED_AUTHENTICATION_FAILURE, + new DisableReasonInfo( + "NETWORK_SELECTION_DISABLED_AUTHENTICATION_FAILURE", + 5, + 5 * 60 * 1000)); + + reasons.append(DISABLED_DHCP_FAILURE, + new DisableReasonInfo( + "NETWORK_SELECTION_DISABLED_DHCP_FAILURE", + 5, + 5 * 60 * 1000)); + + reasons.append(DISABLED_NO_INTERNET_TEMPORARY, + new DisableReasonInfo( + "NETWORK_SELECTION_DISABLED_NO_INTERNET_TEMPORARY", + 1, + 10 * 60 * 1000)); + + reasons.append(DISABLED_AUTHENTICATION_NO_CREDENTIALS, + new DisableReasonInfo( + "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_CREDENTIALS", + 1, + Integer.MAX_VALUE)); + + reasons.append(DISABLED_NO_INTERNET_PERMANENT, + new DisableReasonInfo( + "NETWORK_SELECTION_DISABLED_NO_INTERNET_PERMANENT", + 1, + Integer.MAX_VALUE)); + + reasons.append(DISABLED_BY_WIFI_MANAGER, + new DisableReasonInfo( + "NETWORK_SELECTION_DISABLED_BY_WIFI_MANAGER", + 1, + Integer.MAX_VALUE)); + + reasons.append(DISABLED_BY_WRONG_PASSWORD, + new DisableReasonInfo( + "NETWORK_SELECTION_DISABLED_BY_WRONG_PASSWORD", + 1, + Integer.MAX_VALUE)); + + reasons.append(DISABLED_AUTHENTICATION_NO_SUBSCRIPTION, + new DisableReasonInfo( + "NETWORK_SELECTION_DISABLED_AUTHENTICATION_NO_SUBSCRIPTION", + 1, + Integer.MAX_VALUE)); + + return reasons; + } + + /** + * Get the {@link NetworkSelectionDisableReason} int code by its string value. + * @return the NetworkSelectionDisableReason int code corresponding to the reason string, + * or -1 if the reason string is unrecognized. + * @hide + */ + @NetworkSelectionDisableReason + public static int getDisableReasonByString(@NonNull String reasonString) { + for (int i = 0; i < DISABLE_REASON_INFOS.size(); i++) { + int key = DISABLE_REASON_INFOS.keyAt(i); + DisableReasonInfo value = DISABLE_REASON_INFOS.valueAt(i); + if (value != null && TextUtils.equals(reasonString, value.mReasonStr)) { + return key; + } + } + Log.e(TAG, "Unrecognized network disable reason: " + reasonString); + return -1; + } /** * Invalid time stamp for network selection disable + * @hide */ public static final long INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP = -1L; /** - * This constant indicates the current configuration has connect choice set + * This constant indicates the current configuration has connect choice set */ private static final int CONNECT_CHOICE_EXISTS = 1; /** - * This constant indicates the current configuration does not have connect choice set + * This constant indicates the current configuration does not have connect choice set */ private static final int CONNECT_CHOICE_NOT_EXISTS = -1; @@ -1263,6 +1408,7 @@ public class WifiConfiguration implements Parcelable { /** * Reason for disable this network */ + @NetworkSelectionDisableReason private int mNetworkSelectionDisableReason; /** @@ -1323,30 +1469,9 @@ public class WifiConfiguration implements Parcelable { private boolean mHasEverConnected; /** - * Boolean indicating whether {@link com.android.server.wifi.RecommendedNetworkEvaluator} - * chose not to connect to this network in the last qualified network selection process. - */ - private boolean mNotRecommended; - - /** - * Set whether {@link com.android.server.wifi.RecommendedNetworkEvaluator} does not - * recommend connecting to this network. - */ - public void setNotRecommended(boolean notRecommended) { - mNotRecommended = notRecommended; - } - - /** - * Returns whether {@link com.android.server.wifi.RecommendedNetworkEvaluator} does not - * recommend connecting to this network. - */ - public boolean isNotRecommended() { - return mNotRecommended; - } - - /** * set whether this network is visible in latest Qualified Network Selection * @param seen value set to candidate + * @hide */ public void setSeenInLastQualifiedNetworkSelection(boolean seen) { mSeenInLastQualifiedNetworkSelection = seen; @@ -1356,6 +1481,7 @@ public class WifiConfiguration implements Parcelable { * get whether this network is visible in latest Qualified Network Selection * @return returns true -- network is visible in latest Qualified Network Selection * false -- network is invisible in latest Qualified Network Selection + * @hide */ public boolean getSeenInLastQualifiedNetworkSelection() { return mSeenInLastQualifiedNetworkSelection; @@ -1363,6 +1489,7 @@ public class WifiConfiguration implements Parcelable { /** * set the temporary candidate of current network selection procedure * @param scanCandidate {@link ScanResult} the candidate set to mCandidate + * @hide */ public void setCandidate(ScanResult scanCandidate) { mCandidate = scanCandidate; @@ -1372,6 +1499,7 @@ public class WifiConfiguration implements Parcelable { * get the temporary candidate of current network selection procedure * @return returns {@link ScanResult} temporary candidate of current network selection * procedure + * @hide */ public ScanResult getCandidate() { return mCandidate; @@ -1380,6 +1508,7 @@ public class WifiConfiguration implements Parcelable { /** * set the score of the temporary candidate of current network selection procedure * @param score value set to mCandidateScore + * @hide */ public void setCandidateScore(int score) { mCandidateScore = score; @@ -1388,6 +1517,7 @@ public class WifiConfiguration implements Parcelable { /** * get the score of the temporary candidate of current network selection procedure * @return returns score of the temporary candidate of current network selection procedure + * @hide */ public int getCandidateScore() { return mCandidateScore; @@ -1395,7 +1525,8 @@ public class WifiConfiguration implements Parcelable { /** * get user preferred choice over this configuration - *@return returns configKey of user preferred choice over this configuration + * @return returns configKey of user preferred choice over this configuration + * @hide */ public String getConnectChoice() { return mConnectChoice; @@ -1404,6 +1535,7 @@ public class WifiConfiguration implements Parcelable { /** * set user preferred choice over this configuration * @param newConnectChoice, the configKey of user preferred choice over this configuration + * @hide */ public void setConnectChoice(String newConnectChoice) { mConnectChoice = newConnectChoice; @@ -1412,6 +1544,7 @@ public class WifiConfiguration implements Parcelable { /** * get the timeStamp when user select a choice over this configuration * @return returns when current connectChoice is set (time from System.currentTimeMillis) + * @hide */ public long getConnectChoiceTimestamp() { return mConnectChoiceTimestamp; @@ -1421,82 +1554,90 @@ public class WifiConfiguration implements Parcelable { * set the timeStamp when user select a choice over this configuration * @param timeStamp, the timestamp set to connectChoiceTimestamp, expected timestamp should * be obtained from System.currentTimeMillis + * @hide */ public void setConnectChoiceTimestamp(long timeStamp) { mConnectChoiceTimestamp = timeStamp; } - /** - * get current Quality network selection status - * @return returns current Quality network selection status in String (for debug purpose) - */ + /** Get the current Quality network selection status as a String (for debugging). */ + @NonNull public String getNetworkStatusString() { return QUALITY_NETWORK_SELECTION_STATUS[mStatus]; } + /** @hide */ public void setHasEverConnected(boolean value) { mHasEverConnected = value; } + /** True if the device has ever connected to this network, false otherwise. */ public boolean getHasEverConnected() { return mHasEverConnected; } + /** @hide */ public NetworkSelectionStatus() { // previously stored configs will not have this parameter, so we default to false. mHasEverConnected = false; - }; + } /** - * @param reason specific error reason - * @return corresponding network disable reason String (for debug purpose) + * Get the network disable reason string for a reason code (for debugging). + * @param reason specific error reason. One of the {@link #NETWORK_SELECTION_ENABLE} or + * DISABLED_* constants e.g. {@link #DISABLED_ASSOCIATION_REJECTION}. + * @return network disable reason string, or null if the reason is invalid. */ - public static String getNetworkDisableReasonString(int reason) { - if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) { - return QUALITY_NETWORK_SELECTION_DISABLE_REASON[reason]; - } else { + @Nullable + public static String getNetworkDisableReasonString( + @NetworkSelectionDisableReason int reason) { + DisableReasonInfo info = DISABLE_REASON_INFOS.get(reason); + if (info == null) { return null; + } else { + return info.mReasonStr; } } /** * get current network disable reason * @return current network disable reason in String (for debug purpose) + * @hide */ public String getNetworkDisableReasonString() { - return QUALITY_NETWORK_SELECTION_DISABLE_REASON[mNetworkSelectionDisableReason]; + return getNetworkDisableReasonString(mNetworkSelectionDisableReason); } /** * get current network network selection status * @return return current network network selection status + * @hide */ public int getNetworkSelectionStatus() { return mStatus; } - /** - * @return whether current network is enabled to join network selection - */ + + /** True if the current network is enabled to join network selection, false otherwise. */ public boolean isNetworkEnabled() { return mStatus == NETWORK_SELECTION_ENABLED; } /** * @return whether current network is temporary disabled + * @hide */ public boolean isNetworkTemporaryDisabled() { return mStatus == NETWORK_SELECTION_TEMPORARY_DISABLED; } - /** - * @return returns whether current network is permanently disabled - */ + /** True if the current network is permanently disabled, false otherwise. */ public boolean isNetworkPermanentlyDisabled() { return mStatus == NETWORK_SELECTION_PERMANENTLY_DISABLED; } /** - * set current networ work selection status + * set current network selection status * @param status network selection status to set + * @hide */ public void setNetworkSelectionStatus(int status) { if (status >= 0 && status < NETWORK_SELECTION_STATUS_MAX) { @@ -1505,17 +1646,21 @@ public class WifiConfiguration implements Parcelable { } /** - * @return returns current network's disable reason + * Returns the current network's disable reason. + * One of the {@link #NETWORK_SELECTION_ENABLE} or DISABLED_* constants + * e.g. {@link #DISABLED_ASSOCIATION_REJECTION}. */ + @NetworkSelectionDisableReason public int getNetworkSelectionDisableReason() { return mNetworkSelectionDisableReason; } /** * set Network disable reason - * @param reason Network disable reason + * @param reason Network disable reason + * @hide */ - public void setNetworkSelectionDisableReason(int reason) { + public void setNetworkSelectionDisableReason(@NetworkSelectionDisableReason int reason) { if (reason >= 0 && reason < NETWORK_SELECTION_DISABLED_MAX) { mNetworkSelectionDisableReason = reason; } else { @@ -1524,38 +1669,30 @@ public class WifiConfiguration implements Parcelable { } /** - * check whether network is disabled by this reason - * @param reason a specific disable reason - * @return true -- network is disabled for this reason - * false -- network is not disabled for this reason - */ - public boolean isDisabledByReason(int reason) { - return mNetworkSelectionDisableReason == reason; - } - - /** * @param timeStamp Set when current network is disabled in millisecond since January 1, * 1970 00:00:00.0 UTC + * @hide */ public void setDisableTime(long timeStamp) { mTemporarilyDisabledTimestamp = timeStamp; } /** - * @return returns when current network is disabled in millisecond since January 1, - * 1970 00:00:00.0 UTC + * Returns when the current network was disabled, in milliseconds since January 1, + * 1970 00:00:00.0 UTC. */ public long getDisableTime() { return mTemporarilyDisabledTimestamp; } /** - * get the disable counter of a specific reason - * @param reason specific failure reason - * @exception throw IllegalArgumentException for illegal input + * Get the disable counter of a specific reason. + * @param reason specific failure reason. One of the {@link #NETWORK_SELECTION_ENABLE} or + * DISABLED_* constants e.g. {@link #DISABLED_ASSOCIATION_REJECTION}. + * @exception IllegalArgumentException for invalid reason * @return counter number for specific error reason. */ - public int getDisableReasonCounter(int reason) { + public int getDisableReasonCounter(@NetworkSelectionDisableReason int reason) { if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) { return mNetworkSeclectionDisableCounter[reason]; } else { @@ -1568,6 +1705,7 @@ public class WifiConfiguration implements Parcelable { * @param reason reason for disable error * @param value the counter value for this specific reason * @exception throw IllegalArgumentException for illegal input + * @hide */ public void setDisableReasonCounter(int reason, int value) { if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) { @@ -1581,6 +1719,7 @@ public class WifiConfiguration implements Parcelable { * increment the counter of a specific failure reason * @param reason a specific failure reason * @exception throw IllegalArgumentException for illegal input + * @hide */ public void incrementDisableReasonCounter(int reason) { if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) { @@ -1592,9 +1731,9 @@ public class WifiConfiguration implements Parcelable { /** * clear the counter of a specific failure reason - * @hide * @param reason a specific failure reason * @exception throw IllegalArgumentException for illegal input + * @hide */ public void clearDisableReasonCounter(int reason) { if (reason >= NETWORK_SELECTION_ENABLE && reason < NETWORK_SELECTION_DISABLED_MAX) { @@ -1606,6 +1745,7 @@ public class WifiConfiguration implements Parcelable { /** * clear all the failure reason counters + * @hide */ public void clearDisableReasonCounter() { Arrays.fill(mNetworkSeclectionDisableCounter, NETWORK_SELECTION_ENABLE); @@ -1619,6 +1759,7 @@ public class WifiConfiguration implements Parcelable { /** * get current network Selection BSSID * @return current network Selection BSSID + * @hide */ public String getNetworkSelectionBSSID() { return mNetworkSelectionBSSID; @@ -1627,11 +1768,13 @@ public class WifiConfiguration implements Parcelable { /** * set network Selection BSSID * @param bssid The target BSSID for assocaition + * @hide */ public void setNetworkSelectionBSSID(String bssid) { mNetworkSelectionBSSID = bssid; } + /** @hide */ public void copy(NetworkSelectionStatus source) { mStatus = source.mStatus; mNetworkSelectionDisableReason = source.mNetworkSelectionDisableReason; @@ -1648,9 +1791,9 @@ public class WifiConfiguration implements Parcelable { setConnectChoice(source.getConnectChoice()); setConnectChoiceTimestamp(source.getConnectChoiceTimestamp()); setHasEverConnected(source.getHasEverConnected()); - setNotRecommended(source.isNotRecommended()); } + /** @hide */ public void writeToParcel(Parcel dest) { dest.writeInt(getNetworkSelectionStatus()); dest.writeInt(getNetworkSelectionDisableReason()); @@ -1668,9 +1811,9 @@ public class WifiConfiguration implements Parcelable { dest.writeInt(CONNECT_CHOICE_NOT_EXISTS); } dest.writeInt(getHasEverConnected() ? 1 : 0); - dest.writeInt(isNotRecommended() ? 1 : 0); } + /** @hide */ public void readFromParcel(Parcel in) { setNetworkSelectionStatus(in.readInt()); setNetworkSelectionDisableReason(in.readInt()); @@ -1688,7 +1831,6 @@ public class WifiConfiguration implements Parcelable { setConnectChoiceTimestamp(INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP); } setHasEverConnected(in.readInt() != 0); - setNotRecommended(in.readInt() != 0); } } @@ -1703,8 +1845,16 @@ public class WifiConfiguration implements Parcelable { * This class is intended to store extra failure reason information for the most recent * connection attempt, so that it may be surfaced to the settings UI */ + @SystemApi public static class RecentFailure { + private RecentFailure() {} + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = {NONE, STATUS_AP_UNABLE_TO_HANDLE_NEW_STA}) + public @interface AssociationStatus {} + /** * No recent failure, or no specific reason given for the recent connection failure */ @@ -1717,38 +1867,47 @@ public class WifiConfiguration implements Parcelable { /** * Association Rejection Status code (NONE for success/non-association-rejection-fail) */ + @AssociationStatus private int mAssociationStatus = NONE; /** * @param status the association status code for the recent failure + * @hide */ - public void setAssociationStatus(int status) { + public void setAssociationStatus(@AssociationStatus int status) { mAssociationStatus = status; } /** * Sets the RecentFailure to NONE + * @hide */ public void clear() { mAssociationStatus = NONE; } /** - * Get the recent failure code + * Get the recent failure code. One of {@link #NONE} or + * {@link #STATUS_AP_UNABLE_TO_HANDLE_NEW_STA}. */ + @AssociationStatus public int getAssociationStatus() { return mAssociationStatus; } } /** - * @hide * RecentFailure member + * @hide */ - final public RecentFailure recentFailure = new RecentFailure(); + @NonNull + @SystemApi + public final RecentFailure recentFailure = new RecentFailure(); /** + * Get the network selection status. * @hide - * @return network selection status */ + @NonNull + @SystemApi public NetworkSelectionStatus getNetworkSelectionStatus() { return mNetworkSelectionStatus; } @@ -1791,8 +1950,6 @@ public class WifiConfiguration implements Parcelable { wepKeys[i] = null; } enterpriseConfig = new WifiEnterpriseConfig(); - selfAdded = false; - didSelfAdd = false; ephemeral = false; osu = false; trusted = true; // Networks are considered trusted by default. @@ -1808,7 +1965,6 @@ public class WifiConfiguration implements Parcelable { shared = true; dtimInterval = 0; mRandomizedMacAddress = MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS); - clonedNetworkConfigKey = null; } /** @@ -1905,8 +2061,6 @@ public class WifiConfiguration implements Parcelable { if (this.creationTime != null) { sbuf.append(" creation ").append(this.creationTime).append("\n"); } - if (this.didSelfAdd) sbuf.append(" didSelfAdd"); - if (this.selfAdded) sbuf.append(" selfAdded"); if (this.validatedInternetAccess) sbuf.append(" validatedInternetAccess"); if (this.ephemeral) sbuf.append(" ephemeral"); if (this.osu) sbuf.append(" osu"); @@ -1915,9 +2069,9 @@ public class WifiConfiguration implements Parcelable { if (this.fromWifiNetworkSpecifier) sbuf.append(" fromWifiNetworkSpecifier"); if (this.meteredHint) sbuf.append(" meteredHint"); if (this.useExternalScores) sbuf.append(" useExternalScores"); - if (this.didSelfAdd || this.selfAdded || this.validatedInternetAccess - || this.ephemeral || this.trusted || this.fromWifiNetworkSuggestion - || this.fromWifiNetworkSpecifier || this.meteredHint || this.useExternalScores) { + if (this.validatedInternetAccess || this.ephemeral || this.trusted + || this.fromWifiNetworkSuggestion || this.fromWifiNetworkSpecifier + || this.meteredHint || this.useExternalScores) { sbuf.append("\n"); } if (this.meteredOverride != METERED_OVERRIDE_NONE) { @@ -2045,7 +2199,6 @@ public class WifiConfiguration implements Parcelable { if (lastUpdateName != null) sbuf.append(" lname=" + lastUpdateName); if (updateIdentifier != null) sbuf.append(" updateIdentifier=" + updateIdentifier); sbuf.append(" lcuid=" + lastConnectUid); - sbuf.append(" userApproved=" + userApprovedAsString(userApproved)); sbuf.append(" allowAutojoin=" + allowAutojoin); sbuf.append(" noInternetAccessExpected=" + noInternetAccessExpected); sbuf.append(" "); @@ -2067,8 +2220,13 @@ public class WifiConfiguration implements Parcelable { return sbuf.toString(); } - /** {@hide} */ - @UnsupportedAppUsage + /** + * Get the SSID in a human-readable format, with all additional formatting removed + * e.g. quotation marks around the SSID, "P" prefix + * @hide + */ + @NonNull + @SystemApi public String getPrintableSsid() { if (SSID == null) return ""; final int length = SSID.length(); @@ -2076,7 +2234,7 @@ public class WifiConfiguration implements Parcelable { return SSID.substring(1, length - 1); } - /** The ascii-encoded string format is P"<ascii-encoded-string>" + /* The ascii-encoded string format is P"<ascii-encoded-string>" * The decoding is implemented in the supplicant for a newly configured * network. */ @@ -2089,20 +2247,6 @@ public class WifiConfiguration implements Parcelable { return SSID; } - /** @hide **/ - public static String userApprovedAsString(int userApproved) { - switch (userApproved) { - case USER_APPROVED: - return "USER_APPROVED"; - case USER_BANNED: - return "USER_BANNED"; - case USER_UNSPECIFIED: - return "USER_UNSPECIFIED"; - default: - return "INVALID"; - } - } - /** * Get an identifier for associating credentials with this config * @param current configuration contains values for additional fields @@ -2171,8 +2315,13 @@ public class WifiConfiguration implements Parcelable { } } - /** @hide */ - @UnsupportedAppUsage + /** + * Get the authentication type of the network. + * @return One of the {@link KeyMgmt} constants. e.g. {@link KeyMgmt#WPA2_PSK}. + * @hide + */ + @SystemApi + @KeyMgmt.KeyMgmtScheme public int getAuthType() { if (allowedKeyManagement.cardinality() > 1) { throw new IllegalStateException("More than one auth type set"); @@ -2261,15 +2410,25 @@ public class WifiConfiguration implements Parcelable { return mIpConfiguration; } - /** @hide */ - @UnsupportedAppUsage - public void setIpConfiguration(IpConfiguration ipConfiguration) { + /** + * Set the {@link IpConfiguration} for this network. + * @param ipConfiguration the {@link IpConfiguration} to set, or null to use the default + * constructor {@link IpConfiguration#IpConfiguration()}. + * @hide + */ + @SystemApi + public void setIpConfiguration(@Nullable IpConfiguration ipConfiguration) { if (ipConfiguration == null) ipConfiguration = new IpConfiguration(); mIpConfiguration = ipConfiguration; } - /** @hide */ - @UnsupportedAppUsage + /** + * Get the {@link StaticIpConfiguration} for this network. + * @return the {@link StaticIpConfiguration}, or null if unset. + * @hide + */ + @Nullable + @SystemApi public StaticIpConfiguration getStaticIpConfiguration() { return mIpConfiguration.getStaticIpConfiguration(); } @@ -2280,8 +2439,12 @@ public class WifiConfiguration implements Parcelable { mIpConfiguration.setStaticIpConfiguration(staticIpConfiguration); } - /** @hide */ - @UnsupportedAppUsage + /** + * Get the {@link IpConfiguration.IpAssignment} for this network. + * @hide + */ + @NonNull + @SystemApi public IpConfiguration.IpAssignment getIpAssignment() { return mIpConfiguration.ipAssignment; } @@ -2292,8 +2455,12 @@ public class WifiConfiguration implements Parcelable { mIpConfiguration.ipAssignment = ipAssignment; } - /** @hide */ - @UnsupportedAppUsage + /** + * Get the {@link IpConfiguration.ProxySettings} for this network. + * @hide + */ + @NonNull + @SystemApi public IpConfiguration.ProxySettings getProxySettings() { return mIpConfiguration.proxySettings; } @@ -2352,9 +2519,12 @@ public class WifiConfiguration implements Parcelable { mIpConfiguration.setHttpProxy(httpProxyCopy); } - /** @hide */ - @UnsupportedAppUsage - public void setProxy(ProxySettings settings, ProxyInfo proxy) { + /** + * Set the {@link ProxySettings} and {@link ProxyInfo} for this network. + * @hide + */ + @SystemApi + public void setProxy(@NonNull ProxySettings settings, @NonNull ProxyInfo proxy) { mIpConfiguration.proxySettings = settings; mIpConfiguration.httpProxy = proxy; } @@ -2376,7 +2546,6 @@ public class WifiConfiguration implements Parcelable { /** copy constructor {@hide} */ @UnsupportedAppUsage - public WifiConfiguration(WifiConfiguration source) { if (source != null) { networkId = source.networkId; @@ -2421,7 +2590,6 @@ public class WifiConfiguration implements Parcelable { linkedConfigurations.putAll(source.linkedConfigurations); } mCachedConfigKey = null; //force null configKey - selfAdded = source.selfAdded; validatedInternetAccess = source.validatedInternetAccess; isLegacyPasspointConfig = source.isLegacyPasspointConfig; ephemeral = source.ephemeral; @@ -2433,7 +2601,6 @@ public class WifiConfiguration implements Parcelable { meteredOverride = source.meteredOverride; useExternalScores = source.useExternalScores; - didSelfAdd = source.didSelfAdd; lastConnectUid = source.lastConnectUid; lastUpdateUid = source.lastUpdateUid; creatorUid = source.creatorUid; @@ -2446,7 +2613,6 @@ public class WifiConfiguration implements Parcelable { numScorerOverride = source.numScorerOverride; numScorerOverrideAndSwitchedNetwork = source.numScorerOverrideAndSwitchedNetwork; numAssociation = source.numAssociation; - userApproved = source.userApproved; allowAutojoin = source.allowAutojoin; numNoInternetAccessReports = source.numNoInternetAccessReports; noInternetAccessExpected = source.noInternetAccessExpected; @@ -2460,7 +2626,6 @@ public class WifiConfiguration implements Parcelable { requirePMF = source.requirePMF; updateIdentifier = source.updateIdentifier; carrierId = source.carrierId; - clonedNetworkConfigKey = source.clonedNetworkConfigKey; } } @@ -2505,8 +2670,6 @@ public class WifiConfiguration implements Parcelable { dest.writeParcelable(mIpConfiguration, flags); dest.writeString(dhcpServer); dest.writeString(defaultGwMacAddress); - dest.writeInt(selfAdded ? 1 : 0); - dest.writeInt(didSelfAdd ? 1 : 0); dest.writeInt(validatedInternetAccess ? 1 : 0); dest.writeInt(isLegacyPasspointConfig ? 1 : 0); dest.writeInt(ephemeral ? 1 : 0); @@ -2524,7 +2687,6 @@ public class WifiConfiguration implements Parcelable { dest.writeInt(numScorerOverride); dest.writeInt(numScorerOverrideAndSwitchedNetwork); dest.writeInt(numAssociation); - dest.writeInt(userApproved); dest.writeBoolean(allowAutojoin); dest.writeInt(numNoInternetAccessReports); dest.writeInt(noInternetAccessExpected ? 1 : 0); @@ -2536,7 +2698,6 @@ public class WifiConfiguration implements Parcelable { dest.writeInt(osu ? 1 : 0); dest.writeLong(randomizedMacExpirationTimeMs); dest.writeInt(carrierId); - dest.writeString(clonedNetworkConfigKey); } /** Implement the Parcelable interface {@hide} */ @@ -2583,8 +2744,6 @@ public class WifiConfiguration implements Parcelable { config.setIpConfiguration(in.readParcelable(null)); config.dhcpServer = in.readString(); config.defaultGwMacAddress = in.readString(); - config.selfAdded = in.readInt() != 0; - config.didSelfAdd = in.readInt() != 0; config.validatedInternetAccess = in.readInt() != 0; config.isLegacyPasspointConfig = in.readInt() != 0; config.ephemeral = in.readInt() != 0; @@ -2602,7 +2761,6 @@ public class WifiConfiguration implements Parcelable { config.numScorerOverride = in.readInt(); config.numScorerOverrideAndSwitchedNetwork = in.readInt(); config.numAssociation = in.readInt(); - config.userApproved = in.readInt(); config.allowAutojoin = in.readBoolean(); config.numNoInternetAccessReports = in.readInt(); config.noInternetAccessExpected = in.readInt() != 0; @@ -2614,7 +2772,6 @@ public class WifiConfiguration implements Parcelable { config.osu = in.readInt() != 0; config.randomizedMacExpirationTimeMs = in.readLong(); config.carrierId = in.readInt(); - config.clonedNetworkConfigKey = in.readString(); return config; } @@ -2624,9 +2781,11 @@ public class WifiConfiguration implements Parcelable { }; /** - * Serializes the object for backup + * Serialize the Soft AP configuration contained in this object for backup. * @hide */ + @NonNull + // TODO(b/144368124): this method should be removed once we migrate to SoftApConfiguration public byte[] getBytesForBackup() throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream out = new DataOutputStream(baos); @@ -2642,11 +2801,16 @@ public class WifiConfiguration implements Parcelable { } /** - * Deserializes a byte array into the WiFiConfiguration Object + * Deserialize a byte array containing Soft AP configuration into a WifiConfiguration object. + * @return The deserialized WifiConfiguration containing Soft AP configuration, or null if + * the version contains a bad dataset e.g. Version 1 + * @throws BackupUtils.BadVersionException if the version is unrecognized * @hide */ - public static WifiConfiguration getWifiConfigFromBackup(DataInputStream in) throws IOException, - BackupUtils.BadVersionException { + @Nullable + // TODO(b/144368124): this method should be removed once we migrate to SoftApConfiguration + public static WifiConfiguration getWifiConfigFromBackup(@NonNull DataInputStream in) + throws IOException, BackupUtils.BadVersionException { WifiConfiguration config = new WifiConfiguration(); int version = in.readInt(); if (version < 1 || version > BACKUP_VERSION) { diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java index 7b99a2b5502f..449f95e8a161 100644 --- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java +++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java @@ -16,7 +16,9 @@ package android.net.wifi; import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -118,18 +120,21 @@ public class WifiEnterpriseConfig implements Parcelable { * Do not use OCSP stapling (TLS certificate status extension) * @hide */ + @SystemApi public static final int OCSP_NONE = 0; /** * Try to use OCSP stapling, but not require response * @hide */ + @SystemApi public static final int OCSP_REQUEST_CERT_STATUS = 1; /** * Require valid OCSP stapling response * @hide */ + @SystemApi public static final int OCSP_REQUIRE_CERT_STATUS = 2; /** @@ -137,6 +142,7 @@ public class WifiEnterpriseConfig implements Parcelable { * certificate chain * @hide */ + @SystemApi public static final int OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS = 3; /** @hide */ @@ -147,8 +153,7 @@ public class WifiEnterpriseConfig implements Parcelable { OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS }) @Retention(RetentionPolicy.SOURCE) - public @interface Ocsp { - } + public @interface Ocsp {} /** * Whether to use/require OCSP (Online Certificate Status Protocol) to check server certificate. @@ -636,9 +641,11 @@ public class WifiEnterpriseConfig implements Parcelable { * <p> See the {@link android.security.KeyChain} for details on installing or choosing * a certificate. * </p> - * @param aliases identifies the certificate + * @param aliases identifies the certificate. Can be null to indicate the absence of a + * certificate. * @hide */ + @SystemApi public void setCaCertificateAliases(@Nullable String[] aliases) { if (aliases == null) { setFieldValue(CA_CERT_KEY, null, CA_CERT_PREFIX); @@ -669,11 +676,13 @@ public class WifiEnterpriseConfig implements Parcelable { } /** - * Get CA certificate aliases - * @return alias to the CA certificate + * Get CA certificate aliases. + * @return alias to the CA certificate, or null if unset. * @hide */ - @Nullable public String[] getCaCertificateAliases() { + @Nullable + @SystemApi + public String[] getCaCertificateAliases() { String value = getFieldValue(CA_CERT_KEY); if (value.startsWith(CA_CERT_PREFIX)) { // Backwards compatibility: parse the original alias prefix. @@ -792,32 +801,36 @@ public class WifiEnterpriseConfig implements Parcelable { * like /etc/ssl/certs. If configured, these certificates are added to the * list of trusted CAs. ca_cert may also be included in that case, but it is * not required. - * @param domain The path for CA certificate files + * @param path The path for CA certificate files, or null/empty string to clear. * @hide */ - public void setCaPath(String path) { + @SystemApi + public void setCaPath(@Nullable String path) { setFieldValue(CA_PATH_KEY, path); } /** * Get the domain_suffix_match value. See setDomSuffixMatch. - * @return The path for CA certificate files. + * @return The path for CA certificate files, or an empty string if unset. * @hide */ + @NonNull + @SystemApi public String getCaPath() { return getFieldValue(CA_PATH_KEY); } - /** Set Client certificate alias. + /** + * Set Client certificate alias. * * <p> See the {@link android.security.KeyChain} for details on installing or choosing * a certificate * </p> - * @param alias identifies the certificate + * @param alias identifies the certificate, or null/empty string to clear. * @hide */ - @UnsupportedAppUsage - public void setClientCertificateAlias(String alias) { + @SystemApi + public void setClientCertificateAlias(@Nullable String alias) { setFieldValue(CLIENT_CERT_KEY, alias, CLIENT_CERT_PREFIX); setFieldValue(PRIVATE_KEY_ID_KEY, alias, Credentials.USER_PRIVATE_KEY); // Also, set engine parameters @@ -831,11 +844,12 @@ public class WifiEnterpriseConfig implements Parcelable { } /** - * Get client certificate alias - * @return alias to the client certificate + * Get client certificate alias. + * @return alias to the client certificate, or an empty string if unset. * @hide */ - @UnsupportedAppUsage + @NonNull + @SystemApi public String getClientCertificateAlias() { return getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX); } @@ -1241,12 +1255,14 @@ public class WifiEnterpriseConfig implements Parcelable { } /** - * Set the ocsp type. - * @param ocsp is one {@link ##OCSP_NONE}, {@link #OCSP_REQUEST_CERT_STATUS}, + * Set the OCSP type. + * @param ocsp is one of {@link ##OCSP_NONE}, {@link #OCSP_REQUEST_CERT_STATUS}, * {@link #OCSP_REQUIRE_CERT_STATUS} or * {@link #OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS} + * @throws IllegalArgumentException if the OCSP type is invalid * @hide */ + @SystemApi public void setOcsp(@Ocsp int ocsp) { if (ocsp >= OCSP_NONE && ocsp <= OCSP_REQUIRE_ALL_NON_TRUSTED_CERTS_STATUS) { mOcsp = ocsp; @@ -1256,10 +1272,10 @@ public class WifiEnterpriseConfig implements Parcelable { } /** - * Get the ocsp type. - * @return ocsp type + * Get the OCSP type. * @hide */ + @SystemApi public @Ocsp int getOcsp() { return mOcsp; } diff --git a/wifi/java/android/net/wifi/WifiFrameworkInitializer.java b/wifi/java/android/net/wifi/WifiFrameworkInitializer.java new file mode 100644 index 000000000000..775043ae3291 --- /dev/null +++ b/wifi/java/android/net/wifi/WifiFrameworkInitializer.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2019 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; + +import android.annotation.SystemApi; +import android.app.SystemServiceRegistry; +import android.content.Context; +import android.net.wifi.aware.IWifiAwareManager; +import android.net.wifi.aware.WifiAwareManager; +import android.net.wifi.p2p.IWifiP2pManager; +import android.net.wifi.p2p.WifiP2pManager; +import android.net.wifi.rtt.IWifiRttManager; +import android.net.wifi.rtt.WifiRttManager; +import android.os.HandlerThread; +import android.os.Looper; + +/** + * Class for performing registration for all Wifi services. + * + * @hide + */ +@SystemApi +public class WifiFrameworkInitializer { + + /** + * A class implementing the lazy holder idiom: the unique static instance + * of {@link #INSTANCE} is instantiated in a thread-safe way (guaranteed by + * the language specs) the first time that NoPreloadHolder is referenced in getInstanceLooper(). + * + * This is necessary because we can't spawn a new thread in {@link #registerServiceWrappers()}. + * {@link #registerServiceWrappers()} is called during the Zygote phase, which disallows + * spawning new threads. Naming the class "NoPreloadHolder" ensures that the classloader will + * not preload this class, inadvertently spawning the thread too early. + */ + private static class NoPreloadHolder { + private static final HandlerThread INSTANCE = createInstance(); + + private static HandlerThread createInstance() { + HandlerThread thread = new HandlerThread("WifiManagerThread"); + thread.start(); + return thread; + } + } + + private static Looper getInstanceLooper() { + return NoPreloadHolder.INSTANCE.getLooper(); + } + + private WifiFrameworkInitializer() {} + + /** + * Called by {@link SystemServiceRegistry}'s static initializer and registers all Wifi services + * to {@link Context}, so that {@link Context#getSystemService} can return them. + * + * @throws IllegalStateException if this is called from anywhere besides + * {@link SystemServiceRegistry} + */ + public static void registerServiceWrappers() { + SystemServiceRegistry.registerContextAwareService( + Context.WIFI_SERVICE, + WifiManager.class, + context -> new WifiManager(context, getInstanceLooper()) + ); + SystemServiceRegistry.registerStaticService( + Context.WIFI_P2P_SERVICE, + WifiP2pManager.class, + serviceBinder -> { + IWifiP2pManager service = IWifiP2pManager.Stub.asInterface(serviceBinder); + return new WifiP2pManager(service); + } + ); + SystemServiceRegistry.registerContextAwareService( + Context.WIFI_AWARE_SERVICE, + WifiAwareManager.class, + (context, serviceBinder) -> { + IWifiAwareManager service = IWifiAwareManager.Stub.asInterface(serviceBinder); + return new WifiAwareManager(context, service); + } + ); + SystemServiceRegistry.registerContextAwareService( + Context.WIFI_SCANNING_SERVICE, + WifiScanner.class, + (context, serviceBinder) -> { + IWifiScanner service = IWifiScanner.Stub.asInterface(serviceBinder); + return new WifiScanner(context, service, getInstanceLooper()); + } + ); + SystemServiceRegistry.registerContextAwareService( + Context.WIFI_RTT_SERVICE, + RttManager.class, + (context, serviceBinder) -> { + IWifiRttManager service = IWifiRttManager.Stub.asInterface(serviceBinder); + WifiRttManager wifiRttManager = new WifiRttManager(context, service); + return new RttManager(context, wifiRttManager); + } + ); + SystemServiceRegistry.registerContextAwareService( + Context.WIFI_RTT_RANGING_SERVICE, + WifiRttManager.class, + (context, serviceBinder) -> { + IWifiRttManager service = IWifiRttManager.Stub.asInterface(serviceBinder); + return new WifiRttManager(context, service); + } + ); + } +} diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 6c2a08c14082..2a0211b77450 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -1153,8 +1153,6 @@ public class WifiManager { * @hide */ @UnsupportedAppUsage - // TODO(b/140781184): need to support custom number of RSSI levels, as well as levels that are - // not evenly spaced public static final int RSSI_LEVELS = 5; /** @@ -1215,11 +1213,13 @@ public class WifiManager { * Applications will almost always want to use * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}. + * * @param context the application context - * @hide - hide this because it takes in a parameter of type IWifiManager, which - * is a system private class. + * @param looper the Looper used to deliver callbacks + * + * @hide */ - public WifiManager(Context context, Looper looper) { + public WifiManager(@NonNull Context context, @NonNull Looper looper) { mContext = context; mLooper = looper; mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion; @@ -2782,11 +2782,13 @@ public class WifiManager { * is being shown. * * @param rssi The power of the signal measured in RSSI. - * @param numLevels The number of levels to consider in the calculated - * level. - * @return A level of the signal, given in the range of 0 to numLevels-1 - * (both inclusive). + * @param numLevels The number of levels to consider in the calculated level. + * @return A level of the signal, given in the range of 0 to numLevels-1 (both inclusive). + * @deprecated Callers should use {@link #calculateSignalLevel(int)} instead to get the + * signal level using the system default RSSI thresholds, or otherwise compute the RSSI level + * themselves using their own formula. */ + @Deprecated public static int calculateSignalLevel(int rssi, int numLevels) { if (rssi <= MIN_RSSI) { return 0; @@ -2800,6 +2802,34 @@ public class WifiManager { } /** + * Given a raw RSSI, return the RSSI signal quality rating using the system default RSSI + * quality rating thresholds. + * @param rssi a raw RSSI value, in dBm, usually between -55 and -90 + * @return the RSSI signal quality rating, in the range + * [0, {@link #getMaxSignalLevel()}], where 0 is the lowest (worst signal) RSSI + * rating and {@link #getMaxSignalLevel()} is the highest (best signal) RSSI rating. + */ + public int calculateSignalLevel(int rssi) { + try { + IWifiManager iWifiManager = getIWifiManager(); + if (iWifiManager == null) { + throw new RemoteException("Wifi service is not running"); + } + return iWifiManager.calculateSignalLevel(rssi); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Get the system default maximum signal level. + * This is the maximum RSSI level returned by {@link #calculateSignalLevel(int)}. + */ + public int getMaxSignalLevel() { + return calculateSignalLevel(Integer.MAX_VALUE); + } + + /** * Compares two signal strengths. * * @param rssiA The power of the first signal measured in RSSI. @@ -3207,27 +3237,6 @@ public class WifiManager { } /** - * Method that triggers a notification to the user about a band conversion - * (e.g. 5 GHz to 2.4 GHz) to their saved AP config. - * - * @hide - */ - // TODO(b/144218444): move the notification to Settings instead of making this @SystemApi - @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) - public void notifyUserOfApBandConversion() { - Log.d(TAG, "apBand was converted, notify the user"); - try { - IWifiManager iWifiManager = getIWifiManager(); - if (iWifiManager == null) { - throw new RemoteException("Wifi service is not running"); - } - iWifiManager.notifyUserOfApBandConversion(mContext.getOpPackageName()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** * Enable/Disable TDLS on a specific local route. * * <p> @@ -5444,40 +5453,76 @@ public class WifiManager { } /** - * Interface for scan results listener. Should be implemented by applications and set when - * calling {@link WifiManager#addScanResultsListener(Executor, ScanResultsListener)}. + * Abstract class for scan results callback. Should be extended by applications and set when + * calling {@link WifiManager#registerScanResultsCallback(Executor, ScanResultsCallback)}. */ - public interface ScanResultsListener { + public abstract static class ScanResultsCallback { + private final ScanResultsCallbackProxy mScanResultsCallbackProxy; + + public ScanResultsCallback() { + mScanResultsCallbackProxy = new ScanResultsCallbackProxy(); + } /** - * Called when new scan results available. - * Caller should use {@link WifiManager#getScanResults()} to get the scan results. + * Called when new scan results are available. + * Clients should use {@link WifiManager#getScanResults()} to get the scan results. */ - void onScanResultsAvailable(); - } + public abstract void onScanResultsAvailable(); - private class ScanResultsListenerProxy extends IScanResultsListener.Stub { - private final Executor mExecutor; - private final ScanResultsListener mListener; - - ScanResultsListenerProxy(Executor executor, ScanResultsListener listener) { - mExecutor = executor; - mListener = listener; + /*package*/ @NonNull ScanResultsCallbackProxy getProxy() { + return mScanResultsCallbackProxy; } - @Override - public void onScanResultsAvailable() { - mExecutor.execute(mListener::onScanResultsAvailable); + private static class ScanResultsCallbackProxy extends IScanResultsCallback.Stub { + private final Object mLock = new Object(); + @Nullable @GuardedBy("mLock") private Executor mExecutor; + @Nullable @GuardedBy("mLock") private ScanResultsCallback mCallback; + + ScanResultsCallbackProxy() { + mCallback = null; + mExecutor = null; + } + + /*package*/ void initProxy(@NonNull Executor executor, + @NonNull ScanResultsCallback callback) { + synchronized (mLock) { + mExecutor = executor; + mCallback = callback; + } + } + + /*package*/ void cleanUpProxy() { + synchronized (mLock) { + mExecutor = null; + mCallback = null; + } + } + + @Override + public void onScanResultsAvailable() { + ScanResultsCallback callback; + Executor executor; + synchronized (mLock) { + executor = mExecutor; + callback = mCallback; + } + if (callback == null || executor == null) { + return; + } + Binder.clearCallingIdentity(); + executor.execute(callback::onScanResultsAvailable); + } } + } /** - * Add a listener for Scan Results. See {@link ScanResultsListener}. + * Register a callback for Scan Results. See {@link ScanResultsCallback}. * Caller will receive the event when scan results are available. * Caller should use {@link WifiManager#getScanResults()} requires * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} to get the scan results. - * Caller can remove a previously registered listener using - * {@link WifiManager#removeScanResultsListener(ScanResultsListener)} + * Caller can remove a previously registered callback using + * {@link WifiManager#unregisterScanResultsCallback(ScanResultsCallback)} * Same caller can add multiple listeners. * <p> * Applications should have the @@ -5485,49 +5530,52 @@ public class WifiManager { * without the permission will trigger a {@link java.lang.SecurityException}. * <p> * - * @param executor The executor to execute the listener of the {@code listener} object. - * @param listener listener for Scan Results events + * @param executor The executor to execute the callback of the {@code callback} object. + * @param callback callback for Scan Results events */ @RequiresPermission(ACCESS_WIFI_STATE) - public void addScanResultsListener(@NonNull @CallbackExecutor Executor executor, - @NonNull ScanResultsListener listener) { - if (listener == null) throw new IllegalArgumentException("listener cannot be null"); + public void registerScanResultsCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull ScanResultsCallback callback) { if (executor == null) throw new IllegalArgumentException("executor cannot be null"); - Log.v(TAG, "addScanResultsListener: listener=" + listener + ", executor=" + executor); + if (callback == null) throw new IllegalArgumentException("callback cannot be null"); + + Log.v(TAG, "registerScanResultsCallback: callback=" + callback + + ", executor=" + executor); + ScanResultsCallback.ScanResultsCallbackProxy proxy = callback.getProxy(); + proxy.initProxy(executor, callback); try { IWifiManager iWifiManager = getIWifiManager(); if (iWifiManager == null) { throw new RemoteException("Wifi service is not running"); } - iWifiManager.registerScanResultsListener( - new Binder(), - new ScanResultsListenerProxy(executor, listener), - listener.hashCode()); + iWifiManager.registerScanResultsCallback(proxy); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** - * Allow callers to remove a previously added listener. After calling this method, + * Allow callers to unregister a previously registered callback. After calling this method, * applications will no longer receive Scan Results events. * - * @param listener listener to remove for Scan Results events + * @param callback callback to unregister for Scan Results events */ @RequiresPermission(ACCESS_WIFI_STATE) - public void removeScanResultsListener(@NonNull ScanResultsListener listener) { - if (listener == null) throw new IllegalArgumentException("listener cannot be null"); - Log.v(TAG, "removeScanResultsListener: listener=" + listener); - + public void unregisterScanResultsCallback(@NonNull ScanResultsCallback callback) { + if (callback == null) throw new IllegalArgumentException("callback cannot be null"); + Log.v(TAG, "unregisterScanResultsCallback: Callback=" + callback); + ScanResultsCallback.ScanResultsCallbackProxy proxy = callback.getProxy(); try { IWifiManager iWifiManager = getIWifiManager(); if (iWifiManager == null) { throw new RemoteException("Wifi service is not running"); } - iWifiManager.unregisterScanResultsListener(listener.hashCode()); + iWifiManager.unregisterScanResultsCallback(proxy); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } finally { + proxy.cleanUpProxy(); } } diff --git a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java index b22ae07015c8..5a212a824452 100755 --- a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java +++ b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java @@ -22,6 +22,7 @@ import android.annotation.Nullable; import android.content.Context; import android.net.INetworkScoreCache; import android.net.NetworkKey; +import android.net.NetworkScoreManager; import android.net.ScoredNetwork; import android.os.Handler; import android.os.Process; @@ -40,7 +41,8 @@ import java.util.List; * * @hide */ -public class WifiNetworkScoreCache extends INetworkScoreCache.Stub { +public class WifiNetworkScoreCache extends INetworkScoreCache.Stub + implements NetworkScoreManager.NetworkScoreCallback { private static final String TAG = "WifiNetworkScoreCache"; private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); @@ -246,6 +248,17 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub { } @Override protected final void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + dumpWithLatestScanResults(fd, writer, args, wifiManager.getScanResults()); + } + + /** + * This is directly invoked from within Wifi-Service (on it's instance of this class), hence + * avoid making the WifiManager.getScanResults() call to avoid a deadlock. + */ + public final void dumpWithLatestScanResults( + FileDescriptor fd, PrintWriter writer, String[] args, + List<ScanResult> latestScanResults) { mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG); String header = String.format("WifiNetworkScoreCache (%s/%d)", mContext.getPackageName(), Process.myUid()); @@ -256,8 +269,7 @@ public class WifiNetworkScoreCache extends INetworkScoreCache.Stub { writer.println(" " + score); } writer.println(" Network scores for latest ScanResults:"); - WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); - for (ScanResult scanResult : wifiManager.getScanResults()) { + for (ScanResult scanResult : latestScanResults) { writer.println( " " + buildNetworkKey(scanResult) + ": " + getNetworkScore(scanResult)); } diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java index 0d36718f07f1..0de506610ec1 100644 --- a/wifi/java/android/net/wifi/WifiScanner.java +++ b/wifi/java/android/net/wifi/WifiScanner.java @@ -789,12 +789,11 @@ public class WifiScanner { /** * Enable/Disable wifi scanning. - * Note: WifiService calls this after any client interface mode changes (i.e. a new interface - * set up or an existing interface torn down) - * If there are >= 1 active client interface, invoke setScanningEnabled(true) - * If there are 0 active client interface, invoke setScanningEnabled(false) + * + * @param enable set to true to enable scanning, set to false to disable all types of scanning. * {@hide} */ + @SystemApi @RequiresPermission(Manifest.permission.NETWORK_STACK) public void setScanningEnabled(boolean enable) { validateChannel(); @@ -1291,12 +1290,15 @@ public class WifiScanner { * Applications will almost always want to use * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}. + * * @param context the application context - * @param service the Binder interface + * @param service the Binder interface for {@link Context#WIFI_SCANNING_SERVICE} * @param looper the Looper used to deliver callbacks + * * @hide */ - public WifiScanner(Context context, IWifiScanner service, Looper looper) { + public WifiScanner(@NonNull Context context, @NonNull IWifiScanner service, + @NonNull Looper looper) { mContext = context; mService = service; diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java index 5aab3470d979..7b37d652426d 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java @@ -158,7 +158,7 @@ public class WifiAwareManager { private final Object mLock = new Object(); // lock access to the following vars /** @hide */ - public WifiAwareManager(Context context, IWifiAwareManager service) { + public WifiAwareManager(@NonNull Context context, @NonNull IWifiAwareManager service) { mContext = context; mService = service; } diff --git a/wifi/java/android/net/wifi/rtt/WifiRttManager.java b/wifi/java/android/net/wifi/rtt/WifiRttManager.java index 770a12096806..cb0c5d41df90 100644 --- a/wifi/java/android/net/wifi/rtt/WifiRttManager.java +++ b/wifi/java/android/net/wifi/rtt/WifiRttManager.java @@ -77,7 +77,7 @@ public class WifiRttManager { "android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED"; /** @hide */ - public WifiRttManager(Context context, IWifiRttManager service) { + public WifiRttManager(@NonNull Context context, @NonNull IWifiRttManager service) { mContext = context; mService = service; } diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java index cf74ff07d2ee..534e609f9af4 100644 --- a/wifi/java/com/android/server/wifi/BaseWifiService.java +++ b/wifi/java/com/android/server/wifi/BaseWifiService.java @@ -26,6 +26,7 @@ import android.net.wifi.IDppCallback; import android.net.wifi.ILocalOnlyHotspotCallback; import android.net.wifi.INetworkRequestMatchCallback; import android.net.wifi.IOnWifiUsabilityStatsListener; +import android.net.wifi.IScanResultsCallback; import android.net.wifi.IScanResultsListener; import android.net.wifi.ISoftApCallback; import android.net.wifi.ISuggestionConnectionStatusListener; @@ -42,7 +43,6 @@ import android.net.wifi.hotspot2.IProvisioningCallback; import android.net.wifi.hotspot2.OsuProvider; import android.net.wifi.hotspot2.PasspointConfiguration; import android.os.IBinder; -import android.os.Messenger; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.WorkSource; @@ -325,7 +325,6 @@ public class BaseWifiService extends IWifiManager.Stub { throw new UnsupportedOperationException(); } - @Override public void notifyUserOfApBandConversion(String packageName) { throw new UnsupportedOperationException(); } @@ -514,18 +513,30 @@ public class BaseWifiService extends IWifiManager.Stub { throw new UnsupportedOperationException(); } - @Override + /** @deprecated replaced by {@link #registerScanResultsCallback(IScanResultsCallback)} */ + @Deprecated public void registerScanResultsListener( IBinder binder, IScanResultsListener listener, int listenerIdentifier) { throw new UnsupportedOperationException(); } - @Override + /** @deprecated replaced by {@link #unregisterScanResultsCallback(IScanResultsCallback)} */ + @Deprecated public void unregisterScanResultsListener(int listenerIdentifier) { throw new UnsupportedOperationException(); } @Override + public void registerScanResultsCallback(IScanResultsCallback callback) { + throw new UnsupportedOperationException(); + } + + @Override + public void unregisterScanResultsCallback(IScanResultsCallback callback) { + throw new UnsupportedOperationException(); + } + + @Override public void registerSuggestionConnectionStatusListener(IBinder binder, ISuggestionConnectionStatusListener listener, int listenerIdentifier, String packageName, String featureId) { @@ -537,4 +548,9 @@ public class BaseWifiService extends IWifiManager.Stub { String packageName) { throw new UnsupportedOperationException(); } + + @Override + public int calculateSignalLevel(int rssi) { + throw new UnsupportedOperationException(); + } } diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java index 6d7e621a9bc2..7e38e147427f 100644 --- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java @@ -19,6 +19,7 @@ package android.net.wifi; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import android.net.MacAddress; @@ -90,37 +91,6 @@ public class WifiConfigurationTest { } @Test - public void testNetworkSelectionStatusCopy() { - NetworkSelectionStatus networkSelectionStatus = new NetworkSelectionStatus(); - networkSelectionStatus.setNotRecommended(true); - - NetworkSelectionStatus copy = new NetworkSelectionStatus(); - copy.copy(networkSelectionStatus); - - assertEquals(networkSelectionStatus.isNotRecommended(), copy.isNotRecommended()); - } - - @Test - public void testNetworkSelectionStatusParcel() { - NetworkSelectionStatus networkSelectionStatus = new NetworkSelectionStatus(); - networkSelectionStatus.setNotRecommended(true); - - Parcel parcelW = Parcel.obtain(); - networkSelectionStatus.writeToParcel(parcelW); - byte[] bytes = parcelW.marshall(); - parcelW.recycle(); - - Parcel parcelR = Parcel.obtain(); - parcelR.unmarshall(bytes, 0, bytes.length); - parcelR.setDataPosition(0); - - NetworkSelectionStatus copy = new NetworkSelectionStatus(); - copy.readFromParcel(parcelR); - - assertEquals(networkSelectionStatus.isNotRecommended(), copy.isNotRecommended()); - } - - @Test public void testIsOpenNetwork_IsOpen_NullWepKeys() { WifiConfiguration config = new WifiConfiguration(); config.allowedKeyManagement.clear(); @@ -348,4 +318,18 @@ public class WifiConfigurationTest { config.allowedKeyManagement.set(KeyMgmt.NONE); assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.NONE], config.getSsidAndSecurityTypeString()); } + + /** + * Ensure that the {@link NetworkSelectionStatus.DisableReasonInfo}s are populated in + * {@link NetworkSelectionStatus#DISABLE_REASON_INFOS} for reason codes from 0 to + * {@link NetworkSelectionStatus#NETWORK_SELECTION_DISABLED_MAX} - 1. + */ + @Test + public void testNetworkSelectionDisableReasonInfosPopulated() { + assertEquals(NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX, + NetworkSelectionStatus.DISABLE_REASON_INFOS.size()); + for (int i = 0; i < NetworkSelectionStatus.NETWORK_SELECTION_DISABLED_MAX; i++) { + assertNotNull(NetworkSelectionStatus.DISABLE_REASON_INFOS.get(i)); + } + } } diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index 06ebc1b3f6da..8cdcba67386b 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -60,7 +60,7 @@ import android.net.wifi.WifiManager.LocalOnlyHotspotSubscription; import android.net.wifi.WifiManager.NetworkRequestMatchCallback; import android.net.wifi.WifiManager.NetworkRequestUserSelectionCallback; import android.net.wifi.WifiManager.OnWifiUsabilityStatsListener; -import android.net.wifi.WifiManager.ScanResultsListener; +import android.net.wifi.WifiManager.ScanResultsCallback; import android.net.wifi.WifiManager.SoftApCallback; import android.net.wifi.WifiManager.SuggestionConnectionStatusListener; import android.net.wifi.WifiManager.TrafficStateCallback; @@ -112,15 +112,16 @@ public class WifiManagerTest { @Mock TrafficStateCallback mTrafficStateCallback; @Mock NetworkRequestMatchCallback mNetworkRequestMatchCallback; @Mock OnWifiUsabilityStatsListener mOnWifiUsabilityStatsListener; - @Mock ScanResultsListener mScanResultListener; @Mock SuggestionConnectionStatusListener mListener; - @Mock Executor mCallbackExecutor; + @Mock Runnable mRunnable; @Mock Executor mExecutor; + @Mock Executor mAnotherExecutor; private Handler mHandler; private TestLooper mLooper; private WifiManager mWifiManager; private WifiNetworkSuggestion mWifiNetworkSuggestion; + private ScanResultsCallback mScanResultsCallback; @Before public void setUp() throws Exception { @@ -133,6 +134,12 @@ public class WifiManagerTest { mWifiManager = new WifiManager(mContext, mWifiService, mLooper.getLooper()); verify(mWifiService).getVerboseLoggingLevel(); mWifiNetworkSuggestion = new WifiNetworkSuggestion(); + mScanResultsCallback = new ScanResultsCallback() { + @Override + public void onScanResultsAvailable() { + mRunnable.run(); + } + }; } /** @@ -1778,65 +1785,81 @@ public class WifiManagerTest { } /** - * Verify an IllegalArgumentException is thrown if listener is not provided. + * Verify an IllegalArgumentException is thrown if callback is not provided. */ @Test(expected = IllegalArgumentException.class) - public void testAddScanResultsListenerWithNullListener() throws Exception { - mWifiManager.addScanResultsListener(mCallbackExecutor, null); + public void testRegisterScanResultsCallbackWithNullCallback() throws Exception { + mWifiManager.registerScanResultsCallback(mExecutor, null); } /** * Verify an IllegalArgumentException is thrown if executor is not provided. */ @Test(expected = IllegalArgumentException.class) - public void testAddScanResultsListenerWithNullExecutor() throws Exception { - mWifiManager.addScanResultsListener(null, mScanResultListener); + public void testRegisterCallbackWithNullExecutor() throws Exception { + mWifiManager.registerScanResultsCallback(null, mScanResultsCallback); } /** - * Verify client provided listener is being called to the right listener. + * Verify client provided callback is being called to the right callback. */ @Test - public void testAddScanResultsListenerAndReceiveEvent() throws Exception { - ArgumentCaptor<IScanResultsListener.Stub> callbackCaptor = - ArgumentCaptor.forClass(IScanResultsListener.Stub.class); - Executor executor = new SynchronousExecutor(); - mWifiManager.addScanResultsListener(executor, mScanResultListener); - verify(mWifiService).registerScanResultsListener(any(IBinder.class), - callbackCaptor.capture(), anyInt()); + public void testAddScanResultsCallbackAndReceiveEvent() throws Exception { + ArgumentCaptor<IScanResultsCallback.Stub> callbackCaptor = + ArgumentCaptor.forClass(IScanResultsCallback.Stub.class); + mWifiManager.registerScanResultsCallback(new SynchronousExecutor(), mScanResultsCallback); + verify(mWifiService).registerScanResultsCallback(callbackCaptor.capture()); callbackCaptor.getValue().onScanResultsAvailable(); - verify(mScanResultListener).onScanResultsAvailable(); + verify(mRunnable).run(); } /** - * Verify client provided listener is being called on the right executor. + * Verify client provided callback is being called to the right executor. */ @Test - public void testAddScanResultsListenerWithTheTargetExecutor() throws Exception { - ArgumentCaptor<IScanResultsListener.Stub> callbackCaptor = - ArgumentCaptor.forClass(IScanResultsListener.Stub.class); - mWifiManager.addScanResultsListener(mExecutor, mScanResultListener); - verify(mWifiService).registerScanResultsListener(any(IBinder.class), - callbackCaptor.capture(), anyInt()); + public void testRegisterScanResultsCallbackWithTheTargetExecutor() throws Exception { + ArgumentCaptor<IScanResultsCallback.Stub> callbackCaptor = + ArgumentCaptor.forClass(IScanResultsCallback.Stub.class); + mWifiManager.registerScanResultsCallback(mExecutor, mScanResultsCallback); + verify(mWifiService).registerScanResultsCallback(callbackCaptor.capture()); + mWifiManager.registerScanResultsCallback(mAnotherExecutor, mScanResultsCallback); callbackCaptor.getValue().onScanResultsAvailable(); - verify(mExecutor).execute(any(Runnable.class)); + verify(mExecutor, never()).execute(any(Runnable.class)); + verify(mAnotherExecutor).execute(any(Runnable.class)); } /** - * Verify client removeScanResultsListener. + * Verify client register unregister then register again, to ensure callback still works. */ @Test - public void testRemoveScanResultsListener() throws Exception { - mWifiManager.removeScanResultsListener(mScanResultListener); - verify(mWifiService).unregisterScanResultsListener(anyInt()); + public void testRegisterUnregisterThenRegisterAgainWithScanResultCallback() throws Exception { + ArgumentCaptor<IScanResultsCallback.Stub> callbackCaptor = + ArgumentCaptor.forClass(IScanResultsCallback.Stub.class); + mWifiManager.registerScanResultsCallback(new SynchronousExecutor(), mScanResultsCallback); + verify(mWifiService).registerScanResultsCallback(callbackCaptor.capture()); + mWifiManager.unregisterScanResultsCallback(mScanResultsCallback); + callbackCaptor.getValue().onScanResultsAvailable(); + verify(mRunnable, never()).run(); + mWifiManager.registerScanResultsCallback(new SynchronousExecutor(), mScanResultsCallback); + callbackCaptor.getValue().onScanResultsAvailable(); + verify(mRunnable).run(); } /** - * Verify client removeScanResultsListener with null listener will cause an exception. + * Verify client unregisterScanResultsCallback. + */ + @Test + public void testUnregisterScanResultsCallback() throws Exception { + mWifiManager.unregisterScanResultsCallback(mScanResultsCallback); + verify(mWifiService).unregisterScanResultsCallback(any()); + } + + /** + * Verify client unregisterScanResultsCallback with null callback will cause an exception. */ @Test(expected = IllegalArgumentException.class) - public void testRemoveScanResultsListenerWithNullListener() throws Exception { - mWifiManager.removeScanResultsListener(null); + public void testUnregisterScanResultsCallbackWithNullCallback() throws Exception { + mWifiManager.unregisterScanResultsCallback(null); } /** @@ -1899,8 +1922,25 @@ public class WifiManagerTest { */ @Test public void testRemoveSuggestionConnectionListener() throws Exception { - mWifiManager.removeSuggestionConnectionStatusListener(mListener); verify(mWifiService).unregisterSuggestionConnectionStatusListener(anyInt(), anyString()); } + + /** Test {@link WifiManager#calculateSignalLevel(int)} */ + @Test + public void testCalculateSignalLevel() throws Exception { + when(mWifiService.calculateSignalLevel(anyInt())).thenReturn(3); + int actual = mWifiManager.calculateSignalLevel(-60); + verify(mWifiService).calculateSignalLevel(-60); + assertEquals(3, actual); + } + + /** Test {@link WifiManager#getMaxSignalLevel()} */ + @Test + public void testGetMaxSignalLevel() throws Exception { + when(mWifiService.calculateSignalLevel(anyInt())).thenReturn(4); + int actual = mWifiManager.getMaxSignalLevel(); + verify(mWifiService).calculateSignalLevel(Integer.MAX_VALUE); + assertEquals(4, actual); + } } |