[Provider Model] Cherry-pick from master ag/15008434, ag/15023697 and ag/15023698

Add InternetAdapter for Wi-Fi network in internet dialog

    - Set each Wi-Fi entry into recycle view
    - Add InternetAdapterTest for unit test

Add InternetDialog for showing current networks

    - Set mobile data layout
    - Set connected Wi-Fi layout
    - Set recycle view and adapter for Wi-Fi entries
    - Add InternetDialogTest for unit test

Launch InternetDialog from tile and onReceive

    - Call from SystemUI: Inject
    - Call from outside: Receiver

Bug: 187779230
Test: build pass
Change-Id: Ib127ad43831ada06fa6a07802b3648b30faac5b0
Merged-In: Ib127ad43831ada06fa6a07802b3648b30faac5b0
This commit is contained in:
Zoey Chen
2021-08-13 12:46:35 +08:00
parent 7b5e298218
commit 5dbe2af746
29 changed files with 2174 additions and 4 deletions

View File

@@ -0,0 +1,26 @@
<!--
~ 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:autoMirrored="true"
android:tint="?android:attr/colorControlNormal">
<path
android:fillColor="@android:color/black"
android:pathData="M6.23,20.23l1.77,1.77l10,-10l-10,-10l-1.77,1.77l8.23,8.23z"/>
</vector>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2017 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?android:attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M18,8h-1V6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2H6c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V10C20,8.9 19.1,8 18,8zM9,6c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v2H9V6zM18,20H6V10h12V20zM12,17c1.1,0 2,-0.9 2,-2c0,-1.1 -0.9,-2 -2,-2c-1.1,0 -2,0.9 -2,2C10,16.1 10.9,17 12,17z"/>
</vector>

View File

@@ -0,0 +1,29 @@
<!--
Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?android:attr/colorControlNormal">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M13.85,22.25h-3.7c-0.74,0 -1.36,-0.54 -1.45,-1.27l-0.27,-1.89c-0.27,-0.14 -0.53,-0.29 -0.79,-0.46l-1.8,0.72c-0.7,0.26 -1.47,-0.03 -1.81,-0.65L2.2,15.53c-0.35,-0.66 -0.2,-1.44 0.36,-1.88l1.53,-1.19c-0.01,-0.15 -0.02,-0.3 -0.02,-0.46c0,-0.15 0.01,-0.31 0.02,-0.46l-1.52,-1.19C1.98,9.9 1.83,9.09 2.2,8.47l1.85,-3.19c0.34,-0.62 1.11,-0.9 1.79,-0.63l1.81,0.73c0.26,-0.17 0.52,-0.32 0.78,-0.46l0.27,-1.91c0.09,-0.7 0.71,-1.25 1.44,-1.25h3.7c0.74,0 1.36,0.54 1.45,1.27l0.27,1.89c0.27,0.14 0.53,0.29 0.79,0.46l1.8,-0.72c0.71,-0.26 1.48,0.03 1.82,0.65l1.84,3.18c0.36,0.66 0.2,1.44 -0.36,1.88l-1.52,1.19c0.01,0.15 0.02,0.3 0.02,0.46s-0.01,0.31 -0.02,0.46l1.52,1.19c0.56,0.45 0.72,1.23 0.37,1.86l-1.86,3.22c-0.34,0.62 -1.11,0.9 -1.8,0.63l-1.8,-0.72c-0.26,0.17 -0.52,0.32 -0.78,0.46l-0.27,1.91C15.21,21.71 14.59,22.25 13.85,22.25zM13.32,20.72c0,0.01 0,0.01 0,0.02L13.32,20.72zM10.68,20.7l0,0.02C10.69,20.72 10.69,20.71 10.68,20.7zM10.62,20.25h2.76l0.37,-2.55l0.53,-0.22c0.44,-0.18 0.88,-0.44 1.34,-0.78l0.45,-0.34l2.38,0.96l1.38,-2.4l-2.03,-1.58l0.07,-0.56c0.03,-0.26 0.06,-0.51 0.06,-0.78c0,-0.27 -0.03,-0.53 -0.06,-0.78l-0.07,-0.56l2.03,-1.58l-1.39,-2.4l-2.39,0.96l-0.45,-0.35c-0.42,-0.32 -0.87,-0.58 -1.33,-0.77L13.75,6.3l-0.37,-2.55h-2.76L10.25,6.3L9.72,6.51C9.28,6.7 8.84,6.95 8.38,7.3L7.93,7.63L5.55,6.68L4.16,9.07l2.03,1.58l-0.07,0.56C6.09,11.47 6.06,11.74 6.06,12c0,0.26 0.02,0.53 0.06,0.78l0.07,0.56l-2.03,1.58l1.38,2.4l2.39,-0.96l0.45,0.35c0.43,0.33 0.86,0.58 1.33,0.77l0.53,0.22L10.62,20.25zM18.22,17.72c0,0.01 -0.01,0.02 -0.01,0.03L18.22,17.72zM5.77,17.71l0.01,0.02C5.78,17.72 5.77,17.71 5.77,17.71zM3.93,9.47L3.93,9.47C3.93,9.47 3.93,9.47 3.93,9.47zM18.22,6.27c0,0.01 0.01,0.02 0.01,0.02L18.22,6.27zM5.79,6.25L5.78,6.27C5.78,6.27 5.79,6.26 5.79,6.25zM13.31,3.28c0,0.01 0,0.01 0,0.02L13.31,3.28zM10.69,3.26l0,0.02C10.69,3.27 10.69,3.27 10.69,3.26z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M12,12m-3.5,0a3.5,3.5 0,1 1,7 0a3.5,3.5 0,1 1,-7 0"/>
</vector>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android">
<shape android:shape="rectangle">
<corners android:radius="8dp" />
<solid android:color="?android:attr/colorBackground" />
</shape>
</inset>

View File

@@ -0,0 +1,30 @@
<?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
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
<stroke
android:color="?androidprv:attr/colorAccentPrimaryVariant"
android:width="1dp"/>
<corners android:radius="20dp"/>
<padding
android:left="8dp"
android:right="8dp"
android:top="4dp"
android:bottom="4dp" />
<solid android:color="@android:color/transparent" />
</shape>

View File

@@ -0,0 +1,22 @@
<?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.
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android">
<shape android:shape="rectangle">
<corners
android:topLeftRadius="@dimen/internet_dialog_corner_radius"
android:topRightRadius="@dimen/internet_dialog_corner_radius"
android:bottomLeftRadius="@dimen/internet_dialog_corner_radius"
android:bottomRightRadius="@dimen/internet_dialog_corner_radius"/>
<solid android:color="?android:attr/colorBackground" />
</shape>
</inset>

View File

@@ -0,0 +1,26 @@
<?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.
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/settingslib_state_off_color"/>
<corners android:radius="@dimen/settingslib_switch_bar_radius"/>
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,26 @@
<?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.
-->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/settingslib_state_on_color"/>
<corners android:radius="@dimen/settingslib_switch_bar_radius"/>
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,33 @@
<?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.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:top="@dimen/settingslib_switch_thumb_margin"
android:left="@dimen/settingslib_switch_thumb_margin"
android:right="@dimen/settingslib_switch_thumb_margin"
android:bottom="@dimen/settingslib_switch_thumb_margin">
<shape android:shape="oval">
<size
android:height="@dimen/settingslib_switch_thumb_size"
android:width="@dimen/settingslib_switch_thumb_size"/>
<solid
android:color="@color/settingslib_thumb_off_color"
android:alpha="?android:attr/disabledAlpha"/>
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:top="@dimen/settingslib_switch_thumb_margin"
android:left="@dimen/settingslib_switch_thumb_margin"
android:right="@dimen/settingslib_switch_thumb_margin"
android:bottom="@dimen/settingslib_switch_thumb_margin">
<shape android:shape="oval">
<size
android:height="@dimen/settingslib_switch_thumb_size"
android:width="@dimen/settingslib_switch_thumb_size"/>
<solid android:color="@color/settingslib_thumb_off_color"/>
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:top="@dimen/settingslib_switch_thumb_margin"
android:left="@dimen/settingslib_switch_thumb_margin"
android:right="@dimen/settingslib_switch_thumb_margin"
android:bottom="@dimen/settingslib_switch_thumb_margin">
<shape android:shape="oval">
<size
android:height="@dimen/settingslib_switch_thumb_size"
android:width="@dimen/settingslib_switch_thumb_size"/>
<solid android:color="@color/settingslib_state_on_color"/>
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/settingslib_thumb_on" android:state_checked="true"/>
<item android:drawable="@drawable/settingslib_thumb_off" android:state_checked="false"/>
<item android:drawable="@drawable/settingslib_thumb_disabled" android:state_enabled="false"/>
</selector>

View File

@@ -0,0 +1,26 @@
<?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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
android:width="@dimen/settingslib_switch_track_width"
android:height="@dimen/settingslib_switch_track_height">
<solid
android:color="@color/settingslib_track_off_color"
android:alpha="?android:attr/disabledAlpha"/>
<corners android:radius="@dimen/settingslib_switch_track_radius"/>
</shape>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
android:width="@dimen/settingslib_switch_track_width"
android:height="@dimen/settingslib_switch_track_height">
<solid android:color="@color/settingslib_track_off_color"/>
<corners android:radius="@dimen/settingslib_switch_track_radius"/>
</shape>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
android:width="@dimen/settingslib_switch_track_width"
android:height="@dimen/settingslib_switch_track_height">
<solid android:color="@color/settingslib_track_on_color"/>
<corners android:radius="@dimen/settingslib_switch_track_radius"/>
</shape>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/settingslib_track_on_background" android:state_checked="true"/>
<item android:drawable="@drawable/settingslib_track_off_background" android:state_checked="false"/>
<item android:drawable="@drawable/settingslib_track_disabled_background" android:state_enabled="false"/>
</selector>

View File

@@ -0,0 +1,351 @@
<?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:id="@+id/internet_connectivity_dialog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/internet_dialog_rounded_top_corner_background"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
style="@style/Widget.SliceView.Panel"
android:gravity="center_vertical|center_horizontal"
android:layout_marginTop="20dp"
android:layout_height="64dp"
android:orientation="vertical">
<TextView
android:id="@+id/internet_dialog_title"
android:gravity="center_vertical|center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?android:attr/textColorPrimary"
android:fontFamily="google-sans"
android:textSize="24sp"/>
<TextView
android:id="@+id/internet_dialog_subtitle"
android:gravity="center_vertical|center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:fontFamily="google-sans"
android:textSize="14sp"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?android:attr/listDivider"/>
<LinearLayout
android:id="@+id/internet_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/mobile_network_layout"
android:layout_width="match_parent"
android:layout_height="88dp"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical|center_horizontal"
android:orientation="horizontal"
android:layout_marginRight="@dimen/settingslib_switchbar_margin"
android:layout_marginLeft="@dimen/settingslib_switchbar_margin"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:paddingStart="@dimen/settingslib_switchbar_padding_left"
android:paddingEnd="@dimen/settingslib_switchbar_padding_right">
<FrameLayout
android:layout_width="36dp"
android:layout_height="36dp"
android:clickable="false"
android:layout_gravity="center_vertical|start">
<ImageView
android:id="@+id/signal_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
</FrameLayout>
<LinearLayout
android:layout_weight="1"
android:id="@+id/mobile_network_list"
android:orientation="vertical"
android:clickable="false"
android:layout_marginLeft="3dp"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="start|center_vertical">
<TextView
android:id="@+id/mobile_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp"
android:fontFamily="google-sans"/>
<TextView
android:id="@+id/mobile_summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:attr/textColorTertiary"
android:textSize="14sp"
android:fontFamily="google-sans"/>
</LinearLayout>
<FrameLayout
android:layout_width="48dp"
android:layout_height="48dp">
<Switch
android:id="@+id/mobile_toggle"
android:layout_gravity="center"
android:layout_width="48dp"
android:layout_height="wrap_content"
android:track="@drawable/settingslib_track_selector"
android:thumb="@drawable/settingslib_thumb_selector"
android:theme="@style/MainSwitch.Settingslib"/>
</FrameLayout>
</LinearLayout>
<ProgressBar
android:id="@+id/wifi_searching_progress"
android:indeterminate="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="1dp"
android:maxHeight="1dp"
style="@*android:style/Widget.Material.ProgressBar.Horizontal"/>
<LinearLayout
android:id="@+id/turn_on_wifi_layout"
android:layout_width="match_parent"
android:layout_height="48dp"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground"
android:gravity="center"
android:orientation="horizontal"
android:layout_marginTop="8dp"
android:layout_marginRight="@dimen/settingslib_switchbar_margin"
android:layout_marginLeft="@dimen/settingslib_switchbar_margin"
android:paddingStart="@dimen/settingslib_switchbar_padding_left"
android:paddingEnd="@dimen/settingslib_switchbar_padding_right">
<FrameLayout
android:layout_weight="1"
android:orientation="vertical"
android:clickable="false"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<TextView
android:text="@string/turn_on_wifi"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="start|center_vertical"
android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp"
android:fontFamily="google-sans"/>
</FrameLayout>
<FrameLayout
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp">
<Switch
android:id="@+id/wifi_toggle"
android:layout_gravity="center"
android:layout_width="48dp"
android:layout_height="wrap_content"
android:track="@drawable/settingslib_track_selector"
android:thumb="@drawable/settingslib_thumb_selector"
android:theme="@style/MainSwitch.Settingslib"/>
</FrameLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/wifi_connected_layout"
android:layout_width="match_parent"
android:layout_height="72dp"
android:layout_gravity="center_vertical|start"
android:clickable="true"
android:focusable="true"
android:visibility="gone"
android:background="?android:attr/selectableItemBackground"
android:orientation="horizontal"
android:layout_marginTop="8dp"
android:layout_marginRight="@dimen/settingslib_switchbar_margin"
android:layout_marginLeft="@dimen/settingslib_switchbar_margin"
android:paddingStart="@dimen/settingslib_switchbar_padding_left"
android:paddingEnd="@dimen/settingslib_switchbar_padding_right">
<FrameLayout
android:layout_width="24dp"
android:layout_height="24dp"
android:clickable="false"
android:layout_gravity="center_vertical|start">
<ImageView
android:id="@+id/wifi_connected_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
</FrameLayout>
<LinearLayout
android:layout_weight="3"
android:id="@+id/wifi_connected_list"
android:orientation="vertical"
android:clickable="false"
android:layout_width="wrap_content"
android:layout_height="72dp"
android:gravity="start|center_vertical">
<TextView
android:id="@+id/wifi_connected_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="16dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:attr/textColorPrimary"
android:textSize="14sp"
android:fontFamily="google-sans"/>
<TextView
android:id="@+id/wifi_connected_summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="16dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:attr/textColorTertiary"
android:textSize="14sp"
android:fontFamily="google-sans"/>
</LinearLayout>
<FrameLayout
android:layout_width="24dp"
android:layout_height="match_parent"
android:layout_marginRight="5dp"
android:clickable="false"
android:gravity="center">
<ImageView
android:id="@+id/wifi_settings_icon"
android:src="@drawable/ic_settings_24dp"
android:layout_width="24dp"
android:layout_gravity="center"
android:layout_height="wrap_content"/>
</FrameLayout>
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/wifi_list_layout"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never"
android:nestedScrollingEnabled="false"/>
</LinearLayout>
<LinearLayout
android:id="@+id/see_all_layout"
android:layout_width="match_parent"
android:layout_height="64dp"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical|center_horizontal"
android:orientation="horizontal"
android:paddingStart="@dimen/settingslib_switchbar_padding_left"
android:paddingEnd="@dimen/settingslib_switchbar_padding_right">
<FrameLayout
android:layout_width="24dp"
android:layout_height="24dp"
android:clickable="false"
android:layout_gravity="center_vertical|start"
android:layout_marginStart="16dp">
<ImageView
android:id="@+id/arrow_forward"
android:src="@drawable/ic_arrow_forward"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
</FrameLayout>
<FrameLayout
android:orientation="vertical"
android:clickable="false"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp">
<TextView
android:text="@string/see_all_networks"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="start|center_vertical"
android:textColor="?android:attr/textColorPrimary"
android:textSize="14sp"
android:fontFamily="google-sans"/>
</FrameLayout>
</LinearLayout>
<Space
android:id="@+id/space"
android:layout_width="match_parent"
android:layout_height="28dp"
android:visibility="gone"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginBottom="25dp"
android:gravity="end"
android:orientation="horizontal">
<Button
style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
android:id="@+id/done"
android:layout_width="60dp"
android:layout_height="30dp"
android:layout_marginRight="24dp"
android:layout_gravity="end"
android:background="@drawable/internet_dialog_footer_background"
android:textColor="?android:attr/textColorPrimary"
android:text="@string/inline_done_button"
android:textSize="14sp"
android:fontFamily="google-sans"/>
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,99 @@
<?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:id="@+id/internet_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/wifi_list"
android:layout_width="match_parent"
android:layout_height="72dp"
android:layout_gravity="center_vertical|start"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground"
android:orientation="horizontal"
android:paddingStart="@dimen/settingslib_switchbar_padding_left"
android:paddingEnd="@dimen/settingslib_switchbar_padding_right">
<FrameLayout
android:layout_width="24dp"
android:layout_height="24dp"
android:clickable="false"
android:layout_gravity="center_vertical|start"
android:layout_marginStart="16dp">
<ImageView
android:id="@+id/wifi_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
</FrameLayout>
<LinearLayout
android:layout_weight="3"
android:id="@+id/wifi_network_layout"
android:orientation="vertical"
android:clickable="false"
android:layout_width="wrap_content"
android:layout_height="72dp">
<TextView
android:id="@+id/wifi_title"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center_vertical"
android:gravity="start|center_vertical"
android:layout_marginLeft="16dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:attr/textColorPrimary"
android:textSize="14sp"
android:fontFamily="google-sans"/>
<TextView
android:id="@+id/wifi_summary"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_gravity="center_vertical"
android:gravity="start|center_vertical"
android:layout_marginLeft="16dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
android:fontFamily="google-sans"/>
</LinearLayout>
<FrameLayout
android:layout_width="24dp"
android:layout_height="match_parent"
android:layout_marginRight="@dimen/settingslib_switchbar_padding_right"
android:clickable="false"
android:gravity="center">
<ImageView
android:id="@+id/wifi_locked_icon"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:layout_height="wrap_content"/>
</FrameLayout>
</LinearLayout>
</LinearLayout>

View File

@@ -16,7 +16,7 @@
* limitations under the License.
*/
-->
<resources>
<resources xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
<drawable name="notification_number_text_color">#ffffffff</drawable>
<drawable name="ticker_background_color">#ff1d1d1d</drawable>
<drawable name="system_bar_background">@color/system_bar_background_opaque</drawable>
@@ -281,4 +281,16 @@
<color name="wallet_card_border">#33FFFFFF</color>
<color name="people_tile_background">@android:color/system_accent2_50</color>
<!-- Internet Dialog -->
<!-- Material next state on color-->
<color name="settingslib_state_on_color">?androidprv:attr/colorAccentPrimary</color>
<!-- Material next state off color-->
<color name="settingslib_state_off_color">?androidprv:attr/colorAccentSecondary</color>
<!-- Material next track on color-->
<color name="settingslib_track_on_color">?androidprv:attr/colorAccentPrimaryVariant</color>
<!-- Material next track off color-->
<color name="settingslib_track_off_color">?androidprv:attr/colorAccentSecondaryVariant</color>
<color name="connected_network_primary_color">#ff000000</color>
<color name="connected_network_tertiary_color">#808080</color>
</resources>

View File

@@ -1591,6 +1591,34 @@
<dimen name="ongoing_call_chip_icon_text_padding">4dp</dimen>
<dimen name="ongoing_call_chip_corner_radius">28dp</dimen>
<!-- Internet panel related dimensions -->
<dimen name="internet_dialog_list_margin">12dp</dimen>
<dimen name="internet_dialog_list_max_height">614dp</dimen>
<!-- Signal icon in internet dialog -->
<dimen name="signal_strength_icon_size">24dp</dimen>
<!-- Internet dialog related dimensions -->
<dimen name="internet_dialog_corner_radius">24dp</dimen>
<!-- Size of internet dialog -->
<dimen name="settingslib_switchbar_margin">16dp</dimen>
<!-- Minimum width of switch -->
<dimen name="settingslib_min_switch_width">48dp</dimen>
<!-- Size of layout margin left -->
<dimen name="settingslib_switchbar_padding_left">20dp</dimen>
<!-- Size of layout margin right -->
<dimen name="settingslib_switchbar_padding_right">20dp</dimen>
<!-- Radius of switch bar -->
<dimen name="settingslib_switch_bar_radius">24dp</dimen>
<!-- Margin of switch thumb -->
<dimen name="settingslib_switch_thumb_margin">4dp</dimen>
<!-- Size of switch thumb -->
<dimen name="settingslib_switch_thumb_size">16dp</dimen>
<!-- Width of switch track -->
<dimen name="settingslib_switch_track_width">48dp</dimen>
<!-- Height of switch track -->
<dimen name="settingslib_switch_track_height">24dp</dimen>
<!-- Radius of switch track -->
<dimen name="settingslib_switch_track_radius">31dp</dimen>
</resources>

View File

@@ -903,4 +903,43 @@
<!-- Setting a placeholder will avoid using the SystemUI icon on the splash screen. -->
<item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_blank</item>
</style>
<style name="Animation.InternetDialog" parent="@android:style/Animation.InputMethod">
</style>
<style name="Widget.SliceView.Panel">
<item name="titleSize">16sp</item>
<item name="rowStyle">@style/SliceRow</item>
<item name="android:background">?android:attr/colorBackgroundFloating</item>
</style>
<style name="SliceRow">
<!-- 2dp start padding for the start icon -->
<item name="titleItemStartPadding">2dp</item>
<item name="titleItemEndPadding">0dp</item>
<!-- Padding between content and the start icon is 14dp -->
<item name="contentStartPadding">14dp</item>
<!-- Padding between content and end items is 16dp -->
<item name="contentEndPadding">16dp</item>
<!-- Both side margins of end item are 16dp -->
<item name="endItemStartPadding">16dp</item>
<item name="endItemEndPadding">16dp</item>
<!-- Both side margins of bottom divider are 12dp -->
<item name="bottomDividerStartPadding">12dp</item>
<item name="bottomDividerEndPadding">12dp</item>
<item name="actionDividerHeight">32dp</item>
</style>
<style name="Theme.SystemUI.Dialog.Internet">
<item name="android:windowBackground">@drawable/internet_dialog_background</item>
</style>
<style name="MainSwitch.Settingslib" parent="@android:style/Theme.DeviceDefault">
<item name="android:switchMinWidth">@dimen/settingslib_min_switch_width</item>
</style>
</resources>

View File

@@ -65,6 +65,7 @@ import com.android.systemui.power.EnhancedEstimates;
import com.android.systemui.power.PowerUI;
import com.android.systemui.privacy.PrivacyItemController;
import com.android.systemui.qs.ReduceBrightColorsController;
import com.android.systemui.qs.tiles.dialog.InternetDialogFactory;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
import com.android.systemui.screenrecord.RecordingController;
@@ -364,6 +365,7 @@ public class Dependency {
@Inject Lazy<UiEventLogger> mUiEventLogger;
@Inject Lazy<FeatureFlags> mFeatureFlagsLazy;
@Inject Lazy<StatusBarContentInsetsProvider> mContentInsetsProviderLazy;
@Inject Lazy<InternetDialogFactory> mInternetDialogFactory;
@Inject
public Dependency() {
@@ -578,6 +580,7 @@ public class Dependency {
mProviders.put(PrivacyDotViewController.class, mPrivacyDotViewControllerLazy::get);
mProviders.put(EdgeBackGestureHandler.Factory.class,
mEdgeBackGestureHandlerFactoryLazy::get);
mProviders.put(InternetDialogFactory.class, mInternetDialogFactory::get);
mProviders.put(UiEventLogger.class, mUiEventLogger::get);
mProviders.put(FeatureFlags.class, mFeatureFlagsLazy::get);
mProviders.put(StatusBarContentInsetsProvider.class, mContentInsetsProviderLazy::get);

View File

@@ -28,6 +28,7 @@ import android.provider.Settings;
import android.service.quicksettings.Tile;
import android.text.Html;
import android.text.TextUtils;
import android.util.FeatureFlagUtils;
import android.util.Log;
import android.view.View;
import android.widget.Switch;
@@ -51,6 +52,7 @@ 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.qs.tiles.dialog.InternetDialogFactory;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkController.MobileDataIndicators;
@@ -75,6 +77,8 @@ public class InternetTile extends QSTileImpl<SignalState> {
private int mLastTileState = -1;
protected final InternetSignalCallback mSignalCallback = new InternetSignalCallback();
private final InternetDialogFactory mInternetDialogFactory;
final Handler mHandler;
@Inject
public InternetTile(
@@ -86,10 +90,13 @@ public class InternetTile extends QSTileImpl<SignalState> {
StatusBarStateController statusBarStateController,
ActivityStarter activityStarter,
QSLogger qsLogger,
NetworkController networkController
NetworkController networkController,
InternetDialogFactory internetDialogFactory
) {
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
statusBarStateController, activityStarter, qsLogger);
mInternetDialogFactory = internetDialogFactory;
mHandler = mainHandler;
mController = networkController;
mDataController = mController.getMobileDataController();
mController.observe(getLifecycle(), mSignalCallback);
@@ -114,7 +121,13 @@ public class InternetTile extends QSTileImpl<SignalState> {
@Override
protected void handleClick(@Nullable View view) {
mActivityStarter.postStartActivityDismissingKeyguard(INTERNET_PANEL, 0);
if (!FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL)) {
mActivityStarter.postStartActivityDismissingKeyguard(INTERNET_PANEL, 0);
} else {
mHandler.post(() -> {
mInternetDialogFactory.create(true);
});
}
}
@Override

View File

@@ -0,0 +1,228 @@
/*
* 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.systemui.qs.tiles.dialog;
import static com.android.wifitrackerlib.WifiEntry.SECURITY_NONE;
import static com.android.wifitrackerlib.WifiEntry.SECURITY_OWE;
import android.annotation.ColorInt;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.text.Html;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.widget.RecyclerView;
import com.android.settingslib.Utils;
import com.android.systemui.R;
import com.android.wifitrackerlib.WifiEntry;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
/**
* Adapter for showing Wi-Fi networks.
*/
public class InternetAdapter extends RecyclerView.Adapter<InternetAdapter.InternetViewHolder> {
private static final String TAG = "InternetAdapter";
private static final String ACTION_WIFI_DIALOG = "com.android.settings.WIFI_DIALOG";
private static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key";
private static final String EXTRA_CONNECT_FOR_CALLER = "connect_for_caller";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final InternetDialogController mInternetDialogController;
protected View mHolderView;
protected Context mContext;
public InternetAdapter(InternetDialogController controller) {
mInternetDialogController = controller;
}
@Override
public InternetViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
int viewType) {
mContext = viewGroup.getContext();
mHolderView = LayoutInflater.from(mContext).inflate(R.layout.internet_list_item,
viewGroup, false);
return new InternetViewHolder(mHolderView, mInternetDialogController);
}
@Override
public void onBindViewHolder(@NonNull InternetViewHolder viewHolder, int position) {
List<WifiEntry> wifiList = getWifiEntryList();
if (wifiList != null && wifiList.size() != 0) {
int count = getItemCount();
if (wifiList.size() > count) {
wifiList = getWifiEntryList().subList(0, count - 1);
}
if (position < wifiList.size()) {
viewHolder.onBind(wifiList.get(position));
}
} else if (DEBUG) {
Log.d(TAG, "onBindViewHolder, Wi-Fi entry list = null");
}
}
private List<WifiEntry> getWifiEntryList() {
if (mInternetDialogController.getWifiEntryList() == null) {
return null;
}
return mInternetDialogController.getWifiEntryList().stream()
.filter(wifiAp -> wifiAp.getConnectedState()
!= WifiEntry.CONNECTED_STATE_CONNECTED)
.limit(getItemCount())
.collect(Collectors.toList());
}
/**
* The total number of networks (mobile network and entries of Wi-Fi) should be four in
* {@link InternetDialog}.
*
* Airplane mode is ON (mobile network is gone):
* Return four Wi-Fi's entries if no connected Wi-Fi.
* Return three Wi-Fi's entries if one connected Wi-Fi.
* Airplane mode is OFF (mobile network is visible):
* Return three Wi-Fi's entries if no connected Wi-Fi.
* Return two Wi-Fi's entries if one connected Wi-Fi.
*
* @return The total number of networks.
*/
@Override
public int getItemCount() {
boolean hasConnectedWifi = mInternetDialogController.getConnectedWifiEntry() != null;
if (mInternetDialogController.isAirplaneModeEnabled()) {
return hasConnectedWifi ? 3 : 4;
} else {
return hasConnectedWifi ? 2 : 3;
}
}
/**
* ViewHolder for binding Wi-Fi view.
*/
static class InternetViewHolder extends RecyclerView.ViewHolder {
final LinearLayout mContainerLayout;
final LinearLayout mWifiListLayout;
final LinearLayout mWifiNetworkLayout;
final ImageView mWifiIcon;
final TextView mWifiTitleText;
final TextView mWifiSummaryText;
final ImageView mWifiLockedIcon;
final Context mContext;
final InternetDialogController mInternetDialogController;
InternetViewHolder(View view, InternetDialogController internetDialogController) {
super(view);
mContext = view.getContext();
mInternetDialogController = internetDialogController;
mContainerLayout = view.requireViewById(R.id.internet_container);
mWifiListLayout = view.requireViewById(R.id.wifi_list);
mWifiNetworkLayout = view.requireViewById(R.id.wifi_network_layout);
mWifiIcon = view.requireViewById(R.id.wifi_icon);
mWifiTitleText = view.requireViewById(R.id.wifi_title);
mWifiSummaryText = view.requireViewById(R.id.wifi_summary);
mWifiLockedIcon = view.requireViewById(R.id.wifi_locked_icon);
}
void onBind(WifiEntry wifiEntry) {
int security = wifiEntry.getSecurity();
try {
mWifiIcon.setImageDrawable(getWifiDrawable(wifiEntry));
if (isOpenNetwork(security)) {
mWifiLockedIcon.setVisibility(View.GONE);
} else {
mWifiLockedIcon.setVisibility(View.VISIBLE);
mWifiLockedIcon.setImageDrawable(
mContext.getDrawable(R.drawable.ic_friction_lock_closed));
}
} catch (Throwable throwable) {
throwable.printStackTrace();
}
setWifiNetworkLayout(wifiEntry.getTitle(),
Html.fromHtml(wifiEntry.getSummary(false), Html.FROM_HTML_MODE_LEGACY));
mWifiListLayout.setOnClickListener(v -> {
if (!isOpenNetwork(security)) {
// Popup Wi-Fi password dialog condition:
// 1. The access point is a non-open network.
// 2. The Wi-Fi connection is not connected with this access point.
final Intent intent = new Intent(ACTION_WIFI_DIALOG);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
intent.putExtra(EXTRA_CHOSEN_WIFI_ENTRY_KEY, wifiEntry.getKey());
intent.putExtra(EXTRA_CONNECT_FOR_CALLER, false);
mContext.startActivity(intent);
}
mInternetDialogController.connect(wifiEntry);
});
}
/** Return true if this is an open network AccessPoint. */
boolean isOpenNetwork(int security) {
return security == SECURITY_NONE
|| security == SECURITY_OWE;
}
void setWifiNetworkLayout(CharSequence title, CharSequence summary) {
mWifiNetworkLayout.setVisibility(View.VISIBLE);
mWifiTitleText.setText(title);
if (TextUtils.isEmpty(summary)) {
mWifiTitleText.setGravity(Gravity.CENTER);
mWifiSummaryText.setVisibility(View.GONE);
return;
} else {
mWifiTitleText.setGravity(Gravity.BOTTOM);
mWifiSummaryText.setGravity(Gravity.TOP);
mWifiSummaryText.setVisibility(View.VISIBLE);
}
mWifiSummaryText.setText(summary);
}
Drawable getWifiDrawable(WifiEntry wifiEntry) throws Throwable {
Drawable drawable = mContext.getDrawable(
com.android.internal.R.drawable.ic_wifi_signal_0);
AtomicReference<Drawable> shared = new AtomicReference<>();
final @ColorInt int tint = Utils.getColorAttrDefaultColor(mContext,
android.R.attr.colorControlNormal);
Drawable signalDrawable = mContext.getDrawable(
Utils.getWifiIconResource(wifiEntry.getLevel()));
signalDrawable.setTint(tint);
shared.set(signalDrawable);
drawable = shared.get();
return drawable;
}
}
}

View File

@@ -0,0 +1,552 @@
/*
* 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.systemui.qs.tiles.dialog;
import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
import static com.android.systemui.Prefs.Key.QS_HAS_TURNED_OFF_MOBILE_DATA;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyDisplayInfo;
import android.telephony.TelephonyManager;
import android.text.Html;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.Space;
import android.widget.Switch;
import android.widget.TextView;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.settingslib.Utils;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.wifitrackerlib.WifiEntry;
import java.util.List;
import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
/**
* Dialog for showing mobile network, connected Wi-Fi network and Wi-Fi networks.
*/
@SysUISingleton
public class InternetDialog extends SystemUIDialog implements
InternetDialogController.InternetDialogCallback, Window.Callback {
private static final String TAG = "InternetDialog";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final Handler mHandler;
private final LinearLayoutManager mLayoutManager;
private final Runnable mHideProgressBarRunnable = () -> {
setProgressBarVisible(false);
};
@VisibleForTesting
protected InternetAdapter mAdapter;
@VisibleForTesting
protected WifiManager mWifiManager;
@VisibleForTesting
protected View mDialogView;
private InternetDialogFactory mInternetDialogFactory;
private SubscriptionManager mSubscriptionManager;
private TelephonyManager mTelephonyManager;
private AlertDialog mAlertDialog;
private UiEventLogger mUiEventLogger;
private Context mContext;
private InternetDialogController mInternetDialogController;
private TextView mInternetDialogTitle;
private TextView mInternetDialogSubTitle;
private ProgressBar mProgressBar;
private LinearLayout mInternetListLayout;
private LinearLayout mConnectedWifListLayout;
private LinearLayout mConnectedWifList;
private LinearLayout mMobileNetworkLayout;
private LinearLayout mMobileNetworkList;
private LinearLayout mTurnWifiOnLayout;
private LinearLayout mSeeAllLayout;
private Space mSpace;
private RecyclerView mWifiRecyclerView;
private ImageView mConnectedWifiIcon;
private ImageView mWifiSettingsIcon;
private TextView mConnectedWifiTitleText;
private TextView mConnectedWifiSummaryText;
private ImageView mSignalIcon;
private TextView mMobileTitleText;
private TextView mMobileSummaryText;
private Switch mMobileDataToggle;
private Switch mWiFiToggle;
private Button mDoneButton;
private Drawable mBackgroundOn;
private WifiEntry mConnectedWifiEntry;
private int mListMaxHeight;
private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private boolean mIsProgressBarVisible;
private final ViewTreeObserver.OnGlobalLayoutListener mInternetListLayoutListener = () -> {
// Set max height for list
if (mInternetListLayout.getHeight() > mListMaxHeight) {
ViewGroup.LayoutParams params = mInternetListLayout.getLayoutParams();
params.height = mListMaxHeight;
mInternetListLayout.setLayoutParams(params);
}
};
public InternetDialog(Context context, InternetDialogFactory internetDialogFactory,
InternetDialogController internetDialogController,
boolean aboveStatusBar, UiEventLogger uiEventLogger, @Main Handler handler) {
super(context, R.style.Theme_SystemUI_Dialog_Internet);
if (DEBUG) {
Log.d(TAG, "Init InternetDialog");
}
mContext = context;
mHandler = handler;
mInternetDialogFactory = internetDialogFactory;
mInternetDialogController = internetDialogController;
mSubscriptionManager = mInternetDialogController.getSubscriptionManager();
mDefaultDataSubId = mInternetDialogController.getDefaultDataSubscriptionId();
mTelephonyManager = mInternetDialogController.getTelephonyManager();
mWifiManager = mInternetDialogController.getWifiManager();
mLayoutManager = new LinearLayoutManager(mContext) {
@Override
public boolean canScrollVertically() {
return false;
}
};
mListMaxHeight = context.getResources().getDimensionPixelSize(
R.dimen.internet_dialog_list_max_height);
mUiEventLogger = uiEventLogger;
mAdapter = new InternetAdapter(mInternetDialogController);
if (!aboveStatusBar) {
getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
}
show();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (DEBUG) {
Log.d(TAG, "onCreate");
}
mUiEventLogger.log(InternetDialogEvent.INTERNET_DIALOG_SHOW);
mDialogView = LayoutInflater.from(mContext).inflate(R.layout.internet_connectivity_dialog,
null);
final Window window = getWindow();
final WindowManager.LayoutParams lp = window.getAttributes();
lp.gravity = Gravity.BOTTOM;
lp.setFitInsetsTypes(statusBars() | navigationBars());
lp.setFitInsetsSides(WindowInsets.Side.all());
lp.setFitInsetsIgnoringVisibility(true);
window.setAttributes(lp);
window.setContentView(mDialogView);
window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
window.setWindowAnimations(R.style.Animation_InternetDialog);
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
mInternetDialogTitle = mDialogView.requireViewById(R.id.internet_dialog_title);
mInternetDialogSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle);
mProgressBar = mDialogView.requireViewById(R.id.wifi_searching_progress);
mInternetListLayout = mDialogView.requireViewById(R.id.internet_list);
mMobileNetworkLayout = mDialogView.requireViewById(R.id.mobile_network_layout);
mMobileNetworkList = mDialogView.requireViewById(R.id.mobile_network_list);
mTurnWifiOnLayout = mDialogView.requireViewById(R.id.turn_on_wifi_layout);
mConnectedWifListLayout = mDialogView.requireViewById(R.id.wifi_connected_layout);
mConnectedWifList = mDialogView.requireViewById(R.id.wifi_connected_list);
mConnectedWifiIcon = mDialogView.requireViewById(R.id.wifi_connected_icon);
mConnectedWifiTitleText = mDialogView.requireViewById(R.id.wifi_connected_title);
mConnectedWifiSummaryText = mDialogView.requireViewById(R.id.wifi_connected_summary);
mWifiSettingsIcon = mDialogView.requireViewById(R.id.wifi_settings_icon);
mWifiRecyclerView = mDialogView.requireViewById(R.id.wifi_list_layout);
mSeeAllLayout = mDialogView.requireViewById(R.id.see_all_layout);
mSpace = mDialogView.requireViewById(R.id.space);
mDoneButton = mDialogView.requireViewById(R.id.done);
mSignalIcon = mDialogView.requireViewById(R.id.signal_icon);
mMobileTitleText = mDialogView.requireViewById(R.id.mobile_title);
mMobileSummaryText = mDialogView.requireViewById(R.id.mobile_summary);
mMobileDataToggle = mDialogView.requireViewById(R.id.mobile_toggle);
mWiFiToggle = mDialogView.requireViewById(R.id.wifi_toggle);
mBackgroundOn = mContext.getDrawable(R.drawable.settingslib_switch_bar_bg_on);
mInternetListLayout.getViewTreeObserver().addOnGlobalLayoutListener(
mInternetListLayoutListener);
mInternetDialogTitle.setText(getDialogTitleText());
mInternetDialogTitle.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
setOnClickListener();
mTurnWifiOnLayout.setBackground(null);
mWifiRecyclerView.setLayoutManager(mLayoutManager);
mWifiRecyclerView.setAdapter(mAdapter);
}
@Override
public void onStart() {
super.onStart();
if (DEBUG) {
Log.d(TAG, "onStart");
}
mInternetDialogController.onStart(this);
}
@Override
public void onStop() {
super.onStop();
if (DEBUG) {
Log.d(TAG, "onStop");
}
mHandler.removeCallbacks(mHideProgressBarRunnable);
mMobileNetworkLayout.setOnClickListener(null);
mMobileDataToggle.setOnCheckedChangeListener(null);
mConnectedWifListLayout.setOnClickListener(null);
mSeeAllLayout.setOnClickListener(null);
mWiFiToggle.setOnCheckedChangeListener(null);
mDoneButton.setOnClickListener(null);
mInternetDialogController.onStop();
mInternetDialogFactory.destroyDialog();
}
@Override
public void dismissDialog() {
if (DEBUG) {
Log.d(TAG, "dismissDialog");
}
mInternetDialogFactory.destroyDialog();
dismiss();
}
void updateDialog() {
if (DEBUG) {
Log.d(TAG, "updateDialog");
}
if (mInternetDialogController.isAirplaneModeEnabled()) {
mInternetDialogSubTitle.setVisibility(View.GONE);
} else {
mInternetDialogSubTitle.setText(getSubtitleText());
}
showProgressBar();
setMobileDataLayout(mInternetDialogController.activeNetworkIsCellular());
setConnectedWifiLayout();
boolean isWifiEnabled = mWifiManager.isWifiEnabled();
mWiFiToggle.setChecked(isWifiEnabled);
int visible = isWifiEnabled ? View.VISIBLE : View.GONE;
mWifiRecyclerView.setVisibility(visible);
mAdapter.notifyDataSetChanged();
mSeeAllLayout.setVisibility(visible);
mSpace.setVisibility(isWifiEnabled ? View.GONE : View.VISIBLE);
}
private void setOnClickListener() {
mMobileNetworkLayout.setOnClickListener(v -> {
if (mInternetDialogController.isMobileDataEnabled()) {
if (!mInternetDialogController.activeNetworkIsCellular()) {
mInternetDialogController.connectCarrierNetwork();
}
}
});
mMobileDataToggle.setOnCheckedChangeListener(
(buttonView, isChecked) -> {
if (!isChecked && shouldShowMobileDialog()) {
showTurnOffMobileDialog();
} else if (!shouldShowMobileDialog()) {
mInternetDialogController.setMobileDataEnabled(mContext, mDefaultDataSubId,
isChecked, false);
}
});
mConnectedWifListLayout.setOnClickListener(v -> {
// TODO(b/191475923): Need to launch the detailed page of Wi-Fi entry.
});
mSeeAllLayout.setOnClickListener(v -> onClickSeeMoreButton());
mWiFiToggle.setOnCheckedChangeListener(
(buttonView, isChecked) -> {
buttonView.setChecked(isChecked);
mWifiManager.setWifiEnabled(isChecked);
mSpace.setVisibility(isChecked ? View.GONE : View.VISIBLE);
});
mDoneButton.setOnClickListener(v -> dismiss());
}
private void setMobileDataLayout(boolean isCellularNetwork) {
if (mInternetDialogController.isAirplaneModeEnabled()
|| !mInternetDialogController.hasCarrier()) {
mMobileNetworkLayout.setVisibility(View.GONE);
} else {
mMobileDataToggle.setChecked(mInternetDialogController.isMobileDataEnabled());
mMobileNetworkLayout.setVisibility(View.VISIBLE);
mMobileTitleText.setText(getMobileNetworkTitle());
mMobileSummaryText.setText(
Html.fromHtml(getMobileNetworkSummary(), Html.FROM_HTML_MODE_LEGACY));
mSignalIcon.setImageDrawable(getSignalStrengthDrawable());
int titleColor = isCellularNetwork ? mContext.getColor(
R.color.connected_network_primary_color) : Utils.getColorAttrDefaultColor(
mContext, android.R.attr.textColorPrimary);
int summaryColor = isCellularNetwork ? mContext.getColor(
R.color.connected_network_tertiary_color) : Utils.getColorAttrDefaultColor(
mContext, android.R.attr.textColorTertiary);
mMobileTitleText.setTextColor(titleColor);
mMobileSummaryText.setTextColor(summaryColor);
mMobileNetworkLayout.setBackground(isCellularNetwork ? mBackgroundOn : null);
}
}
private void setConnectedWifiLayout() {
if (!mWifiManager.isWifiEnabled()
|| mInternetDialogController.getConnectedWifiEntry() == null) {
mConnectedWifListLayout.setBackground(null);
mConnectedWifListLayout.setVisibility(View.GONE);
return;
}
mConnectedWifListLayout.setVisibility(View.VISIBLE);
mConnectedWifiTitleText.setText(getConnectedWifiTitle());
mConnectedWifiSummaryText.setText(getConnectedWifiSummary());
mConnectedWifiIcon.setImageDrawable(getConnectedWifiDrawable());
mConnectedWifiTitleText.setTextColor(
mContext.getColor(R.color.connected_network_primary_color));
mConnectedWifiSummaryText.setTextColor(
mContext.getColor(R.color.connected_network_tertiary_color));
mWifiSettingsIcon.setColorFilter(
mContext.getColor(R.color.connected_network_primary_color));
mConnectedWifListLayout.setBackground(mBackgroundOn);
}
void onClickSeeMoreButton() {
mInternetDialogController.launchNetworkSetting();
}
CharSequence getDialogTitleText() {
return mInternetDialogController.getDialogTitleText();
}
CharSequence getSubtitleText() {
return mInternetDialogController.getSubtitleText(mIsProgressBarVisible);
}
private Drawable getConnectedWifiDrawable() {
try {
return mInternetDialogController.getWifiConnectedDrawable(mConnectedWifiEntry);
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
private Drawable getSignalStrengthDrawable() {
return mInternetDialogController.getSignalStrengthDrawable();
}
CharSequence getMobileNetworkTitle() {
return mInternetDialogController.getMobileNetworkTitle();
}
String getMobileNetworkSummary() {
return mInternetDialogController.getMobileNetworkSummary();
}
String getConnectedWifiTitle() {
return mInternetDialogController.getConnectedWifiTitle();
}
String getConnectedWifiSummary() {
return mInternetDialogController.getConnectedWifiSummary();
}
private void showProgressBar() {
if (mWifiManager == null || !mWifiManager.isWifiEnabled()) {
setProgressBarVisible(false);
return;
}
setProgressBarVisible(true);
List<ScanResult> wifiScanResults = mWifiManager.getScanResults();
if (wifiScanResults != null && wifiScanResults.size() > 0) {
mContext.getMainThreadHandler().postDelayed(mHideProgressBarRunnable,
2000 /* delay millis */);
}
}
private void setProgressBarVisible(boolean visible) {
if (mWifiManager.isWifiEnabled() && mAdapter.mHolderView != null
&& mAdapter.mHolderView.isAttachedToWindow()) {
mIsProgressBarVisible = true;
}
mIsProgressBarVisible = visible;
mProgressBar.setVisibility(mIsProgressBarVisible ? View.VISIBLE : View.INVISIBLE);
mInternetDialogSubTitle.setText(getSubtitleText());
}
private boolean shouldShowMobileDialog() {
boolean flag = Prefs.getBoolean(mContext, QS_HAS_TURNED_OFF_MOBILE_DATA,
false);
if (mInternetDialogController.isMobileDataEnabled() && !flag) {
return true;
}
return false;
}
private void showTurnOffMobileDialog() {
CharSequence carrierName =
mSubscriptionManager.getDefaultDataSubscriptionInfo().getCarrierName();
boolean isInService = mInternetDialogController.isVoiceStateInService();
if (TextUtils.isEmpty(carrierName) || !isInService) {
carrierName = mContext.getString(R.string.mobile_data_disable_message_default_carrier);
}
mAlertDialog = new Builder(mContext)
.setTitle(R.string.mobile_data_disable_title)
.setMessage(mContext.getString(R.string.mobile_data_disable_message, carrierName))
.setNegativeButton(android.R.string.cancel, (d, w) -> {
mMobileDataToggle.setChecked(true);
})
.setPositiveButton(
com.android.internal.R.string.alert_windows_notification_turn_off_action,
(d, w) -> {
mInternetDialogController.setMobileDataEnabled(mContext,
mDefaultDataSubId, false, false);
mMobileDataToggle.setChecked(false);
Prefs.putBoolean(mContext, QS_HAS_TURNED_OFF_MOBILE_DATA, true);
})
.create();
mAlertDialog.setOnCancelListener(dialog -> mMobileDataToggle.setChecked(true));
mAlertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
SystemUIDialog.setShowForAllUsers(mAlertDialog, true);
SystemUIDialog.registerDismissListener(mAlertDialog);
SystemUIDialog.setWindowOnTop(mAlertDialog);
mAlertDialog.show();
}
@Override
public void onRefreshCarrierInfo() {
mHandler.post(() -> updateDialog());
}
@Override
public void onSimStateChanged() {
mHandler.post(() -> updateDialog());
}
@Override
public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
mHandler.post(() -> updateDialog());
}
@Override
public void onSubscriptionsChanged(int defaultDataSubId) {
mDefaultDataSubId = defaultDataSubId;
mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId);
mHandler.post(() -> updateDialog());
}
@Override
public void onServiceStateChanged(ServiceState serviceState) {
mHandler.post(() -> updateDialog());
}
@Override
public void onDataConnectionStateChanged(int state, int networkType) {
mAdapter.notifyDataSetChanged();
mHandler.post(() -> updateDialog());
}
@Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
mHandler.post(() -> updateDialog());
}
@Override
public void onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo) {
mHandler.post(() -> updateDialog());
}
@Override
public void onAccessPointsChanged(List<WifiEntry> wifiEntryList, WifiEntry connectedEntry) {
mConnectedWifiEntry = connectedEntry;
mAdapter.notifyDataSetChanged();
mHandler.post(() -> updateDialog());
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (mAlertDialog != null && !mAlertDialog.isShowing()) {
if (!hasFocus && isShowing()) {
dismiss();
}
}
}
@Override
public void onWifiStateReceived(Context context, Intent intent) {
if (intent == null) {
return;
}
String action = intent.getAction();
if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
mInternetDialogController.scanWifiAccessPoints();
showProgressBar();
return;
}
if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
mHandler.post(() -> updateDialog());
}
}
public enum InternetDialogEvent implements UiEventLogger.UiEventEnum {
@UiEvent(doc = "The Internet dialog became visible on the screen.")
INTERNET_DIALOG_SHOW(843);
private final int mId;
InternetDialogEvent(int id) {
mId = id;
}
@Override
public int getId() {
return mId;
}
}
}

View File

@@ -0,0 +1,62 @@
/*
* 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.systemui.qs.tiles.dialog
import android.content.Context
import android.os.Handler
import android.util.Log
import com.android.internal.logging.UiEventLogger
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import javax.inject.Inject
private const val TAG = "InternetDialogFactory"
private val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
/**
* Factory to create [InternetDialog] objects.
*/
@SysUISingleton
class InternetDialogFactory @Inject constructor(
@Main private val handler: Handler,
private val internetDialogController: InternetDialogController,
private val context: Context,
private val uiEventLogger: UiEventLogger
) {
companion object {
var internetDialog: InternetDialog? = null
}
/** Creates a [InternetDialog]. */
fun create(aboveStatusBar: Boolean) {
if (internetDialog != null) {
if (DEBUG) {
Log.d(TAG, "InternetDialog is showing, do not create it twice.")
}
return
} else {
internetDialog = InternetDialog(context, this, internetDialogController, aboveStatusBar,
uiEventLogger, handler)
}
}
fun destroyDialog() {
if (DEBUG) {
Log.d(TAG, "destroyDialog")
}
internetDialog = null
}
}

View File

@@ -68,9 +68,12 @@ import com.android.systemui.R;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.qs.tiles.dialog.InternetDialogFactory;
import com.android.systemui.qs.tiles.dialog.InternetDialogUtil;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
@@ -191,6 +194,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
private boolean mUserSetup;
private boolean mSimDetected;
private boolean mForceCellularValidated;
private InternetDialogFactory mInternetDialogFactory;
private Handler mMainHandler;
private ConfigurationController.ConfigurationListener mConfigurationListener =
new ConfigurationController.ConfigurationListener() {
@@ -221,7 +226,9 @@ public class NetworkControllerImpl extends BroadcastReceiver
DemoModeController demoModeController,
CarrierConfigTracker carrierConfigTracker,
FeatureFlags featureFlags,
DumpManager dumpManager) {
DumpManager dumpManager,
@Main Handler handler,
InternetDialogFactory internetDialogFactory) {
this(context, connectivityManager,
telephonyManager,
telephonyListenerManager,
@@ -242,6 +249,8 @@ public class NetworkControllerImpl extends BroadcastReceiver
featureFlags,
dumpManager);
mReceiverHandler.post(mRegisterListeners);
mMainHandler = handler;
mInternetDialogFactory = internetDialogFactory;
}
@VisibleForTesting
@@ -480,6 +489,9 @@ public class NetworkControllerImpl extends BroadcastReceiver
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
if (InternetDialogUtil.isProviderModelEnabled(mContext)) {
filter.addAction(Settings.Panel.ACTION_INTERNET_CONNECTIVITY);
}
mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mReceiverHandler);
mListening = true;
@@ -788,6 +800,9 @@ public class NetworkControllerImpl extends BroadcastReceiver
mConfig = Config.readConfig(mContext);
mReceiverHandler.post(this::handleConfigurationChanged);
break;
case Settings.Panel.ACTION_INTERNET_CONNECTIVITY:
mMainHandler.post(() -> mInternetDialogFactory.create(true));
break;
default:
int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);

View File

@@ -0,0 +1,102 @@
package com.android.systemui.qs.tiles.dialog;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner;
import android.view.View;
import android.widget.LinearLayout;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.wifitrackerlib.WifiEntry;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.Arrays;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class InternetAdapterTest extends SysuiTestCase {
private static final String WIFI_TITLE = "Wi-Fi Title";
private static final String WIFI_SUMMARY = "Wi-Fi Summary";
private InternetDialogController mInternetDialogController = mock(
InternetDialogController.class);
private InternetAdapter mInternetAdapter;
private InternetAdapter.InternetViewHolder mViewHolder;
@Mock
private WifiEntry mWifiEntry = mock(WifiEntry.class);
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mInternetAdapter = new InternetAdapter(mInternetDialogController);
mViewHolder = (InternetAdapter.InternetViewHolder) mInternetAdapter
.onCreateViewHolder(new LinearLayout(mContext), 0);
when(mWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
when(mWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
when(mInternetDialogController.getWifiEntryList()).thenReturn(Arrays.asList(mWifiEntry));
}
@Test
public void getItemCount_withApmOnWifiOnNoConnectedWifi_returnFour() {
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
assertThat(mInternetAdapter.getItemCount()).isEqualTo(4);
}
@Test
public void getItemCount_withApmOnWifiOnHasConnectedWifi_returnThree() {
when(mWifiEntry.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED);
when(mInternetDialogController.getConnectedWifiEntry()).thenReturn(mWifiEntry);
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
assertThat(mInternetAdapter.getItemCount()).isEqualTo(3);
}
@Test
public void getItemCount_withApmOffWifiOnNoConnectedWifi_returnThree() {
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
assertThat(mInternetAdapter.getItemCount()).isEqualTo(3);
}
@Test
public void getItemCount_withApmOffWifiOnHasConnectedWifi_returnTwo() {
when(mWifiEntry.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED);
when(mInternetDialogController.getConnectedWifiEntry()).thenReturn(mWifiEntry);
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
assertThat(mInternetAdapter.getItemCount()).isEqualTo(2);
}
@Test
public void onBindViewHolder_bindWithOpenWifiNetwork_verifyView() {
when(mWifiEntry.getSecurity()).thenReturn(WifiEntry.SECURITY_NONE);
mInternetAdapter.onBindViewHolder(mViewHolder, 0);
assertThat(mViewHolder.mWifiTitleText.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mWifiSummaryText.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mWifiIcon.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mWifiLockedIcon.getVisibility()).isEqualTo(View.GONE);
}
@Test
public void onBindViewHolder_bindWithSecurityWifiNetwork_verifyView() {
when(mWifiEntry.getSecurity()).thenReturn(WifiEntry.SECURITY_PSK);
mInternetAdapter.onBindViewHolder(mViewHolder, 0);
assertThat(mViewHolder.mWifiTitleText.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mWifiSummaryText.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mWifiIcon.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mWifiLockedIcon.getVisibility()).isEqualTo(View.VISIBLE);
}
}

View File

@@ -0,0 +1,245 @@
package com.android.systemui.qs.tiles.dialog;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.telephony.TelephonyManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.wifitrackerlib.WifiEntry;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.Arrays;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
public class InternetDialogTest extends SysuiTestCase {
private static final int SUB_ID = 1;
private static final String MOBILE_NETWORK_TITLE = "Mobile Title";
private static final String MOBILE_NETWORK_SUMMARY = "Mobile Summary";
private static final String WIFI_TITLE = "Connected Wi-Fi Title";
private static final String WIFI_SUMMARY = "Connected Wi-Fi Summary";
private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class);
private InternetDialogFactory mInternetDialogFactory = mock(InternetDialogFactory.class);
private InternetAdapter mInternetAdapter = mock(InternetAdapter.class);
private InternetDialogController mInternetDialogController = mock(
InternetDialogController.class);
private InternetDialogController.InternetDialogCallback mCallback =
mock(InternetDialogController.InternetDialogCallback.class);
private MockInternetDialog mInternetDialog;
private WifiReceiver mWifiReceiver = null;
private WifiManager mMockWifiManager = mock(WifiManager.class);
private TelephonyManager mTelephonyManager = mock(TelephonyManager.class);
@Mock
private WifiEntry mWifiEntry = mock(WifiEntry.class);
@Mock
private WifiInfo mWifiInfo;
@Mock
private Handler mHandler;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mInternetDialog = new MockInternetDialog(mContext, mInternetDialogFactory,
mInternetDialogController, true, mUiEventLogger, mHandler);
doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(SUB_ID);
when(mMockWifiManager.isWifiEnabled()).thenReturn(true);
when(mMockWifiManager.getConnectionInfo()).thenReturn(mWifiInfo);
mInternetDialog.setMobileNetworkTitle(MOBILE_NETWORK_TITLE);
mInternetDialog.setMobileNetworkSummary(MOBILE_NETWORK_SUMMARY);
mInternetDialog.setConnectedWifiTitle(WIFI_TITLE);
mInternetDialog.setConnectedWifiSummary(WIFI_SUMMARY);
mWifiReceiver = new WifiReceiver();
IntentFilter mIntentFilter = new IntentFilter();
mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
mContext.registerReceiver(mWifiReceiver, mIntentFilter);
when(mWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
when(mWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
when(mInternetDialogController.getWifiEntryList()).thenReturn(Arrays.asList(mWifiEntry));
}
@After
public void tearDown() {
mInternetDialog.dismissDialog();
}
@Test
public void updateDialog_withApmOn_internetDialogSubTitleGone() {
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
mInternetDialog.updateDialog();
final TextView view = mInternetDialog.mDialogView.requireViewById(
R.id.internet_dialog_subtitle);
assertThat(view.getVisibility()).isEqualTo(View.GONE);
}
@Test
public void updateDialog_withApmOff_internetDialogSubTitleVisible() {
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
mInternetDialog.updateDialog();
final TextView view = mInternetDialog.mDialogView.requireViewById(
R.id.internet_dialog_subtitle);
assertThat(view.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
public void updateDialog_withApmOn_mobileDataLayoutGone() {
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
mInternetDialog.updateDialog();
final LinearLayout linearLayout = mInternetDialog.mDialogView.requireViewById(
R.id.mobile_network_layout);
assertThat(linearLayout.getVisibility()).isEqualTo(View.GONE);
}
@Test
public void updateDialog_withWifiOnAndHasConnectedWifi_connectedWifiLayoutVisible() {
doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
when(mWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
when(mWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
when(mWifiEntry.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_CONNECTED);
when(mInternetDialogController.getConnectedWifiEntry()).thenReturn(mWifiEntry);
mInternetDialog.updateDialog();
final LinearLayout linearLayout = mInternetDialog.mDialogView.requireViewById(
R.id.wifi_connected_layout);
assertThat(linearLayout.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
public void updateDialog_withWifiOnAndNoConnectedWifi_connectedWifiLayoutGone() {
doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
mInternetDialog.updateDialog();
final LinearLayout linearLayout = mInternetDialog.mDialogView.requireViewById(
R.id.wifi_connected_layout);
assertThat(linearLayout.getVisibility()).isEqualTo(View.GONE);
}
@Test
public void updateDialog_withWifiOff_WifiRecycleViewGone() {
when(mMockWifiManager.isWifiEnabled()).thenReturn(false);
mInternetDialog.updateDialog();
final RecyclerView view = mInternetDialog.mDialogView.requireViewById(
R.id.wifi_list_layout);
assertThat(view.getVisibility()).isEqualTo(View.GONE);
}
@Test
public void onClickSeeMoreButton_clickSeeMore_verifyLaunchNetworkSetting() {
final LinearLayout seeAllLayout = mInternetDialog.mDialogView.requireViewById(
R.id.see_all_layout);
seeAllLayout.performClick();
verify(mInternetDialogController).launchNetworkSetting();
}
private class MockInternetDialog extends InternetDialog {
private String mMobileNetworkTitle;
private String mMobileNetworkSummary;
private String mConnectedWifiTitle;
private String mConnectedWifiSummary;
MockInternetDialog(Context context, InternetDialogFactory internetDialogFactory,
InternetDialogController internetDialogController,
boolean aboveStatusBar, UiEventLogger uiEventLogger, @Main Handler handler) {
super(context, internetDialogFactory, internetDialogController, aboveStatusBar,
uiEventLogger, handler);
mAdapter = mInternetAdapter;
mWifiManager = mMockWifiManager;
}
@Override
String getMobileNetworkTitle() {
return mMobileNetworkTitle;
}
@Override
String getMobileNetworkSummary() {
return mMobileNetworkSummary;
}
void setMobileNetworkTitle(String title) {
mMobileNetworkTitle = title;
}
void setMobileNetworkSummary(String summary) {
mMobileNetworkSummary = summary;
}
@Override
String getConnectedWifiTitle() {
return mConnectedWifiTitle;
}
@Override
String getConnectedWifiSummary() {
return mConnectedWifiSummary;
}
void setConnectedWifiTitle(String title) {
mConnectedWifiTitle = title;
}
void setConnectedWifiSummary(String summary) {
mConnectedWifiSummary = summary;
}
@Override
public void onWifiStateReceived(Context context, Intent intent) {
setMobileNetworkTitle(MOBILE_NETWORK_TITLE);
setMobileNetworkSummary(MOBILE_NETWORK_SUMMARY);
}
}
private class WifiReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
return;
}
if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
mInternetDialog.updateDialog();
}
}
}
}