summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt5
-rw-r--r--core/java/android/content/pm/LAUNCHER_OWNERS7
-rw-r--r--core/java/android/content/pm/SHORTCUT_OWNERS7
-rw-r--r--core/java/com/android/internal/os/KernelCpuUidTimeReader.java4
-rw-r--r--data/etc/privapp-permissions-platform.xml2
-rw-r--r--data/etc/services.core.protolog.json18
-rw-r--r--graphics/java/android/graphics/RenderEffect.java19
-rw-r--r--media/java/android/media/tv/TvContract.java65
-rw-r--r--packages/SettingsLib/Android.bp1
-rw-r--r--packages/SettingsLib/UsageProgressBarPreference/Android.bp13
-rw-r--r--packages/SettingsLib/UsageProgressBarPreference/AndroidManifest.xml23
-rw-r--r--packages/SettingsLib/UsageProgressBarPreference/res/layout/preference_usage_progress_bar.xml61
-rw-r--r--packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java160
-rw-r--r--packages/SettingsLib/res/values/styles_support_preference.xml1
-rw-r--r--packages/SettingsLib/tests/integ/Android.bp2
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/UsageProgressBarPreferenceTest.java100
-rw-r--r--packages/SystemUI/res/values/strings.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java449
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java9
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java22
-rw-r--r--services/core/java/com/android/server/ConnectivityServiceInitializer.java9
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java8
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerConstants.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java14
-rw-r--r--services/core/java/com/android/server/wm/ConfigurationContainer.java11
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java131
-rw-r--r--services/core/java/com/android/server/wm/Task.java470
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java176
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java12
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java15
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java8
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java14
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java19
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java24
-rw-r--r--tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt5
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java8
38 files changed, 1558 insertions, 362 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index 99d8b51e185f..0defc05fc5d0 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -24277,7 +24277,9 @@ package android.media.tv {
field public static final String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
field public static final String COLUMN_APP_LINK_POSTER_ART_URI = "app_link_poster_art_uri";
field public static final String COLUMN_APP_LINK_TEXT = "app_link_text";
+ field public static final String COLUMN_BROADCAST_GENRE = "broadcast_genre";
field public static final String COLUMN_BROWSABLE = "browsable";
+ field public static final String COLUMN_CHANNEL_LIST_ID = "channel_list_id";
field public static final String COLUMN_DESCRIPTION = "description";
field public static final String COLUMN_DISPLAY_NAME = "display_name";
field public static final String COLUMN_DISPLAY_NUMBER = "display_number";
@@ -24292,6 +24294,8 @@ package android.media.tv {
field public static final String COLUMN_LOCKED = "locked";
field public static final String COLUMN_NETWORK_AFFILIATION = "network_affiliation";
field public static final String COLUMN_ORIGINAL_NETWORK_ID = "original_network_id";
+ field public static final String COLUMN_REMOTE_CONTROL_KEY_PRESET_NUMBER = "remote_control_key_preset_number";
+ field public static final String COLUMN_SCRAMBLED = "scrambled";
field public static final String COLUMN_SEARCHABLE = "searchable";
field public static final String COLUMN_SERVICE_ID = "service_id";
field public static final String COLUMN_SERVICE_TYPE = "service_type";
@@ -24300,6 +24304,7 @@ package android.media.tv {
field public static final String COLUMN_TYPE = "type";
field public static final String COLUMN_VERSION_NUMBER = "version_number";
field public static final String COLUMN_VIDEO_FORMAT = "video_format";
+ field public static final String COLUMN_VIDEO_RESOLUTION = "video_resolution";
field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/channel";
field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/channel";
field public static final android.net.Uri CONTENT_URI;
diff --git a/core/java/android/content/pm/LAUNCHER_OWNERS b/core/java/android/content/pm/LAUNCHER_OWNERS
new file mode 100644
index 000000000000..400836f55ceb
--- /dev/null
+++ b/core/java/android/content/pm/LAUNCHER_OWNERS
@@ -0,0 +1,7 @@
+set noparent
+
+omakoto@google.com
+sunnygoyal@google.com
+mett@google.com
+jonmiranda@google.com
+pinyaoting@google.com
diff --git a/core/java/android/content/pm/SHORTCUT_OWNERS b/core/java/android/content/pm/SHORTCUT_OWNERS
new file mode 100644
index 000000000000..3688d5a3a4c7
--- /dev/null
+++ b/core/java/android/content/pm/SHORTCUT_OWNERS
@@ -0,0 +1,7 @@
+set noparent
+
+omakoto@google.com
+yamasani@google.com
+sunnygoyal@google.com
+mett@google.com
+pinyaoting@google.com
diff --git a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
index f7fad2c5bbaa..2dd51b4459e7 100644
--- a/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
+++ b/core/java/com/android/internal/os/KernelCpuUidTimeReader.java
@@ -143,6 +143,10 @@ public abstract class KernelCpuUidTimeReader<T> {
*/
public void removeUid(int uid) {
mLastTimes.delete(uid);
+
+ if (mBpfTimesAvailable) {
+ mBpfReader.removeUidsInRange(uid, uid);
+ }
}
/**
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index d601029640dd..e44ab34285a4 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -469,6 +469,8 @@ applications that come with the platform
<privapp-permissions package="com.android.traceur">
<!-- Permissions required to receive BUGREPORT_STARTED intent -->
<permission name="android.permission.DUMP"/>
+ <!-- Permissions required to start/stop tracing -->
+ <permission name="android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND"/>
<!-- Permissions required for quick settings tile -->
<permission name="android.permission.STATUS_BAR"/>
</privapp-permissions>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index faf49733050a..145ad1368108 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -49,12 +49,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "-2062338592": {
- "message": "Looking for task of %s",
- "level": "DEBUG",
- "group": "WM_DEBUG_TASKS",
- "at": "com\/android\/server\/wm\/RootWindowContainer.java"
- },
"-2054442123": {
"message": "Setting Intent of %s to %s",
"level": "VERBOSE",
@@ -475,6 +469,12 @@
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
"at": "com\/android\/server\/wm\/Transition.java"
},
+ "-1559645910": {
+ "message": "Looking for task of type=%s, taskAffinity=%s, intent=%s, info=%s, preferredTDA=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+ },
"-1558137010": {
"message": "Config is relaunching invisible activity %s called by %s",
"level": "VERBOSE",
@@ -1531,6 +1531,12 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "-373110070": {
+ "message": "Skipping task: (mismatch activity\/task) %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_TASKS",
+ "at": "com\/android\/server\/wm\/RootWindowContainer.java"
+ },
"-354571697": {
"message": "Existence Changed in transition %d: %s",
"level": "VERBOSE",
diff --git a/graphics/java/android/graphics/RenderEffect.java b/graphics/java/android/graphics/RenderEffect.java
index 8b9e36a3b6b1..496e4707dbff 100644
--- a/graphics/java/android/graphics/RenderEffect.java
+++ b/graphics/java/android/graphics/RenderEffect.java
@@ -24,7 +24,11 @@ import libcore.util.NativeAllocationRegistry;
/**
* Intermediate rendering step used to render drawing commands with a corresponding
- * visual effect
+ * visual effect. A {@link RenderEffect} can be configured on a {@link RenderNode} through
+ * {@link RenderNode#setRenderEffect(RenderEffect)} and will be applied when drawn through
+ * {@link Canvas#drawRenderNode(RenderNode)}.
+ * Additionally a {@link RenderEffect} can be applied to a View's backing RenderNode through
+ * {@link android.view.View#setRenderEffect(RenderEffect)}
*/
public final class RenderEffect {
@@ -156,7 +160,8 @@ public final class RenderEffect {
* @param src Optional subset of the bitmap to be part of the rendered output. If null
* is provided, the entire bitmap bounds are used.
* @param dst Bounds of the destination which the bitmap is translated and scaled to be
- * drawn into
+ * drawn into within the bounds of the {@link RenderNode} this RenderEffect is
+ * installed on
*/
@NonNull
public static RenderEffect createBitmapEffect(
@@ -222,8 +227,8 @@ public final class RenderEffect {
* {@link RenderEffect} that is a composition of 2 other {@link RenderEffect} instances
* combined by the specified {@link BlendMode}
*
- * @param dst The Dst pixels used in blending, if null the source bitmap is used.
- * @param src The Src pixels used in blending, if null the source bitmap is use
+ * @param dst The Dst pixels used in blending
+ * @param src The Src pixels used in blending
* @param blendMode The {@link BlendMode} to be used to combine colors from the two
* {@link RenderEffect}s
*/
@@ -246,7 +251,11 @@ public final class RenderEffect {
* Create a filter that composes 'inner' with 'outer', such that the results of 'inner' are
* treated as the source bitmap passed to 'outer', i.e.
*
- * result = outer(inner(source)).
+ * <pre>
+ * {@code
+ * result = outer(inner(source))
+ * }
+ * </pre>
*
* Consumers should favor explicit chaining of {@link RenderEffect} instances at creation time
* rather than using chain effect. Chain effects are useful for situations where the input or
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 433c6227cd5f..30a14c84b72e 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -2450,6 +2450,71 @@ public final class TvContract {
*/
public static final String COLUMN_GLOBAL_CONTENT_ID = "global_content_id";
+ /**
+ * The remote control key preset number that is assigned to this channel.
+ *
+ * <p> This can be used for one-touch-tuning, tuning to the channel with
+ * pressing the preset button.
+ *
+ * <p> Type: INTEGER (remote control key preset number)
+ */
+ public static final String COLUMN_REMOTE_CONTROL_KEY_PRESET_NUMBER =
+ "remote_control_key_preset_number";
+
+ /**
+ * The flag indicating whether this TV channel is scrambled or not.
+ *
+ * <p>Use the same coding for scrambled in the underlying broadcast standard
+ * if {@code free_ca_mode} in SDT is defined there (e.g. ETSI EN 300 468).
+ *
+ * <p>Type: INTEGER (boolean)
+ */
+ public static final String COLUMN_SCRAMBLED = "scrambled";
+
+ /**
+ * The typical video resolution.
+ *
+ * <p>This is primarily used to filter out channels based on video resolution
+ * by applications. The value is from SDT if defined there. (e.g. ETSI EN 300 468)
+ * The value should match one of the followings: {@link #VIDEO_RESOLUTION_SD},
+ * {@link #VIDEO_RESOLUTION_HD}, {@link #VIDEO_RESOLUTION_UHD}.
+ *
+ * <p>Type: TEXT
+ *
+ */
+ public static final String COLUMN_VIDEO_RESOLUTION = "video_resolution";
+
+ /**
+ * The channel list ID of this TV channel.
+ *
+ * <p>It is used to identify the channel list constructed from broadcast SI based on the
+ * underlying broadcast standard or country/operator profile, if applicable. Otherwise,
+ * leave empty.
+ *
+ * <p>The ID can be defined by individual TV input services. For example, one may assign a
+ * service operator name for the service operator channel list constructed from broadcast
+ * SI or one may assign the {@code profile_name} of the operator_info() APDU defined in CI
+ * Plus 1.3 for the dedicated CICAM operator profile channel list constructed
+ * from CICAM NIT.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_CHANNEL_LIST_ID = "channel_list_id";
+
+ /**
+ * The comma-separated genre string of this TV channel.
+ *
+ * <p>Use the same language appeared in the underlying broadcast standard, if applicable.
+ * Otherwise, leave empty. Use
+ * {@link Genres#encode Genres.encode()} to create a text that can be stored in this column.
+ * Use {@link Genres#decode Genres.decode()} to get the broadcast genre strings from the
+ * text stored in the column.
+ *
+ * <p>Type: TEXT
+ * @see Programs#COLUMN_BROADCAST_GENRE
+ */
+ public static final String COLUMN_BROADCAST_GENRE = Programs.COLUMN_BROADCAST_GENRE;
+
private Channels() {}
/**
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 383416221901..0d4e7460c21f 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -56,6 +56,7 @@ java_defaults {
"SettingsLibTopIntroPreference",
"SettingsLibBannerMessagePreference",
"SettingsLibFooterPreference",
+ "SettingsLibUsageProgressBarPreference",
],
}
diff --git a/packages/SettingsLib/UsageProgressBarPreference/Android.bp b/packages/SettingsLib/UsageProgressBarPreference/Android.bp
new file mode 100644
index 000000000000..f346a5962d1c
--- /dev/null
+++ b/packages/SettingsLib/UsageProgressBarPreference/Android.bp
@@ -0,0 +1,13 @@
+android_library {
+ name: "SettingsLibUsageProgressBarPreference",
+
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+
+ static_libs: [
+ "androidx.preference_preference",
+ ],
+
+ sdk_version: "system_current",
+ min_sdk_version: "21",
+}
diff --git a/packages/SettingsLib/UsageProgressBarPreference/AndroidManifest.xml b/packages/SettingsLib/UsageProgressBarPreference/AndroidManifest.xml
new file mode 100644
index 000000000000..51fc7ed64660
--- /dev/null
+++ b/packages/SettingsLib/UsageProgressBarPreference/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.settingslib.widget">
+
+ <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/UsageProgressBarPreference/res/layout/preference_usage_progress_bar.xml b/packages/SettingsLib/UsageProgressBarPreference/res/layout/preference_usage_progress_bar.xml
new file mode 100644
index 000000000000..9dbd5fa4b2d2
--- /dev/null
+++ b/packages/SettingsLib/UsageProgressBarPreference/res/layout/preference_usage_progress_bar.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:orientation="vertical"
+ android:layout_marginStart="16dp"
+ android:layout_marginEnd="16dp"
+ android:paddingTop="32dp"
+ android:paddingBottom="32dp">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TextView
+ android:id="@+id/usage_summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:layout_alignBaseline="@id/total_summary"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:fontFamily="@*android:string/config_headlineFontFamily"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Display1"
+ android:textSize="20sp"/>
+ <TextView
+ android:id="@+id/total_summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentEnd="true"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"/>
+ </RelativeLayout>
+
+ <ProgressBar
+ android:id="@android:id/progress"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:scaleY="2"
+ android:layout_marginTop="4dp"
+ android:max="100"/>
+</LinearLayout>
diff --git a/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java b/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java
new file mode 100644
index 000000000000..950a8b4ad7cc
--- /dev/null
+++ b/packages/SettingsLib/UsageProgressBarPreference/src/com/android/settingslib/widget/UsageProgressBarPreference.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2021 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.widget;
+
+import android.content.Context;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.TextUtils;
+import android.text.style.RelativeSizeSpan;
+import android.util.AttributeSet;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Progres bar preference with a usage summary and a total summary.
+ * This preference shows number in usage summary with enlarged font size.
+ */
+public class UsageProgressBarPreference extends Preference {
+
+ private final Pattern mNumberPattern = Pattern.compile("[\\d]*\\.?[\\d]+");
+
+ private CharSequence mUsageSummary;
+ private CharSequence mTotalSummary;
+ private int mPercent = -1;
+
+ /**
+ * Perform inflation from XML and apply a class-specific base style.
+ *
+ * @param context The {@link Context} this is associated with, through which it can
+ * access the current theme, resources, {@link SharedPreferences}, etc.
+ * @param attrs The attributes of the XML tag that is inflating the preference
+ * @param defStyle An attribute in the current theme that contains a reference to a style
+ * resource that supplies default values for the view. Can be 0 to not
+ * look for defaults.
+ */
+ public UsageProgressBarPreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ setLayoutResource(R.layout.preference_usage_progress_bar);
+ }
+
+ /**
+ * Perform inflation from XML and apply a class-specific base style.
+ *
+ * @param context The {@link Context} this is associated with, through which it can
+ * access the current theme, resources, {@link SharedPreferences}, etc.
+ * @param attrs The attributes of the XML tag that is inflating the preference
+ */
+ public UsageProgressBarPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setLayoutResource(R.layout.preference_usage_progress_bar);
+ }
+
+ /**
+ * Constructor to create a preference.
+ *
+ * @param context The Context this is associated with.
+ */
+ public UsageProgressBarPreference(Context context) {
+ this(context, null);
+ }
+
+ /** Set usage summary, number in the summary will show with enlarged font size. */
+ public void setUsageSummary(CharSequence usageSummary) {
+ if (TextUtils.equals(mUsageSummary, usageSummary)) {
+ return;
+ }
+ mUsageSummary = usageSummary;
+ notifyChanged();
+ }
+
+ /** Set total summary. */
+ public void setTotalSummary(CharSequence totalSummary) {
+ if (TextUtils.equals(mTotalSummary, totalSummary)) {
+ return;
+ }
+ mTotalSummary = totalSummary;
+ notifyChanged();
+ }
+
+ /** Set percentage of the progress bar. */
+ public void setPercent(long usage, long total) {
+ if (total == 0L || usage > total) {
+ return;
+ }
+ final int percent = (int) (usage / (double) total * 100);
+ if (mPercent == percent) {
+ return;
+ }
+ mPercent = percent;
+ notifyChanged();
+ }
+
+ /**
+ * Binds the created View to the data for this preference.
+ *
+ * <p>This is a good place to grab references to custom Views in the layout and set
+ * properties on them.
+ *
+ * <p>Make sure to call through to the superclass's implementation.
+ *
+ * @param holder The ViewHolder that provides references to the views to fill in. These views
+ * will be recycled, so you should not hold a reference to them after this method
+ * returns.
+ */
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+
+ final TextView usageSummary = (TextView) holder.findViewById(R.id.usage_summary);
+ usageSummary.setText(enlargeFontOfNumber(mUsageSummary));
+
+ final TextView totalSummary = (TextView) holder.findViewById(R.id.total_summary);
+ if (mTotalSummary != null) {
+ totalSummary.setText(mTotalSummary);
+ }
+
+ final ProgressBar progressBar = (ProgressBar) holder.findViewById(android.R.id.progress);
+ if (mPercent < 0) {
+ progressBar.setIndeterminate(true);
+ } else {
+ progressBar.setIndeterminate(false);
+ progressBar.setProgress(mPercent);
+ }
+ }
+
+ private CharSequence enlargeFontOfNumber(CharSequence summary) {
+ if (TextUtils.isEmpty(summary)) {
+ return "";
+ }
+
+ final Matcher matcher = mNumberPattern.matcher(summary);
+ if (matcher.find()) {
+ final SpannableString spannableSummary = new SpannableString(summary);
+ spannableSummary.setSpan(new RelativeSizeSpan(2.4f), matcher.start(),
+ matcher.end(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ return spannableSummary;
+ }
+ return summary;
+ }
+}
diff --git a/packages/SettingsLib/res/values/styles_support_preference.xml b/packages/SettingsLib/res/values/styles_support_preference.xml
index 6e611960b2c7..8ba9033ef1fb 100644
--- a/packages/SettingsLib/res/values/styles_support_preference.xml
+++ b/packages/SettingsLib/res/values/styles_support_preference.xml
@@ -23,7 +23,6 @@
<!-- Footer Preferences -->
<style name="Preference.FooterPreference.SettingsBase" parent="@style/Preference.Material">
<item name="android:layout">@layout/preference_footer</item>
- <item name="allowDividerAbove">true</item>
</style>
<style name="PreferenceThemeOverlay.SettingsBase" parent="@style/PreferenceThemeOverlay">
diff --git a/packages/SettingsLib/tests/integ/Android.bp b/packages/SettingsLib/tests/integ/Android.bp
index 2ccff1ecaf6c..f6f9dba784a0 100644
--- a/packages/SettingsLib/tests/integ/Android.bp
+++ b/packages/SettingsLib/tests/integ/Android.bp
@@ -33,10 +33,12 @@ android_test {
test_suites: ["device-tests"],
static_libs: [
+ "androidx.test.core",
"androidx.test.rules",
"androidx.test.espresso.core",
"mockito-target-minus-junit4",
"truth-prebuilt",
+ "SettingsLibUsageProgressBarPreference",
],
dxflags: ["--multi-dex"],
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/UsageProgressBarPreferenceTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/UsageProgressBarPreferenceTest.java
new file mode 100644
index 000000000000..85e2174bf87a
--- /dev/null
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/widget/UsageProgressBarPreferenceTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2021 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.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.text.SpannedString;
+import android.text.style.RelativeSizeSpan;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import androidx.preference.PreferenceViewHolder;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class UsageProgressBarPreferenceTest {
+
+ private UsageProgressBarPreference mUsageProgressBarPreference;
+ private PreferenceViewHolder mViewHolder;
+
+ @Before
+ public void setUp() {
+ final Context context = ApplicationProvider.getApplicationContext();
+ mUsageProgressBarPreference = new UsageProgressBarPreference(context);
+ final LayoutInflater inflater = LayoutInflater.from(context);
+ final View rootView = inflater.inflate(mUsageProgressBarPreference.getLayoutResource(),
+ new LinearLayout(context), false /* attachToRoot */);
+ mViewHolder = PreferenceViewHolder.createInstanceForTests(rootView);
+ }
+
+ @Test
+ public void setUsageSummary_noNumber_noRelativeSizeSpan() {
+ mUsageProgressBarPreference.setUsageSummary("test");
+
+ mUsageProgressBarPreference.onBindViewHolder(mViewHolder);
+
+ final TextView usageSummary = (TextView) mViewHolder.findViewById(R.id.usage_summary);
+ final SpannedString summary = new SpannedString(usageSummary.getText());
+ assertThat(summary.getSpans(0, summary.length(), RelativeSizeSpan.class).length)
+ .isEqualTo(0);
+ }
+
+ @Test
+ public void setUsageSummary_integerNumber_findRelativeSizeSpan() {
+ mUsageProgressBarPreference.setUsageSummary("10Test");
+
+ mUsageProgressBarPreference.onBindViewHolder(mViewHolder);
+
+ final TextView usageSummary = (TextView) mViewHolder.findViewById(R.id.usage_summary);
+ final SpannedString summary = new SpannedString(usageSummary.getText());
+ assertThat(summary.getSpans(0, summary.length(), RelativeSizeSpan.class).length)
+ .isEqualTo(1);
+ }
+
+ @Test
+ public void setUsageSummary_floatNumber_findRelativeSizeSpan() {
+ mUsageProgressBarPreference.setUsageSummary("3.14Test");
+
+ mUsageProgressBarPreference.onBindViewHolder(mViewHolder);
+
+ final TextView usageSummary = (TextView) mViewHolder.findViewById(R.id.usage_summary);
+ final SpannedString summary = new SpannedString(usageSummary.getText());
+ assertThat(summary.getSpans(0, summary.length(), RelativeSizeSpan.class).length)
+ .isEqualTo(1);
+ }
+
+ @Test
+ public void setPercent_getCorrectProgress() {
+ mUsageProgressBarPreference.setPercent(31, 80);
+
+ mUsageProgressBarPreference.onBindViewHolder(mViewHolder);
+
+ final ProgressBar progressBar = (ProgressBar) mViewHolder
+ .findViewById(android.R.id.progress);
+ assertThat(progressBar.getProgress()).isEqualTo((int) (31.0f / 80 * 100));
+ }
+}
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index db6427970ba1..86af4647ed7a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -839,6 +839,8 @@
<string name="quick_settings_user_new_user">New user</string>
<!-- QuickSettings: Wifi [CHAR LIMIT=NONE] -->
<string name="quick_settings_wifi_label">Wi-Fi</string>
+ <!-- QuickSettings: Internet [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_internet_label">Internet</string>
<!-- QuickSettings: Wifi (Not connected) [CHAR LIMIT=NONE] -->
<string name="quick_settings_wifi_not_connected">Not Connected</string>
<!-- QuickSettings: Wifi (No network) [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 0d0d01249c3d..ac3fd4b51931 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -28,6 +28,7 @@ import android.provider.Settings.Secure;
import android.service.quicksettings.Tile;
import android.text.TextUtils;
import android.util.ArraySet;
+import android.util.FeatureFlagUtils;
import android.util.Log;
import com.android.internal.logging.InstanceId;
@@ -444,6 +445,11 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
final ArrayList<String> tiles = new ArrayList<String>();
boolean addedDefault = false;
Set<String> addedSpecs = new ArraySet<>();
+ // TODO(b/174753536): Move it into the config file.
+ if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL)) {
+ tiles.add("internet");
+ addedSpecs.add("internet");
+ }
for (String tile : tileList.split(",")) {
tile = tile.trim();
if (tile.isEmpty()) continue;
@@ -459,6 +465,12 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
addedDefault = true;
}
} else {
+ // TODO(b/174753536): Move it into the config file.
+ if (FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL)) {
+ if (tile.equals("wifi") || tile.equals("cell")) {
+ continue;
+ }
+ }
if (!addedSpecs.contains(tile)) {
tiles.add(tile);
addedSpecs.add(tile);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 24c0fd76d827..e9d481b2e7f0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -37,6 +37,7 @@ import com.android.systemui.qs.tiles.DataSaverTile;
import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.qs.tiles.FlashlightTile;
import com.android.systemui.qs.tiles.HotspotTile;
+import com.android.systemui.qs.tiles.InternetTile;
import com.android.systemui.qs.tiles.LocationTile;
import com.android.systemui.qs.tiles.NfcTile;
import com.android.systemui.qs.tiles.NightDisplayTile;
@@ -60,6 +61,7 @@ public class QSFactoryImpl implements QSFactory {
private static final String TAG = "QSFactory";
private final Provider<WifiTile> mWifiTileProvider;
+ private final Provider<InternetTile> mInternetTileProvider;
private final Provider<BluetoothTile> mBluetoothTileProvider;
private final Provider<CellularTile> mCellularTileProvider;
private final Provider<DndTile> mDndTileProvider;
@@ -89,6 +91,7 @@ public class QSFactoryImpl implements QSFactory {
Lazy<QSHost> qsHostLazy,
Provider<CustomTile.Builder> customTileBuilderProvider,
Provider<WifiTile> wifiTileProvider,
+ Provider<InternetTile> internetTileProvider,
Provider<BluetoothTile> bluetoothTileProvider,
Provider<CellularTile> cellularTileProvider,
Provider<DndTile> dndTileProvider,
@@ -113,6 +116,7 @@ public class QSFactoryImpl implements QSFactory {
mCustomTileBuilderProvider = customTileBuilderProvider;
mWifiTileProvider = wifiTileProvider;
+ mInternetTileProvider = internetTileProvider;
mBluetoothTileProvider = bluetoothTileProvider;
mCellularTileProvider = cellularTileProvider;
mDndTileProvider = dndTileProvider;
@@ -148,6 +152,8 @@ public class QSFactoryImpl implements QSFactory {
switch (tileSpec) {
case "wifi":
return mWifiTileProvider.get();
+ case "internet":
+ return mInternetTileProvider.get();
case "bt":
return mBluetoothTileProvider.get();
case "cell":
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
new file mode 100644
index 000000000000..86524f5408c0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.quicksettings.Tile;
+import android.text.Html;
+import android.text.TextUtils;
+import android.util.Log;
+import android.widget.Switch;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settingslib.graph.SignalDrawable;
+import com.android.settingslib.net.DataUsageController;
+import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.qs.QSIconView;
+import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.plugins.qs.QSTile.Icon;
+import com.android.systemui.plugins.qs.QSTile.SignalState;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.qs.AlphaControlledSignalTileView;
+import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
+import com.android.systemui.statusbar.policy.WifiIcons;
+
+import javax.inject.Inject;
+
+/** Quick settings tile: Internet **/
+public class InternetTile extends QSTileImpl<SignalState> {
+ private static final Intent WIFI_SETTINGS = new Intent(Settings.ACTION_WIFI_SETTINGS);
+
+ protected final NetworkController mController;
+ private final DataUsageController mDataController;
+ private final QSTile.SignalState mStateBeforeClick = newTileState();
+ // The last updated tile state, 0: mobile, 1: wifi
+ private int mLastTileState = -1;
+
+ protected final InternetSignalCallback mSignalCallback = new InternetSignalCallback();
+
+ @Inject
+ public InternetTile(
+ QSHost host,
+ @Background Looper backgroundLooper,
+ @Main Handler mainHandler,
+ MetricsLogger metricsLogger,
+ StatusBarStateController statusBarStateController,
+ ActivityStarter activityStarter,
+ QSLogger qsLogger,
+ NetworkController networkController
+ ) {
+ super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController,
+ activityStarter, qsLogger);
+ mController = networkController;
+ mDataController = mController.getMobileDataController();
+ mController.observe(getLifecycle(), mSignalCallback);
+ }
+
+ @Override
+ public SignalState newTileState() {
+ return new SignalState();
+ }
+
+ @Override
+ public QSIconView createTileView(Context context) {
+ return new AlphaControlledSignalTileView(context);
+ }
+
+ @Override
+ public Intent getLongClickIntent() {
+ return WIFI_SETTINGS;
+ }
+
+ @Override
+ protected void handleClick() {
+ mActivityStarter.postStartActivityDismissingKeyguard(WIFI_SETTINGS, 0);
+ }
+
+ @Override
+ public CharSequence getTileLabel() {
+ return mContext.getString(R.string.quick_settings_internet_label);
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return MetricsEvent.QS_WIFI;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)
+ || (mController.hasMobileDataFeature()
+ && mHost.getUserContext().getUserId() == UserHandle.USER_SYSTEM);
+ }
+
+ private CharSequence getSecondaryLabel(boolean isTransient, String statusLabel) {
+ return isTransient
+ ? mContext.getString(R.string.quick_settings_wifi_secondary_label_transient)
+ : statusLabel;
+ }
+
+ private static String removeDoubleQuotes(String string) {
+ if (string == null) return null;
+ final int length = string.length();
+ if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
+ return string.substring(1, length - 1);
+ }
+ return string;
+ }
+
+ private static final class WifiCallbackInfo {
+ boolean mEnabled;
+ boolean mConnected;
+ int mWifiSignalIconId;
+ String mSsid;
+ boolean mActivityIn;
+ boolean mActivityOut;
+ String mWifiSignalContentDescription;
+ boolean mIsTransient;
+ public String mStatusLabel;
+
+ @Override
+ public String toString() {
+ return new StringBuilder("WifiCallbackInfo[")
+ .append("mEnabled=").append(mEnabled)
+ .append(",mConnected=").append(mConnected)
+ .append(",mWifiSignalIconId=").append(mWifiSignalIconId)
+ .append(",mSsid=").append(mSsid)
+ .append(",mActivityIn=").append(mActivityIn)
+ .append(",mActivityOut=").append(mActivityOut)
+ .append(",mWifiSignalContentDescription=").append(mWifiSignalContentDescription)
+ .append(",mIsTransient=").append(mIsTransient)
+ .append(']').toString();
+ }
+ }
+
+ private static final class CellularCallbackInfo {
+ boolean mAirplaneModeEnabled;
+ CharSequence mDataSubscriptionName;
+ CharSequence mDataContentDescription;
+ int mMobileSignalIconId;
+ boolean mActivityIn;
+ boolean mActivityOut;
+ boolean mNoSim;
+ boolean mRoaming;
+ boolean mMultipleSubs;
+
+ @Override
+ public String toString() {
+ return new StringBuilder("CellularCallbackInfo[")
+ .append("mAirplaneModeEnabled=").append(mAirplaneModeEnabled)
+ .append(",mDataSubscriptionName=").append(mDataSubscriptionName)
+ .append(",mDataContentDescription=").append(mDataContentDescription)
+ .append(",mMobileSignalIconId=").append(mMobileSignalIconId)
+ .append(",mActivityIn=").append(mActivityIn)
+ .append(",mActivityOut=").append(mActivityOut)
+ .append(",mNoSim=").append(mNoSim)
+ .append(",mRoaming=").append(mRoaming)
+ .append(",mMultipleSubs=").append(mMultipleSubs)
+ .append(']').toString();
+ }
+ }
+
+ protected final class InternetSignalCallback implements SignalCallback {
+ final WifiCallbackInfo mWifiInfo = new WifiCallbackInfo();
+ final CellularCallbackInfo mCellularInfo = new CellularCallbackInfo();
+
+ @Override
+ public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
+ boolean activityIn, boolean activityOut, String description, boolean isTransient,
+ String statusLabel) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "setWifiIndicators: "
+ + "enabled = " + enabled + ","
+ + "statusIcon = " + (statusIcon == null ? "" : statusIcon.toString()) + ","
+ + "qsIcon = " + (qsIcon == null ? "" : qsIcon.toString()) + ","
+ + "activityIn = " + activityIn + ","
+ + "activityOut = " + activityOut + ","
+ + "description = " + description + ","
+ + "isTransient = " + isTransient + ","
+ + "statusLabel = " + statusLabel);
+ }
+ mWifiInfo.mEnabled = enabled;
+ mWifiInfo.mConnected = qsIcon.visible;
+ mWifiInfo.mWifiSignalIconId = qsIcon.icon;
+ mWifiInfo.mSsid = description;
+ mWifiInfo.mActivityIn = activityIn;
+ mWifiInfo.mActivityOut = activityOut;
+ mWifiInfo.mWifiSignalContentDescription = qsIcon.contentDescription;
+ mWifiInfo.mIsTransient = isTransient;
+ mWifiInfo.mStatusLabel = statusLabel;
+ refreshState(mWifiInfo);
+ }
+
+ @Override
+ public void setMobileDataIndicators(IconState statusIcon, IconState qsIcon, int statusType,
+ int qsType, boolean activityIn, boolean activityOut,
+ CharSequence typeContentDescription,
+ CharSequence typeContentDescriptionHtml, CharSequence description,
+ boolean isWide, int subId, boolean roaming) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "setMobileDataIndicators: "
+ + "statusIcon = " + (statusIcon == null ? "" : statusIcon.toString()) + ","
+ + "qsIcon = " + (qsIcon == null ? "" : qsIcon.toString()) + ","
+ + "statusType = " + statusType + ","
+ + "qsType = " + qsType + ","
+ + "activityIn = " + activityIn + ","
+ + "activityOut = " + activityOut + ","
+ + "typeContentDescription = " + typeContentDescription + ","
+ + "typeContentDescriptionHtml = " + typeContentDescriptionHtml + ","
+ + "description = " + description + ","
+ + "isWide = " + isWide + ","
+ + "subId = " + subId + ","
+ + "roaming = " + roaming);
+ }
+ if (qsIcon == null) {
+ // Not data sim, don't display.
+ return;
+ }
+ mCellularInfo.mDataSubscriptionName = mController.getMobileDataNetworkName();
+ mCellularInfo.mDataContentDescription =
+ (description != null) ? typeContentDescriptionHtml : null;
+ mCellularInfo.mMobileSignalIconId = qsIcon.icon;
+ mCellularInfo.mActivityIn = activityIn;
+ mCellularInfo.mActivityOut = activityOut;
+ mCellularInfo.mRoaming = roaming;
+ mCellularInfo.mMultipleSubs = mController.getNumberSubscriptions() > 1;
+ refreshState(mCellularInfo);
+ }
+
+ @Override
+ public void setNoSims(boolean show, boolean simDetected) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "setNoSims: "
+ + "show = " + show + ","
+ + "simDetected = " + simDetected);
+ }
+ mCellularInfo.mNoSim = show;
+ if (mCellularInfo.mNoSim) {
+ // Make sure signal gets cleared out when no sims.
+ mCellularInfo.mMobileSignalIconId = 0;
+ }
+ refreshState(mCellularInfo);
+ }
+
+ @Override
+ public void setIsAirplaneMode(IconState icon) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "InternetTile-setIsAirplaneMode: "
+ + "icon = " + (icon == null ? "" : icon.toString()));
+ }
+ mCellularInfo.mAirplaneModeEnabled = icon.visible;
+ refreshState(mCellularInfo);
+ }
+ }
+
+ @Override
+ protected void handleUpdateState(SignalState state, Object arg) {
+ Log.d(TAG, "handleUpdateState: " + "arg = " + arg);
+ if (arg instanceof CellularCallbackInfo) {
+ mLastTileState = 0;
+ handleUpdateCellularState(state, arg);
+ } else if (arg instanceof WifiCallbackInfo) {
+ mLastTileState = 1;
+ handleUpdateWifiState(state, arg);
+ } else {
+ // handleUpdateState will be triggered when user expands the QuickSetting panel with
+ // arg = null, in this case the last updated CellularCallbackInfo or WifiCallbackInfo
+ // should be used to refresh the tile.
+ if (mLastTileState == 0) {
+ handleUpdateCellularState(state, mSignalCallback.mCellularInfo);
+ } else if (mLastTileState == 1) {
+ handleUpdateWifiState(state, mSignalCallback.mWifiInfo);
+ }
+ }
+ }
+
+ private void handleUpdateWifiState(SignalState state, Object arg) {
+ WifiCallbackInfo cb = (WifiCallbackInfo) arg;
+ boolean wifiConnected = cb.mEnabled && (cb.mWifiSignalIconId > 0) && (cb.mSsid != null);
+ boolean wifiNotConnected = (cb.mWifiSignalIconId > 0) && (cb.mSsid == null);
+ boolean enabledChanging = state.value != cb.mEnabled;
+ if (enabledChanging) {
+ fireToggleStateChanged(cb.mEnabled);
+ }
+ if (state.slash == null) {
+ state.slash = new SlashState();
+ state.slash.rotation = 6;
+ }
+ state.slash.isSlashed = false;
+ state.secondaryLabel = getSecondaryLabel(cb.mIsTransient, removeDoubleQuotes(cb.mSsid));
+ state.state = Tile.STATE_ACTIVE;
+ state.dualTarget = true;
+ state.value = cb.mEnabled;
+ state.activityIn = cb.mEnabled && cb.mActivityIn;
+ state.activityOut = cb.mEnabled && cb.mActivityOut;
+ final StringBuffer minimalContentDescription = new StringBuffer();
+ final StringBuffer minimalStateDescription = new StringBuffer();
+ final Resources r = mContext.getResources();
+ // TODO(b/174753536): Use the new "Internet" string as state.label once available.
+ if (cb.mIsTransient) {
+ state.icon = ResourceIcon.get(
+ com.android.internal.R.drawable.ic_signal_wifi_transient_animation);
+ state.label = r.getString(R.string.quick_settings_internet_label);
+ } else if (!state.value) {
+ state.slash.isSlashed = true;
+ state.state = Tile.STATE_INACTIVE;
+ state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_DISABLED);
+ state.label = r.getString(R.string.quick_settings_internet_label);
+ } else if (wifiConnected) {
+ state.icon = ResourceIcon.get(cb.mWifiSignalIconId);
+ state.label = r.getString(R.string.quick_settings_internet_label);
+ } else if (wifiNotConnected) {
+ state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK);
+ state.label = r.getString(R.string.quick_settings_internet_label);
+ } else {
+ state.icon = ResourceIcon.get(WifiIcons.QS_WIFI_NO_NETWORK);
+ state.label = r.getString(R.string.quick_settings_internet_label);
+ }
+ minimalContentDescription.append(
+ mContext.getString(R.string.quick_settings_internet_label)).append(",");
+ if (state.value) {
+ if (wifiConnected) {
+ minimalStateDescription.append(cb.mWifiSignalContentDescription);
+ minimalContentDescription.append(removeDoubleQuotes(cb.mSsid));
+ if (!TextUtils.isEmpty(state.secondaryLabel)) {
+ minimalContentDescription.append(",").append(state.secondaryLabel);
+ }
+ }
+ }
+ state.stateDescription = minimalStateDescription.toString();
+ state.contentDescription = minimalContentDescription.toString();
+ state.dualLabelContentDescription = r.getString(
+ R.string.accessibility_quick_settings_open_settings, getTileLabel());
+ state.expandedAccessibilityClassName = Switch.class.getName();
+ }
+
+ private void handleUpdateCellularState(SignalState state, Object arg) {
+ CellularCallbackInfo cb = (CellularCallbackInfo) arg;
+ final Resources r = mContext.getResources();
+ // TODO(b/174753536): Use the new "Internet" string as state.label once available.
+ state.label = r.getString(R.string.quick_settings_internet_label);
+ boolean mobileDataEnabled = mDataController.isMobileDataSupported()
+ && mDataController.isMobileDataEnabled();
+ state.value = mobileDataEnabled;
+ state.activityIn = mobileDataEnabled && cb.mActivityIn;
+ state.activityOut = mobileDataEnabled && cb.mActivityOut;
+ state.expandedAccessibilityClassName = Switch.class.getName();
+ if (cb.mNoSim) {
+ state.icon = ResourceIcon.get(R.drawable.ic_qs_no_sim);
+ } else {
+ state.icon = new SignalIcon(cb.mMobileSignalIconId);
+ }
+
+ if (cb.mNoSim) {
+ state.state = Tile.STATE_UNAVAILABLE;
+ state.secondaryLabel = r.getString(R.string.keyguard_missing_sim_message_short);
+ } else if (cb.mAirplaneModeEnabled) {
+ state.state = Tile.STATE_UNAVAILABLE;
+ state.secondaryLabel = r.getString(R.string.status_bar_airplane);
+ } else if (mobileDataEnabled) {
+ state.state = Tile.STATE_ACTIVE;
+ state.secondaryLabel = appendMobileDataType(cb.mDataSubscriptionName,
+ getMobileDataContentName(cb));
+ } else {
+ state.state = Tile.STATE_INACTIVE;
+ state.secondaryLabel = r.getString(R.string.cell_data_off);
+ }
+
+ state.contentDescription = state.label;
+ if (state.state == Tile.STATE_INACTIVE) {
+ // This information is appended later by converting the Tile.STATE_INACTIVE state.
+ state.stateDescription = "";
+ } else {
+ state.stateDescription = state.secondaryLabel;
+ }
+ }
+
+ private CharSequence appendMobileDataType(CharSequence current, CharSequence dataType) {
+ if (TextUtils.isEmpty(dataType)) {
+ return Html.fromHtml((current == null ? "" : current.toString()), 0);
+ }
+ if (TextUtils.isEmpty(current)) {
+ return Html.fromHtml((dataType == null ? "" : dataType.toString()), 0);
+ }
+ String concat = mContext.getString(R.string.mobile_carrier_text_format, current, dataType);
+ return Html.fromHtml(concat, 0);
+ }
+
+ private CharSequence getMobileDataContentName(CellularCallbackInfo cb) {
+ if (cb.mRoaming && !TextUtils.isEmpty(cb.mDataContentDescription)) {
+ String roaming = mContext.getString(R.string.data_connection_roaming);
+ String dataDescription =
+ cb.mDataContentDescription == null ? ""
+ : cb.mDataContentDescription.toString();
+ return mContext.getString(R.string.mobile_data_text_format, roaming, dataDescription);
+ }
+ if (cb.mRoaming) {
+ return mContext.getString(R.string.data_connection_roaming);
+ }
+ return cb.mDataContentDescription;
+ }
+
+ private static class SignalIcon extends Icon {
+ private final int mState;
+ SignalIcon(int state) {
+ mState = state;
+ }
+ public int getState() {
+ return mState;
+ }
+
+ @Override
+ public Drawable getDrawable(Context context) {
+ SignalDrawable d = new SignalDrawable(context);
+ d.setLevel(getState());
+ return d;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
index 8722fecdad96..f92860b70116 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
@@ -104,6 +104,15 @@ public interface NetworkController extends CallbackController<SignalCallback>, D
Context context) {
this(visible, icon, context.getString(contentDescription));
}
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ return builder.append("[visible=").append(visible).append(',')
+ .append("icon=").append(icon).append(',')
+ .append("contentDescription=").append(contentDescription).append(']')
+ .toString();
+ }
}
/**
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 13787768dc93..04032471ff87 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -95,7 +95,6 @@ import android.net.INetworkManagementEventObserver;
import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
import android.net.INetworkPolicyListener;
-import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
import android.net.ISocketKeepaliveCallback;
import android.net.InetAddresses;
@@ -337,7 +336,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
@VisibleForTesting
protected INetd mNetd;
private INetworkStatsService mStatsService;
- private INetworkPolicyManager mPolicyManager;
+ private NetworkPolicyManager mPolicyManager;
private NetworkPolicyManagerInternal mPolicyManagerInternal;
/**
@@ -946,15 +945,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
public ConnectivityService(Context context, INetworkManagementService netManager,
- INetworkStatsService statsService, INetworkPolicyManager policyManager) {
- this(context, netManager, statsService, policyManager, getDnsResolver(context),
- new IpConnectivityLog(), NetdService.getInstance(), new Dependencies());
+ INetworkStatsService statsService) {
+ this(context, netManager, statsService, getDnsResolver(context), new IpConnectivityLog(),
+ NetdService.getInstance(), new Dependencies());
}
@VisibleForTesting
protected ConnectivityService(Context context, INetworkManagementService netManager,
- INetworkStatsService statsService, INetworkPolicyManager policyManager,
- IDnsResolver dnsresolver, IpConnectivityLog logger, INetd netd, Dependencies deps) {
+ INetworkStatsService statsService, IDnsResolver dnsresolver, IpConnectivityLog logger,
+ INetd netd, Dependencies deps) {
if (DBG) log("ConnectivityService starting up");
mDeps = Objects.requireNonNull(deps, "missing Dependencies");
@@ -992,7 +991,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService");
mStatsService = Objects.requireNonNull(statsService, "missing INetworkStatsService");
- mPolicyManager = Objects.requireNonNull(policyManager, "missing INetworkPolicyManager");
+ mPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
mPolicyManagerInternal = Objects.requireNonNull(
LocalServices.getService(NetworkPolicyManagerInternal.class),
"missing NetworkPolicyManagerInternal");
@@ -1008,12 +1007,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// To ensure uid rules are synchronized with Network Policy, register for
// NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService
// reading existing policy from disk.
- try {
- mPolicyManager.registerListener(mPolicyListener);
- } catch (RemoteException e) {
- // ouch, no rules updates means some processes may never get network
- loge("unable to register INetworkPolicyListener" + e);
- }
+ mPolicyManager.registerListener(mPolicyListener);
final PowerManager powerManager = (PowerManager) context.getSystemService(
Context.POWER_SERVICE);
diff --git a/services/core/java/com/android/server/ConnectivityServiceInitializer.java b/services/core/java/com/android/server/ConnectivityServiceInitializer.java
index 2bc8925be019..f701688b2b7e 100644
--- a/services/core/java/com/android/server/ConnectivityServiceInitializer.java
+++ b/services/core/java/com/android/server/ConnectivityServiceInitializer.java
@@ -20,7 +20,6 @@ import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
import android.content.Context;
-import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
import android.os.INetworkManagementService;
import android.os.ServiceManager;
@@ -38,7 +37,7 @@ public final class ConnectivityServiceInitializer extends SystemService {
super(context);
// TODO: Define formal APIs to get the needed services.
mConnectivity = new ConnectivityService(context, getNetworkManagementService(),
- getNetworkStatsService(), getNetworkPolicyManager());
+ getNetworkStatsService());
}
@Override
@@ -57,10 +56,4 @@ public final class ConnectivityServiceInitializer extends SystemService {
return INetworkStatsService.Stub.asInterface(
ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
}
-
- private INetworkPolicyManager getNetworkPolicyManager() {
- return INetworkPolicyManager.Stub.asInterface(
- ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
- }
-
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 5fde046bda0a..6a52266dfe40 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1700,12 +1700,13 @@ public final class ActiveServices {
// TODO: remove as part of fixing b/173627642
@SuppressWarnings("AndroidFrameworkCompatChange")
private void postFgsNotificationLocked(ServiceRecord r) {
+ final boolean isLegacyApp = (r.appInfo.targetSdkVersion < Build.VERSION_CODES.S);
boolean showNow = !mAm.mConstants.mFlagFgsNotificationDeferralEnabled;
if (!showNow) {
// Legacy apps' FGS notifications are not deferred unless the relevant
// DeviceConfig element has been set
showNow = mAm.mConstants.mFlagFgsNotificationDeferralApiGated
- && r.appInfo.targetSdkVersion < Build.VERSION_CODES.S;
+ && isLegacyApp;
}
if (!showNow) {
// is the notification such that it should show right away?
@@ -1760,6 +1761,11 @@ public final class ActiveServices {
Slog.d(TAG_SERVICE, "FGS " + r
+ " notification in " + (when - now) + " ms");
}
+ if (isLegacyApp) {
+ Slog.i(TAG_SERVICE, "Deferring FGS notification in legacy app "
+ + r.appInfo.packageName + "/" + UserHandle.formatUid(r.appInfo.uid)
+ + " : " + r.foregroundNoti);
+ }
mAm.mHandler.postAtTime(mPostDeferredFGSNotifications, when);
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index b0f296f68a47..6892ef770901 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -370,9 +370,9 @@ final class ActivityManagerConstants extends ContentObserver {
volatile boolean mFlagFgsNotificationDeferralEnabled = true;
// Restrict FGS notification deferral policy to only those apps that target
- // API version S or higher. Enabled by default; set to "false" to defer FGS
- // notifications from legacy apps as well.
- volatile boolean mFlagFgsNotificationDeferralApiGated = true;
+ // API version S or higher. Disabled by default; set to "true" to force
+ // legacy app FGS notifications to display immediately in all cases.
+ volatile boolean mFlagFgsNotificationDeferralApiGated = false;
// Time in milliseconds to defer FGS notifications after their transition to
// the foreground state.
@@ -806,7 +806,7 @@ final class ActivityManagerConstants extends ContentObserver {
mFlagFgsNotificationDeferralApiGated = DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
KEY_DEFERRED_FGS_NOTIFICATIONS_API_GATED,
- /*default value*/ true);
+ /*default value*/ false);
}
private void updateFgsNotificationDeferralInterval() {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index cd5ea46afb8d..61da564ebab0 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -2664,14 +2664,18 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
+ ainfo.applicationInfo.uid + ", calling uid=" + callingUid);
}
- final Task stack = r.getRootTask();
- final Task task = stack.getDisplayArea().createRootTask(stack.getWindowingMode(),
- stack.getActivityType(), !ON_TOP, ainfo, intent,
- false /* createdByOrganizer */);
+ final Task rootTask = r.getRootTask();
+ final Task task = new Task.Builder(this)
+ .setWindowingMode(rootTask.getWindowingMode())
+ .setActivityType(rootTask.getActivityType())
+ .setActivityInfo(ainfo)
+ .setParent(rootTask.getDisplayArea())
+ .setIntent(intent)
+ .build();
if (!mRecentTasks.addToBottom(task)) {
// The app has too many tasks already and we can't add any more
- stack.removeChild(task, "addAppTask");
+ rootTask.removeChild(task, "addAppTask");
return INVALID_TASK_ID;
}
task.getTaskDescription().copyFrom(description);
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index 36a1ef9f49b4..0fc4cdb6a928 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -547,19 +547,16 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
return activityType == ACTIVITY_TYPE_STANDARD || activityType == ACTIVITY_TYPE_UNDEFINED;
}
- public boolean hasCompatibleActivityType(ConfigurationContainer other) {
- /*@WindowConfiguration.ActivityType*/ int thisType = getActivityType();
- /*@WindowConfiguration.ActivityType*/ int otherType = other.getActivityType();
-
- if (thisType == otherType) {
+ public static boolean isCompatibleActivityType(int currentType, int otherType) {
+ if (currentType == otherType) {
return true;
}
- if (thisType == ACTIVITY_TYPE_ASSISTANT) {
+ if (currentType == ACTIVITY_TYPE_ASSISTANT) {
// Assistant activities are only compatible with themselves...
return false;
}
// Otherwise we are compatible if us or other is not currently defined.
- return thisType == ACTIVITY_TYPE_UNDEFINED || otherType == ACTIVITY_TYPE_UNDEFINED;
+ return currentType == ACTIVITY_TYPE_UNDEFINED || otherType == ACTIVITY_TYPE_UNDEFINED;
}
/**
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 5195edfb7c86..54996a66ecd7 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -306,52 +306,54 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
static class FindTaskResult implements Function<Task, Boolean> {
- ActivityRecord mRecord;
- boolean mIdealMatch;
+ ActivityRecord mIdealRecord;
+ ActivityRecord mCandidateRecord;
- private ActivityRecord mTarget;
- private Intent intent;
- private ActivityInfo info;
+ private int mActivityType;
+ private String mTaskAffinity;
+ private Intent mIntent;
+ private ActivityInfo mInfo;
private ComponentName cls;
private int userId;
private boolean isDocument;
private Uri documentData;
+ void init(int activityType, String taskAffinity, Intent intent, ActivityInfo info) {
+ mActivityType = activityType;
+ mTaskAffinity = taskAffinity;
+ mIntent = intent;
+ mInfo = info;
+ mIdealRecord = null;
+ mCandidateRecord = null;
+ }
+
/**
* Returns the top activity in any existing task matching the given Intent in the input
* result. Returns null if no such task is found.
*/
- void process(ActivityRecord target, Task parent) {
- mTarget = target;
-
- intent = target.intent;
- info = target.info;
- cls = intent.getComponent();
- if (info.targetActivity != null) {
- cls = new ComponentName(info.packageName, info.targetActivity);
+ void process(WindowContainer parent) {
+ cls = mIntent.getComponent();
+ if (mInfo.targetActivity != null) {
+ cls = new ComponentName(mInfo.packageName, mInfo.targetActivity);
}
- userId = UserHandle.getUserId(info.applicationInfo.uid);
- isDocument = intent != null & intent.isDocument();
+ userId = UserHandle.getUserId(mInfo.applicationInfo.uid);
+ isDocument = mIntent != null & mIntent.isDocument();
// If documentData is non-null then it must match the existing task data.
- documentData = isDocument ? intent.getData() : null;
+ documentData = isDocument ? mIntent.getData() : null;
- ProtoLog.d(WM_DEBUG_TASKS, "Looking for task of %s in %s", target,
+ ProtoLog.d(WM_DEBUG_TASKS, "Looking for task of %s in %s", mInfo,
parent);
parent.forAllLeafTasks(this);
}
- void clear() {
- mRecord = null;
- mIdealMatch = false;
- }
-
- void setTo(FindTaskResult result) {
- mRecord = result.mRecord;
- mIdealMatch = result.mIdealMatch;
- }
-
@Override
public Boolean apply(Task task) {
+ if (!ConfigurationContainer.isCompatibleActivityType(mActivityType,
+ task.getActivityType())) {
+ ProtoLog.d(WM_DEBUG_TASKS, "Skipping task: (mismatch activity/task) %s", task);
+ return false;
+ }
+
if (task.voiceSession != null) {
// We never match voice sessions; those always run independently.
ProtoLog.d(WM_DEBUG_TASKS, "Skipping %s: voice session", task);
@@ -370,7 +372,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
ProtoLog.d(WM_DEBUG_TASKS, "Skipping %s: mismatch root %s", task, r);
return false;
}
- if (!r.hasCompatibleActivityType(mTarget)) {
+ if (!ConfigurationContainer.isCompatibleActivityType(r.getActivityType(),
+ mActivityType)) {
ProtoLog.d(WM_DEBUG_TASKS, "Skipping %s: mismatch activity type", task);
return false;
}
@@ -391,35 +394,33 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
ProtoLog.d(WM_DEBUG_TASKS, "Comparing existing cls=%s /aff=%s to new cls=%s /aff=%s",
- r.getTask().rootAffinity, intent.getComponent().flattenToShortString(),
- info.taskAffinity, (task.realActivity != null
+ r.getTask().rootAffinity, mIntent.getComponent().flattenToShortString(),
+ mInfo.taskAffinity, (task.realActivity != null
? task.realActivity.flattenToShortString() : ""));
// TODO Refactor to remove duplications. Check if logic can be simplified.
if (task.realActivity != null && task.realActivity.compareTo(cls) == 0
&& Objects.equals(documentData, taskDocumentData)) {
ProtoLog.d(WM_DEBUG_TASKS, "Found matching class!");
//dump();
- ProtoLog.d(WM_DEBUG_TASKS, "For Intent %s bringing to top: %s", intent, r.intent);
- mRecord = r;
- mIdealMatch = true;
+ ProtoLog.d(WM_DEBUG_TASKS, "For Intent %s bringing to top: %s", mIntent, r.intent);
+ mIdealRecord = r;
return true;
} else if (affinityIntent != null && affinityIntent.getComponent() != null
&& affinityIntent.getComponent().compareTo(cls) == 0 &&
Objects.equals(documentData, taskDocumentData)) {
ProtoLog.d(WM_DEBUG_TASKS, "Found matching class!");
- ProtoLog.d(WM_DEBUG_TASKS, "For Intent %s bringing to top: %s", intent, r.intent);
- mRecord = r;
- mIdealMatch = true;
+ ProtoLog.d(WM_DEBUG_TASKS, "For Intent %s bringing to top: %s", mIntent, r.intent);
+ mIdealRecord = r;
return true;
} else if (!isDocument && !taskIsDocument
- && mRecord == null && task.rootAffinity != null) {
- if (task.rootAffinity.equals(mTarget.taskAffinity)) {
+ && mIdealRecord == null && mCandidateRecord == null
+ && task.rootAffinity != null) {
+ if (task.rootAffinity.equals(mTaskAffinity)) {
ProtoLog.d(WM_DEBUG_TASKS, "Found matching affinity candidate!");
// It is possible for multiple tasks to have the same root affinity especially
// if they are in separate stacks. We save off this candidate, but keep looking
// to see if there is a better candidate.
- mRecord = r;
- mIdealMatch = false;
+ mCandidateRecord = r;
}
} else {
ProtoLog.d(WM_DEBUG_TASKS, "Not a match: %s", task);
@@ -2152,9 +2153,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
} else {
// In the case of multiple activities, we will create a new task for it and then
// move the PIP activity into the task.
- rootTask = taskDisplayArea.createRootTask(WINDOWING_MODE_UNDEFINED,
- r.getActivityType(), ON_TOP, r.info, r.intent,
- false /* createdByOrganizer */);
+ rootTask = new Task.Builder(mService)
+ .setActivityType(r.getActivityType())
+ .setOnTop(true)
+ .setActivityInfo(r.info)
+ .setParent(taskDisplayArea)
+ .setIntent(r.intent)
+ .build();
// It's possible the task entering PIP is in freeform, so save the last
// non-fullscreen bounds. Then when this new PIP task exits PIP, it can restore
// to its previous freeform bounds.
@@ -2234,38 +2239,48 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
@Nullable
ActivityRecord findTask(ActivityRecord r, TaskDisplayArea preferredTaskDisplayArea) {
- ProtoLog.d(WM_DEBUG_TASKS, "Looking for task of %s", r);
- mTmpFindTaskResult.clear();
+ return findTask(r.getActivityType(), r.taskAffinity, r.intent, r.info,
+ preferredTaskDisplayArea);
+ }
+
+ @Nullable
+ ActivityRecord findTask(int activityType, String taskAffinity, Intent intent, ActivityInfo info,
+ TaskDisplayArea preferredTaskDisplayArea) {
+ ProtoLog.d(WM_DEBUG_TASKS, "Looking for task of type=%s, taskAffinity=%s, intent=%s"
+ + ", info=%s, preferredTDA=%s", activityType, taskAffinity, intent, info,
+ preferredTaskDisplayArea);
+ mTmpFindTaskResult.init(activityType, taskAffinity, intent, info);
// Looking up task on preferred display area first
+ ActivityRecord candidateActivity = null;
if (preferredTaskDisplayArea != null) {
- preferredTaskDisplayArea.findTaskLocked(r, true /* isPreferredDisplay */,
- mTmpFindTaskResult);
- if (mTmpFindTaskResult.mIdealMatch) {
- return mTmpFindTaskResult.mRecord;
+ mTmpFindTaskResult.process(preferredTaskDisplayArea);
+ if (mTmpFindTaskResult.mIdealRecord != null) {
+ return mTmpFindTaskResult.mIdealRecord;
+ } else if (mTmpFindTaskResult.mCandidateRecord != null) {
+ candidateActivity = mTmpFindTaskResult.mCandidateRecord;
}
}
- final ActivityRecord task = getItemFromTaskDisplayAreas(taskDisplayArea -> {
+ final ActivityRecord idealMatchActivity = getItemFromTaskDisplayAreas(taskDisplayArea -> {
if (taskDisplayArea == preferredTaskDisplayArea) {
return null;
}
- taskDisplayArea.findTaskLocked(r, false /* isPreferredDisplay */,
- mTmpFindTaskResult);
- if (mTmpFindTaskResult.mIdealMatch) {
- return mTmpFindTaskResult.mRecord;
+ mTmpFindTaskResult.process(taskDisplayArea);
+ if (mTmpFindTaskResult.mIdealRecord != null) {
+ return mTmpFindTaskResult.mIdealRecord;
}
return null;
});
- if (task != null) {
- return task;
+ if (idealMatchActivity != null) {
+ return idealMatchActivity;
}
- if (WM_DEBUG_TASKS.isEnabled() && mTmpFindTaskResult.mRecord == null) {
+ if (WM_DEBUG_TASKS.isEnabled() && candidateActivity == null) {
ProtoLog.d(WM_DEBUG_TASKS, "No task found");
}
- return mTmpFindTaskResult.mRecord;
+ return candidateActivity;
}
/**
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 81cbd61d62d7..a0e6b423f299 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -807,55 +807,20 @@ class Task extends WindowContainer<WindowContainer> {
// Tracking cookie for the creation of this task.
IBinder mLaunchCookie;
- /**
- * Don't use constructor directly. Use {@link TaskDisplayArea#createStackUnchecked()} instead.
- */
- Task(ActivityTaskManagerService atmService, int id, int activityType, ActivityInfo info,
- Intent intent, boolean createdByOrganizer, boolean deferTaskAppear,
- IBinder launchCookie) {
- this(atmService, id, info, intent, null /*voiceSession*/, null /*voiceInteractor*/,
- null /*taskDescription*/, null /*stack*/);
- mCreatedByOrganizer = createdByOrganizer;
- mLaunchCookie = launchCookie;
- mDeferTaskAppear = deferTaskAppear;
- setActivityType(activityType);
- }
-
- /**
- * Don't use constructor directly. Use {@link Task#reuseOrCreateTask()} instead.
- */
- Task(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info, Intent _intent,
- IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
- TaskDescription _taskDescription, Task stack) {
- this(atmService, _taskId, _intent, null /*_affinityIntent*/, null /*_affinity*/,
- null /*_rootAffinity*/, null /*_realActivity*/, null /*_origActivity*/,
- false /*_rootWasReset*/, false /*_autoRemoveRecents*/, false /*_askedCompatMode*/,
- UserHandle.getUserId(info.applicationInfo.uid), 0 /*_effectiveUid*/,
- null /*_lastDescription*/, System.currentTimeMillis(),
- true /*neverRelinquishIdentity*/,
- _taskDescription != null ? _taskDescription : new TaskDescription(),
- _taskId, INVALID_TASK_ID, INVALID_TASK_ID,
- info.applicationInfo.uid, info.packageName, null /* default featureId */,
- info.resizeMode, info.supportsPictureInPicture(), false /*_realActivitySuspended*/,
- false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE, info,
- _voiceSession, _voiceInteractor, stack);
- }
-
- /** Don't use constructor directly. This is only used by XML parser. */
- Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent, Intent _affinityIntent,
- String _affinity, String _rootAffinity, ComponentName _realActivity,
- ComponentName _origActivity, boolean _rootWasReset, boolean _autoRemoveRecents,
- boolean _askedCompatMode, int _userId, int _effectiveUid, String _lastDescription,
- long lastTimeMoved, boolean neverRelinquishIdentity,
+ private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
+ Intent _affinityIntent, String _affinity, String _rootAffinity,
+ ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
+ boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId, int _effectiveUid,
+ String _lastDescription, long lastTimeMoved, boolean neverRelinquishIdentity,
TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId,
int nextTaskId, int callingUid, String callingPackage,
@Nullable String callingFeatureId, int resizeMode, boolean supportsPictureInPicture,
boolean _realActivitySuspended, boolean userSetupComplete, int minWidth, int minHeight,
ActivityInfo info, IVoiceInteractionSession _voiceSession,
- IVoiceInteractor _voiceInteractor, Task stack) {
+ IVoiceInteractor _voiceInteractor, boolean _createdByOrganizer,
+ IBinder _launchCookie, boolean _deferTaskAppear) {
super(atmService.mWindowManager);
- EventLogTags.writeWmTaskCreated(_taskId, stack != null ? getRootTaskId() : INVALID_TASK_ID);
mAtmService = atmService;
mTaskSupervisor = atmService.mTaskSupervisor;
mRootWindowContainer = mAtmService.mRootWindowContainer;
@@ -903,6 +868,11 @@ class Task extends WindowContainer<WindowContainer> {
mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
mHandler = new ActivityTaskHandler(mTaskSupervisor.mLooper);
mCurrentUser = mAtmService.mAmInternal.getCurrentUserId();
+
+ mCreatedByOrganizer = _createdByOrganizer;
+ mLaunchCookie = _launchCookie;
+ mDeferTaskAppear = _deferTaskAppear;
+ EventLogTags.writeWmTaskCreated(mTaskId, isRootTask() ? INVALID_TASK_ID : getRootTaskId());
}
Task reuseAsLeafTask(IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
@@ -4831,14 +4801,36 @@ class Task extends WindowContainer<WindowContainer> {
}
}
- final Task task = new Task(taskSupervisor.mService, taskId, intent,
- affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset,
- autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
- lastTimeOnTop, neverRelinquishIdentity, taskDescription, taskAffiliation,
- prevTaskId, nextTaskId, callingUid, callingPackage,
- callingFeatureId, resizeMode, supportsPictureInPicture, realActivitySuspended,
- userSetupComplete, minWidth, minHeight, null /*ActivityInfo*/,
- null /*_voiceSession*/, null /*_voiceInteractor*/, null /* stack */);
+ final Task task = new Task.Builder(taskSupervisor.mService)
+ .setTaskId(taskId)
+ .setIntent(intent)
+ .setAffinityIntent(affinityIntent)
+ .setAffinity(affinity)
+ .setRootAffinity(rootAffinity)
+ .setRealActivity(realActivity)
+ .setOrigActivity(origActivity)
+ .setRootWasReset(rootHasReset)
+ .setAutoRemoveRecents(autoRemoveRecents)
+ .setAskedCompatMode(askedCompatMode)
+ .setUserId(userId)
+ .setEffectiveUid(effectiveUid)
+ .setLastDescription(lastDescription)
+ .setLastTimeMoved(lastTimeOnTop)
+ .setNeverRelinquishIdentity(neverRelinquishIdentity)
+ .setLastTaskDescription(taskDescription)
+ .setTaskAffiliation(taskAffiliation)
+ .setPrevAffiliateTaskId(prevTaskId)
+ .setNextAffiliateTaskId(nextTaskId)
+ .setCallingUid(callingUid)
+ .setCallingPackage(callingPackage)
+ .setCallingFeatureId(callingFeatureId)
+ .setResizeMode(resizeMode)
+ .setSupportsPictureInPicture(supportsPictureInPicture)
+ .setRealActivitySuspended(realActivitySuspended)
+ .setUserSetupComplete(userSetupComplete)
+ .setMinWidth(minWidth)
+ .setMinHeight(minHeight)
+ .buildInner();
task.mLastNonFullscreenBounds = lastNonFullscreenBounds;
task.setBounds(lastNonFullscreenBounds);
task.mWindowLayoutAffinity = windowLayoutAffinity;
@@ -7313,11 +7305,15 @@ class Task extends WindowContainer<WindowContainer> {
final int taskId = activity != null
? mTaskSupervisor.getNextTaskIdForUser(activity.mUserId)
: mTaskSupervisor.getNextTaskIdForUser();
- task = new Task(mAtmService, taskId, info, intent, voiceSession,
- voiceInteractor, null /* taskDescription */, this);
-
- // add the task to stack first, mTaskPositioner might need the stack association
- addChild(task, toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
+ task = new Task.Builder(mAtmService)
+ .setTaskId(taskId)
+ .setActivityInfo(info)
+ .setIntent(intent)
+ .setVoiceSession(voiceSession)
+ .setVoiceInteractor(voiceInteractor)
+ .setOnTop(toTop)
+ .setParent(this)
+ .build();
}
int displayId = getDisplayId();
@@ -7718,4 +7714,368 @@ class Task extends WindowContainer<WindowContainer> {
proto.end(token);
}
+
+ static class Builder {
+ private final ActivityTaskManagerService mAtmService;
+ private WindowContainer mParent;
+ private int mTaskId;
+ private Intent mIntent;
+ private Intent mAffinityIntent;
+ private String mAffinity;
+ private String mRootAffinity;
+ private ComponentName mRealActivity;
+ private ComponentName mOrigActivity;
+ private boolean mRootWasReset;
+ private boolean mAutoRemoveRecents;
+ private boolean mAskedCompatMode;
+ private int mUserId;
+ private int mEffectiveUid;
+ private String mLastDescription;
+ private long mLastTimeMoved;
+ private boolean mNeverRelinquishIdentity;
+ private TaskDescription mLastTaskDescription;
+ private int mTaskAffiliation;
+ private int mPrevAffiliateTaskId = INVALID_TASK_ID;
+ private int mNextAffiliateTaskId = INVALID_TASK_ID;
+ private int mCallingUid;
+ private String mCallingPackage;
+ private String mCallingFeatureId;
+ private int mResizeMode;
+ private boolean mSupportsPictureInPicture;
+ private boolean mRealActivitySuspended;
+ private boolean mUserSetupComplete;
+ private int mMinWidth = INVALID_MIN_SIZE;
+ private int mMinHeight = INVALID_MIN_SIZE;
+ private ActivityInfo mActivityInfo;
+ private IVoiceInteractionSession mVoiceSession;
+ private IVoiceInteractor mVoiceInteractor;
+ private int mActivityType;
+ private int mWindowingMode = WINDOWING_MODE_UNDEFINED;
+ private boolean mCreatedByOrganizer;
+ private boolean mDeferTaskAppear;
+ private IBinder mLaunchCookie;
+ private boolean mOnTop;
+
+ Builder(ActivityTaskManagerService atm) {
+ mAtmService = atm;
+ }
+
+ Builder setParent(WindowContainer parent) {
+ mParent = parent;
+ return this;
+ }
+
+ Builder setTaskId(int taskId) {
+ mTaskId = taskId;
+ return this;
+ }
+
+ Builder setIntent(Intent intent) {
+ mIntent = intent;
+ return this;
+ }
+
+ Builder setRealActivity(ComponentName realActivity) {
+ mRealActivity = realActivity;
+ return this;
+ }
+
+ Builder setEffectiveUid(int effectiveUid) {
+ mEffectiveUid = effectiveUid;
+ return this;
+ }
+
+ Builder setMinWidth(int minWidth) {
+ mMinWidth = minWidth;
+ return this;
+ }
+
+ Builder setMinHeight(int minHeight) {
+ mMinHeight = minHeight;
+ return this;
+ }
+
+ Builder setActivityInfo(ActivityInfo info) {
+ mActivityInfo = info;
+ return this;
+ }
+
+ Builder setVoiceSession(IVoiceInteractionSession voiceSession) {
+ mVoiceSession = voiceSession;
+ return this;
+ }
+
+ Builder setActivityType(int activityType) {
+ mActivityType = activityType;
+ return this;
+ }
+
+ int getActivityType() {
+ return mActivityType;
+ }
+
+ Builder setWindowingMode(int windowingMode) {
+ mWindowingMode = windowingMode;
+ return this;
+ }
+
+ int getWindowingMode() {
+ return mWindowingMode;
+ }
+
+ Builder setCreatedByOrganizer(boolean createdByOrganizer) {
+ mCreatedByOrganizer = createdByOrganizer;
+ return this;
+ }
+
+ boolean getCreatedByOrganizer() {
+ return mCreatedByOrganizer;
+ }
+
+ Builder setDeferTaskAppear(boolean defer) {
+ mDeferTaskAppear = defer;
+ return this;
+ }
+
+ Builder setLaunchCookie(IBinder launchCookie) {
+ mLaunchCookie = launchCookie;
+ return this;
+ }
+
+ Builder setOnTop(boolean onTop) {
+ mOnTop = onTop;
+ return this;
+ }
+
+ private Builder setUserId(int userId) {
+ mUserId = userId;
+ return this;
+ }
+
+ private Builder setLastTimeMoved(long lastTimeMoved) {
+ mLastTimeMoved = lastTimeMoved;
+ return this;
+ }
+
+ private Builder setNeverRelinquishIdentity(boolean neverRelinquishIdentity) {
+ mNeverRelinquishIdentity = neverRelinquishIdentity;
+ return this;
+ }
+
+ private Builder setCallingUid(int callingUid) {
+ mCallingUid = callingUid;
+ return this;
+ }
+
+ private Builder setCallingPackage(String callingPackage) {
+ mCallingPackage = callingPackage;
+ return this;
+ }
+
+ private Builder setResizeMode(int resizeMode) {
+ mResizeMode = resizeMode;
+ return this;
+ }
+
+ private Builder setSupportsPictureInPicture(boolean supportsPictureInPicture) {
+ mSupportsPictureInPicture = supportsPictureInPicture;
+ return this;
+ }
+
+ private Builder setUserSetupComplete(boolean userSetupComplete) {
+ mUserSetupComplete = userSetupComplete;
+ return this;
+ }
+
+ private Builder setTaskAffiliation(int taskAffiliation) {
+ mTaskAffiliation = taskAffiliation;
+ return this;
+ }
+
+ private Builder setPrevAffiliateTaskId(int prevAffiliateTaskId) {
+ mPrevAffiliateTaskId = prevAffiliateTaskId;
+ return this;
+ }
+
+ private Builder setNextAffiliateTaskId(int nextAffiliateTaskId) {
+ mNextAffiliateTaskId = nextAffiliateTaskId;
+ return this;
+ }
+
+ private Builder setCallingFeatureId(String callingFeatureId) {
+ mCallingFeatureId = callingFeatureId;
+ return this;
+ }
+
+ private Builder setRealActivitySuspended(boolean realActivitySuspended) {
+ mRealActivitySuspended = realActivitySuspended;
+ return this;
+ }
+
+ private Builder setLastDescription(String lastDescription) {
+ mLastDescription = lastDescription;
+ return this;
+ }
+
+ private Builder setLastTaskDescription(TaskDescription lastTaskDescription) {
+ mLastTaskDescription = lastTaskDescription;
+ return this;
+ }
+
+ private Builder setOrigActivity(ComponentName origActivity) {
+ mOrigActivity = origActivity;
+ return this;
+ }
+
+ private Builder setRootWasReset(boolean rootWasReset) {
+ mRootWasReset = rootWasReset;
+ return this;
+ }
+
+ private Builder setAutoRemoveRecents(boolean autoRemoveRecents) {
+ mAutoRemoveRecents = autoRemoveRecents;
+ return this;
+ }
+
+ private Builder setAskedCompatMode(boolean askedCompatMode) {
+ mAskedCompatMode = askedCompatMode;
+ return this;
+ }
+
+ private Builder setAffinityIntent(Intent affinityIntent) {
+ mAffinityIntent = affinityIntent;
+ return this;
+ }
+
+ private Builder setAffinity(String affinity) {
+ mAffinity = affinity;
+ return this;
+ }
+
+ private Builder setRootAffinity(String rootAffinity) {
+ mRootAffinity = rootAffinity;
+ return this;
+ }
+
+ private Builder setVoiceInteractor(IVoiceInteractor voiceInteractor) {
+ mVoiceInteractor = voiceInteractor;
+ return this;
+ }
+
+ private void validateRootTask(TaskDisplayArea tda) {
+ if (mActivityType == ACTIVITY_TYPE_UNDEFINED && !mCreatedByOrganizer) {
+ // Can't have an undefined root task type yet...so re-map to standard. Anyone
+ // that wants anything else should be passing it in anyways...except for the task
+ // organizer.
+ mActivityType = ACTIVITY_TYPE_STANDARD;
+ }
+
+ if (mActivityType != ACTIVITY_TYPE_STANDARD
+ && mActivityType != ACTIVITY_TYPE_UNDEFINED) {
+ // For now there can be only one root task of a particular non-standard activity
+ // type on a display. So, get that ignoring whatever windowing mode it is
+ // currently in.
+ Task rootTask = tda.getRootTask(WINDOWING_MODE_UNDEFINED, mActivityType);
+ if (rootTask != null) {
+ throw new IllegalArgumentException("Root task=" + rootTask + " of activityType="
+ + mActivityType + " already on display=" + tda
+ + ". Can't have multiple.");
+ }
+ }
+
+ if (!TaskDisplayArea.isWindowingModeSupported(mWindowingMode,
+ mAtmService.mSupportsMultiWindow,
+ mAtmService.mSupportsSplitScreenMultiWindow,
+ mAtmService.mSupportsFreeformWindowManagement,
+ mAtmService.mSupportsPictureInPicture, mActivityType)) {
+ throw new IllegalArgumentException("Can't create root task for unsupported "
+ + "windowingMode=" + mWindowingMode);
+ }
+
+ if (mWindowingMode == WINDOWING_MODE_PINNED
+ && mActivityType != ACTIVITY_TYPE_STANDARD) {
+ throw new IllegalArgumentException(
+ "Root task with pinned windowing mode cannot with "
+ + "non-standard activity type.");
+ }
+
+ if (mWindowingMode == WINDOWING_MODE_PINNED && tda.getRootPinnedTask() != null) {
+ // Only 1 root task can be PINNED at a time, so dismiss the existing one
+ tda.getRootPinnedTask().dismissPip();
+ }
+
+ // Task created by organizer are added as root.
+ final Task launchRootTask = mCreatedByOrganizer
+ ? null : tda.updateLaunchRootTask(mWindowingMode);
+ if (launchRootTask != null) {
+ // Since this task will be put into a root task, its windowingMode will be
+ // inherited.
+ mWindowingMode = WINDOWING_MODE_UNDEFINED;
+ mParent = launchRootTask;
+ }
+
+ mTaskId = tda.getNextRootTaskId();
+ }
+
+ Task build() {
+ if (mParent != null && mParent instanceof TaskDisplayArea) {
+ validateRootTask((TaskDisplayArea) mParent);
+ }
+
+ if (mActivityInfo == null) {
+ mActivityInfo = new ActivityInfo();
+ mActivityInfo.applicationInfo = new ApplicationInfo();
+ }
+
+ mUserId = UserHandle.getUserId(mActivityInfo.applicationInfo.uid);
+ mTaskAffiliation = mTaskId;
+ mLastTimeMoved = System.currentTimeMillis();
+ mNeverRelinquishIdentity = true;
+ mCallingUid = mActivityInfo.applicationInfo.uid;
+ mCallingPackage = mActivityInfo.packageName;
+ mResizeMode = mActivityInfo.resizeMode;
+ mSupportsPictureInPicture = mActivityInfo.supportsPictureInPicture();
+ if (mLastTaskDescription == null) {
+ mLastTaskDescription = new TaskDescription();
+ }
+
+ final Task task = buildInner();
+
+ // Set activity type before adding the root task to TaskDisplayArea, so home task can
+ // be cached, see TaskDisplayArea#addRootTaskReferenceIfNeeded().
+ if (mActivityType != ACTIVITY_TYPE_UNDEFINED) {
+ task.setActivityType(mActivityType);
+ }
+
+ if (mParent != null) {
+ if (mParent instanceof Task) {
+ final Task parentTask = (Task) mParent;
+ parentTask.addChild(task, mOnTop ? POSITION_TOP : POSITION_BOTTOM,
+ (mActivityInfo.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
+ } else {
+ mParent.addChild(task, mOnTop ? POSITION_TOP : POSITION_BOTTOM);
+ }
+ }
+
+ // Set windowing mode after attached to display area or it abort silently.
+ if (mWindowingMode != WINDOWING_MODE_UNDEFINED) {
+ task.setWindowingMode(mWindowingMode, true /* creating */);
+ }
+ return task;
+ }
+
+ /** Don't use {@link Builder#buildInner()} directly. This is only used by XML parser. */
+ @VisibleForTesting
+ Task buildInner() {
+ return new Task(mAtmService, mTaskId, mIntent, mAffinityIntent, mAffinity,
+ mRootAffinity, mRealActivity, mOrigActivity, mRootWasReset, mAutoRemoveRecents,
+ mAskedCompatMode, mUserId, mEffectiveUid, mLastDescription, mLastTimeMoved,
+ mNeverRelinquishIdentity, mLastTaskDescription, mTaskAffiliation,
+ mPrevAffiliateTaskId, mNextAffiliateTaskId, mCallingUid, mCallingPackage,
+ mCallingFeatureId, mResizeMode, mSupportsPictureInPicture,
+ mRealActivitySuspended, mUserSetupComplete, mMinWidth, mMinHeight,
+ mActivityInfo, mVoiceSession, mVoiceInteractor, mCreatedByOrganizer,
+ mLaunchCookie, mDeferTaskAppear);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 97383e3d1386..3f4150b21178 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -35,7 +35,6 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
-import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_TASKS;
import static com.android.server.wm.ActivityTaskManagerService.TAG_ROOT_TASK;
import static com.android.server.wm.DisplayContent.alwaysCreateRootTask;
import static com.android.server.wm.Task.ActivityState.RESUMED;
@@ -47,9 +46,6 @@ import android.annotation.Nullable;
import android.app.ActivityOptions;
import android.app.WindowConfiguration;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.os.IBinder;
import android.os.UserHandle;
import android.util.IntArray;
import android.util.Slog;
@@ -131,9 +127,6 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
*/
Task mPreferredTopFocusableRootTask;
- private final RootWindowContainer.FindTaskResult
- mTmpFindTaskResult = new RootWindowContainer.FindTaskResult();
-
/**
* If this is the same as {@link #getFocusedRootTask} then the activity on the top of the
* focused root task has been resumed. If root tasks are changing position this will hold the
@@ -1045,8 +1038,13 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
}
return stack;
}
- return createRootTask(windowingMode, activityType, onTop, null /*info*/, intent,
- false /* createdByOrganizer */);
+ return new Task.Builder(mAtmService)
+ .setWindowingMode(windowingMode)
+ .setActivityType(activityType)
+ .setOnTop(onTop)
+ .setParent(this)
+ .setIntent(intent)
+ .build();
}
/**
@@ -1074,79 +1072,32 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
return mAtmService.mTaskSupervisor.getNextTaskIdForUser();
}
- Task createRootTask(int windowingMode, int activityType, boolean onTop) {
- return createRootTask(windowingMode, activityType, onTop, null /* info */,
- null /* intent */, false /* createdByOrganizer */);
- }
-
- Task createRootTask(int windowingMode, int activityType, boolean onTop, ActivityInfo info,
- Intent intent, boolean createdByOrganizer) {
- return createRootTask(windowingMode, activityType, onTop, null /* info */,
- null /* intent */, false /* createdByOrganizer */, false /* deferTaskAppear */,
- null /* launchCookie */);
- }
-
/**
- * Creates a stack matching the input windowing mode and activity type on this display.
+ * A convinenit method of creating a root task by providing windowing mode and activity type
+ * on this display.
*
- * @param windowingMode The windowing mode the stack should be created in. If
- * {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack
- * will
- * inherit its parent's windowing mode.
- * @param activityType The activityType the stack should be created in. If
- * {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack
- * will
- * be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
- * @param onTop If true the stack will be created at the top of the display, else
- * at the bottom.
- * @param info The started activity info.
- * @param intent The intent that started this task.
- * @param createdByOrganizer @{code true} if this is created by task organizer, @{code false}
- * otherwise.
- * @param deferTaskAppear @{code true} if the task appeared signal should be deferred.
- * @param launchCookie Launch cookie used for tracking/association of the task we are
- * creating.
- * @return The newly created stack.
+ * @param windowingMode The windowing mode the root task should be created in. If
+ * {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the
+ * root task will inherit its parent's windowing mode.
+ * @param activityType The activityType the root task should be created in. If
+ * {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the
+ * root task will be created in
+ * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
+ * @param onTop If true the root task will be created at the top of the display,
+ * else at the bottom.
+ * @return The newly created root task.
*/
- Task createRootTask(int windowingMode, int activityType, boolean onTop, ActivityInfo info,
- Intent intent, boolean createdByOrganizer, boolean deferTaskAppear,
- IBinder launchCookie) {
- if (activityType == ACTIVITY_TYPE_UNDEFINED && !createdByOrganizer) {
- // Can't have an undefined stack type yet...so re-map to standard. Anyone that wants
- // anything else should be passing it in anyways...except for the task organizer.
- activityType = ACTIVITY_TYPE_STANDARD;
- }
-
- if (activityType != ACTIVITY_TYPE_STANDARD && activityType != ACTIVITY_TYPE_UNDEFINED) {
- // For now there can be only one stack of a particular non-standard activity type on a
- // display. So, get that ignoring whatever windowing mode it is currently in.
- Task stack = getRootTask(WINDOWING_MODE_UNDEFINED, activityType);
- if (stack != null) {
- throw new IllegalArgumentException("Stack=" + stack + " of activityType="
- + activityType + " already on display=" + this + ". Can't have multiple.");
- }
- }
-
- if (!isWindowingModeSupported(windowingMode, mAtmService.mSupportsMultiWindow,
- mAtmService.mSupportsSplitScreenMultiWindow,
- mAtmService.mSupportsFreeformWindowManagement,
- mAtmService.mSupportsPictureInPicture, activityType)) {
- throw new IllegalArgumentException("Can't create stack for unsupported windowingMode="
- + windowingMode);
- }
-
- if (windowingMode == WINDOWING_MODE_PINNED && getRootPinnedTask() != null) {
- // Only 1 stack can be PINNED at a time, so dismiss the existing one
- getRootPinnedTask().dismissPip();
- }
-
- final int stackId = getNextRootTaskId();
- return createRootTaskUnchecked(windowingMode, activityType, stackId, onTop, info, intent,
- createdByOrganizer, deferTaskAppear, launchCookie);
+ Task createRootTask(int windowingMode, int activityType, boolean onTop) {
+ return new Task.Builder(mAtmService)
+ .setWindowingMode(windowingMode)
+ .setActivityType(activityType)
+ .setParent(this)
+ .setOnTop(onTop)
+ .build();
}
/** @return the root task to create the next task in. */
- private Task updateLaunchRootTask(int windowingMode) {
+ Task updateLaunchRootTask(int windowingMode) {
if (!isSplitScreenWindowingMode(windowingMode)) {
// Only split-screen windowing modes can do this currently...
return null;
@@ -1181,40 +1132,6 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
return mLaunchRootTask;
}
- @VisibleForTesting
- Task createRootTaskUnchecked(int windowingMode, int activityType, int stackId, boolean onTop,
- ActivityInfo info, Intent intent, boolean createdByOrganizer, boolean deferTaskAppear,
- IBinder launchCookie) {
- if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) {
- throw new IllegalArgumentException("Stack with windowing mode cannot with non standard "
- + "activity type.");
- }
- if (info == null) {
- info = new ActivityInfo();
- info.applicationInfo = new ApplicationInfo();
- }
-
- // Task created by organizer are added as root.
- Task launchRootTask = createdByOrganizer ? null : updateLaunchRootTask(windowingMode);
- if (launchRootTask != null) {
- // Since this stack will be put into a root task, its windowingMode will be inherited.
- windowingMode = WINDOWING_MODE_UNDEFINED;
- }
-
- final Task stack = new Task(mAtmService, stackId, activityType,
- info, intent, createdByOrganizer, deferTaskAppear, launchCookie);
- if (launchRootTask != null) {
- launchRootTask.addChild(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
- if (onTop) {
- positionChildAt(POSITION_TOP, launchRootTask, false /* includingParents */);
- }
- } else {
- addChild(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
- stack.setWindowingMode(windowingMode, true /* creating */);
- }
- return stack;
- }
-
/**
* Get the preferred focusable root task in priority. If the preferred root task does not exist,
* find a focusable and visible root task from the top of root tasks in this display.
@@ -1391,43 +1308,6 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
return someActivityPaused[0] > 0;
}
- /**
- * Find task for putting the Activity in.
- */
- void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplayArea,
- RootWindowContainer.FindTaskResult result) {
- mTmpFindTaskResult.clear();
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final Task rootTask = mChildren.get(i).asTask();
- if (rootTask == null) {
- continue;
- }
- if (!r.hasCompatibleActivityType(rootTask) && rootTask.isLeafTask()) {
- ProtoLog.d(WM_DEBUG_TASKS, "Skipping rootTask: (mismatch activity/rootTask) "
- + "%s", rootTask);
- continue;
- }
-
- mTmpFindTaskResult.process(r, rootTask);
- // It is possible to have tasks in multiple root tasks with the same root affinity, so
- // we should keep looking after finding an affinity match to see if there is a
- // better match in another root task. Also, task affinity isn't a good enough reason
- // to target a display which isn't the source of the intent, so skip any affinity
- // matches not on the specified display.
- if (mTmpFindTaskResult.mRecord != null) {
- if (mTmpFindTaskResult.mIdealMatch) {
- result.setTo(mTmpFindTaskResult);
- return;
- } else if (isPreferredDisplayArea) {
- // Note: since the traversing through the root tasks is top down, the floating
- // tasks should always have lower priority than any affinity-matching tasks
- // in the fullscreen root tasks
- result.setTo(mTmpFindTaskResult);
- }
- }
- }
- }
-
void onSplitScreenModeDismissed() {
// The focused task could be a non-resizeable fullscreen root task that is on top of the
// other split-screen tasks, therefore had to dismiss split-screen, make sure the current
@@ -1492,7 +1372,7 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
* @param activityType The activity type under consideration.
* @return true if the windowing mode is supported.
*/
- private boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
+ static boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip,
int activityType) {
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 929d7bf03a9e..089071f5de54 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -480,9 +479,14 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
// We want to defer the task appear signal until the task is fully created and attached to
// to the hierarchy so that the complete starting configuration is in the task info we send
// over to the organizer.
- final Task task = display.getDefaultTaskDisplayArea().createRootTask(windowingMode,
- ACTIVITY_TYPE_UNDEFINED, false /* onTop */, null /* info */, new Intent(),
- true /* createdByOrganizer */, true /* deferTaskAppear */, launchCookie);
+ final Task task = new Task.Builder(mService)
+ .setWindowingMode(windowingMode)
+ .setIntent(new Intent())
+ .setCreatedByOrganizer(true)
+ .setDeferTaskAppear(true)
+ .setLaunchCookie(launchCookie)
+ .setParent(display.getDefaultTaskDisplayArea())
+ .build();
task.setDeferTaskAppear(false /* deferTaskAppear */);
return task;
}
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 8b8617d8bf3a..21aa6bf8750a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -314,11 +314,12 @@ public class ActivityStackTests extends WindowTestsBase {
final RootWindowContainer.FindTaskResult result =
new RootWindowContainer.FindTaskResult();
- result.process(r, task);
+ result.init(r.getActivityType(), r.taskAffinity, r.intent, r.info);
+ result.process(task);
assertEquals(r, task.getTopNonFinishingActivity(false /* includeOverlays */));
assertEquals(taskOverlay, task.getTopNonFinishingActivity(true /* includeOverlays */));
- assertNotNull(result.mRecord);
+ assertNotNull(result.mIdealRecord);
}
@Test
@@ -340,15 +341,17 @@ public class ActivityStackTests extends WindowTestsBase {
final ActivityRecord r1 = new ActivityBuilder(mAtm).setComponent(
target).setTargetActivity(targetActivity).build();
RootWindowContainer.FindTaskResult result = new RootWindowContainer.FindTaskResult();
- result.process(r1, parentTask);
- assertThat(result.mRecord).isNotNull();
+ result.init(r1.getActivityType(), r1.taskAffinity, r1.intent, r1.info);
+ result.process(parentTask);
+ assertThat(result.mIdealRecord).isNotNull();
// Using alias activity to find task.
final ActivityRecord r2 = new ActivityBuilder(mAtm).setComponent(
alias).setTargetActivity(targetActivity).build();
result = new RootWindowContainer.FindTaskResult();
- result.process(r2, parentTask);
- assertThat(result.mRecord).isNotNull();
+ result.init(r2.getActivityType(), r2.taskAffinity, r2.intent, r2.info);
+ result.process(parentTask);
+ assertThat(result.mIdealRecord).isNotNull();
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 93ef126b895a..4b42d5603b55 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -324,7 +324,9 @@ public class RecentTasksTest extends WindowTestsBase {
.setActivityType(ACTIVITY_TYPE_UNDEFINED)
.setFlags(FLAG_ACTIVITY_NEW_TASK)
.build();
- assertThat(task1.getActivityType()).isEqualTo(ACTIVITY_TYPE_UNDEFINED);
+ // Set the activity type again or the activity type of a root task would be remapped
+ // to ACTIVITY_TYPE_STANDARD, {@link TaskDisplayArea#createRootTask()}
+ task1.getWindowConfiguration().setActivityType(ACTIVITY_TYPE_UNDEFINED);
mRecentTasks.add(task1);
mCallbacksRecorder.clear();
@@ -347,7 +349,9 @@ public class RecentTasksTest extends WindowTestsBase {
.setFlags(FLAG_ACTIVITY_NEW_TASK)
.setUserId(TEST_USER_0_ID)
.build();
- assertEquals(ACTIVITY_TYPE_UNDEFINED, task1.getActivityType());
+ // Set the activity type again or the activity type of a root task would be remapped
+ // to ACTIVITY_TYPE_STANDARD, {@link TaskDisplayArea#createRootTask()}
+ task1.getWindowConfiguration().setActivityType(ACTIVITY_TYPE_UNDEFINED);
mRecentTasks.add(task1);
mCallbacksRecorder.clear();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
index 1c93e0f7e185..10d2da00a852 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
@@ -43,8 +43,6 @@ 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 static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
@@ -175,15 +173,9 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
}
@Test
- public void testReuseTaskAsStack() {
+ public void testReuseTaskAsRootTask() {
final Task candidateTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, mDisplayContent);
- final Task newStack = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
- ACTIVITY_TYPE_STANDARD, mDisplayContent);
- final TaskDisplayArea taskDisplayArea = candidateTask.getDisplayArea();
- doReturn(newStack).when(taskDisplayArea).createRootTask(anyInt(), anyInt(), anyBoolean(),
- any(), any(), anyBoolean());
-
final int type = ACTIVITY_TYPE_STANDARD;
assertGetOrCreateRootTask(WINDOWING_MODE_FULLSCREEN, type, candidateTask,
true /* reuseCandidate */);
@@ -359,8 +351,8 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
private void assertGetOrCreateRootTask(int windowingMode, int activityType, Task candidateTask,
boolean reuseCandidate) {
final TaskDisplayArea taskDisplayArea = candidateTask.getDisplayArea();
- final Task stack = taskDisplayArea.getOrCreateRootTask(windowingMode, activityType,
+ final Task rootTask = taskDisplayArea.getOrCreateRootTask(windowingMode, activityType,
false /* onTop */, null /* intent */, candidateTask /* candidateTask */);
- assertEquals(reuseCandidate, stack == candidateTask);
+ assertEquals(reuseCandidate, rootTask == candidateTask);
}
}
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 184995d5b3b9..f20513dd369f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -571,9 +571,11 @@ public class TaskRecordTests extends WindowTestsBase {
info.packageName = DEFAULT_COMPONENT_PACKAGE_NAME;
info.targetActivity = targetClassName;
- final Task task = new Task(mAtm, 1 /* taskId */, info, intent,
- null /* voiceSession */, null /* voiceInteractor */, null /* taskDescriptor */,
- null /*stack*/);
+ final Task task = new Task.Builder(mAtm)
+ .setTaskId(1)
+ .setActivityInfo(info)
+ .setIntent(intent)
+ .build();
assertEquals("The alias activity component should be saved in task intent.", aliasClassName,
task.intent.getComponent().getClassName());
@@ -1122,10 +1124,11 @@ public class TaskRecordTests extends WindowTestsBase {
}
private Task createTask(int taskId) {
- return new Task(mAtm, taskId, new Intent(), null, null, null,
- ActivityBuilder.getDefaultComponent(), null, false, false, false, 0, 10050, null,
- 0, false, null, 0, 0, 0, 0, null, null, 0, false, false, false, 0,
- 0, null /*ActivityInfo*/, null /*_voiceSession*/, null /*_voiceInteractor*/,
- null /*stack*/);
+ return new Task.Builder(mAtm)
+ .setTaskId(taskId)
+ .setIntent(new Intent())
+ .setRealActivity(ActivityBuilder.getDefaultComponent())
+ .setEffectiveUid(10050)
+ .buildInner();
}
}
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 ba5ca2e250e8..31e2dce008de 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -1055,23 +1055,25 @@ class WindowTestsBase extends SystemServiceTestsBase {
mIntent.setFlags(mFlags);
}
- Task task;
- final int taskId = mTaskId >= 0 ? mTaskId : mTaskDisplayArea.getNextRootTaskId();
+ final Task.Builder builder = new Task.Builder(mSupervisor.mService)
+ .setTaskId(mTaskId >= 0 ? mTaskId : mTaskDisplayArea.getNextRootTaskId())
+ .setWindowingMode(mWindowingMode)
+ .setActivityInfo(mActivityInfo)
+ .setIntent(mIntent)
+ .setOnTop(mOnTop)
+ .setVoiceSession(mVoiceSession);
+ final Task task;
if (mParentTask == null) {
- task = mTaskDisplayArea.createRootTaskUnchecked(
- mWindowingMode, mActivityType, taskId, mOnTop, mActivityInfo, mIntent,
- false /* createdByOrganizer */, false /* deferTaskAppear */,
- null /* launchCookie */);
+ task = builder.setActivityType(mActivityType)
+ .setParent(mTaskDisplayArea)
+ .build();
} else {
- task = new Task(mSupervisor.mService, taskId, mActivityInfo,
- mIntent /*intent*/, mVoiceSession, null /*_voiceInteractor*/,
- null /*taskDescription*/, mParentTask);
+ task = builder.setParent(mParentTask).build();
mParentTask.moveToFront("build-task");
- mParentTask.addChild(task, true, true);
}
spyOn(task);
task.mUserId = mUserId;
- Task rootTask = task.getRootTask();
+ final Task rootTask = task.getRootTask();
if (task != rootTask && !Mockito.mockingDetails(rootTask).isSpy()) {
spyOn(rootTask);
}
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
index 70f6386aa891..8e1875168a84 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -25,7 +25,6 @@ import android.content.ServiceConnection
import android.net.ConnectivityManager
import android.net.IDnsResolver
import android.net.INetd
-import android.net.INetworkPolicyManager
import android.net.INetworkStatsService
import android.net.LinkProperties
import android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL
@@ -88,8 +87,6 @@ class ConnectivityServiceIntegrationTest {
@Mock
private lateinit var statsService: INetworkStatsService
@Mock
- private lateinit var policyManager: INetworkPolicyManager
- @Mock
private lateinit var log: IpConnectivityLog
@Mock
private lateinit var netd: INetd
@@ -171,7 +168,7 @@ class ConnectivityServiceIntegrationTest {
}
private inner class TestConnectivityService(deps: Dependencies) : ConnectivityService(
- context, netManager, statsService, policyManager, dnsResolver, log, netd, deps)
+ context, netManager, statsService, dnsResolver, log, netd, deps)
private fun makeDependencies(): ConnectivityService.Dependencies {
val deps = spy(ConnectivityService.Dependencies())
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 35eb6bafb740..0e8bfe707d7e 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -166,7 +166,6 @@ import android.net.INetd;
import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
import android.net.INetworkPolicyListener;
-import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
import android.net.InetAddresses;
import android.net.InterfaceConfigurationParcel;
@@ -183,6 +182,7 @@ import android.net.NetworkCapabilities;
import android.net.NetworkFactory;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkPolicyManager;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.net.NetworkStack;
@@ -365,7 +365,6 @@ public class ConnectivityServiceTest {
@Mock INetworkManagementService mNetworkManagementService;
@Mock INetworkStatsService mStatsService;
@Mock IBatteryStats mBatteryStatsService;
- @Mock INetworkPolicyManager mNpm;
@Mock IDnsResolver mMockDnsResolver;
@Mock INetd mMockNetd;
@Mock NetworkStackClient mNetworkStack;
@@ -380,6 +379,7 @@ public class ConnectivityServiceTest {
@Mock TelephonyManager mTelephonyManager;
@Mock MockableSystemProperties mSystemProperties;
@Mock EthernetManager mEthernetManager;
+ @Mock NetworkPolicyManager mNetworkPolicyManager;
private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -477,6 +477,7 @@ public class ConnectivityServiceTest {
if (Context.APP_OPS_SERVICE.equals(name)) return mAppOpsManager;
if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager;
if (Context.ETHERNET_SERVICE.equals(name)) return mEthernetManager;
+ if (Context.NETWORK_POLICY_SERVICE.equals(name)) return mNetworkPolicyManager;
return super.getSystemService(name);
}
@@ -1326,7 +1327,6 @@ public class ConnectivityServiceTest {
mService = new ConnectivityService(mServiceContext,
mNetworkManagementService,
mStatsService,
- mNpm,
mMockDnsResolver,
mock(IpConnectivityLog.class),
mMockNetd,
@@ -1336,7 +1336,7 @@ public class ConnectivityServiceTest {
final ArgumentCaptor<INetworkPolicyListener> policyListenerCaptor =
ArgumentCaptor.forClass(INetworkPolicyListener.class);
- verify(mNpm).registerListener(policyListenerCaptor.capture());
+ verify(mNetworkPolicyManager).registerListener(policyListenerCaptor.capture());
mPolicyListener = policyListenerCaptor.getValue();
// Create local CM before sending system ready so that we can answer