diff options
36 files changed, 3405 insertions, 4 deletions
diff --git a/packages/SystemUI/res/drawable/ic_arrow_forward.xml b/packages/SystemUI/res/drawable/ic_arrow_forward.xml new file mode 100644 index 000000000000..438e4c70dc71 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_arrow_forward.xml @@ -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> diff --git a/packages/SystemUI/res/drawable/ic_friction_lock_closed.xml b/packages/SystemUI/res/drawable/ic_friction_lock_closed.xml new file mode 100644 index 000000000000..2c34060ccd61 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_friction_lock_closed.xml @@ -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> diff --git a/packages/SystemUI/res/drawable/ic_settings_24dp.xml b/packages/SystemUI/res/drawable/ic_settings_24dp.xml new file mode 100644 index 000000000000..ac4c43bd35b9 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_settings_24dp.xml @@ -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> diff --git a/packages/SystemUI/res/drawable/ic_signal_strength_zero_bar_no_internet.xml b/packages/SystemUI/res/drawable/ic_signal_strength_zero_bar_no_internet.xml new file mode 100644 index 000000000000..f38a36804bc8 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_signal_strength_zero_bar_no_internet.xml @@ -0,0 +1,34 @@ +<?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. +--> +<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="#FF000000" + android:pathData="M2,22l16,0l0,-2l-11,0l13,-13l0,1l2,0l0,-6z" + android:strokeAlpha="0.3" + android:fillAlpha="0.3"/> + <path + android:fillColor="#FF000000" + android:pathData="M20,10h2v8h-2z"/> + <path + android:fillColor="#FF000000" + android:pathData="M20,20h2v2h-2z"/> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/internet_dialog_background.xml b/packages/SystemUI/res/drawable/internet_dialog_background.xml new file mode 100644 index 000000000000..3ceb0f6ac06a --- /dev/null +++ b/packages/SystemUI/res/drawable/internet_dialog_background.xml @@ -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> diff --git a/packages/SystemUI/res/drawable/internet_dialog_footer_background.xml b/packages/SystemUI/res/drawable/internet_dialog_footer_background.xml new file mode 100644 index 000000000000..50267fda0b25 --- /dev/null +++ b/packages/SystemUI/res/drawable/internet_dialog_footer_background.xml @@ -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>
\ No newline at end of file diff --git a/packages/SystemUI/res/drawable/internet_dialog_rounded_top_corner_background.xml b/packages/SystemUI/res/drawable/internet_dialog_rounded_top_corner_background.xml new file mode 100644 index 000000000000..14672ef3dcfe --- /dev/null +++ b/packages/SystemUI/res/drawable/internet_dialog_rounded_top_corner_background.xml @@ -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> diff --git a/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_disabled.xml b/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_disabled.xml new file mode 100644 index 000000000000..088e82bb4260 --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_disabled.xml @@ -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> diff --git a/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml b/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml new file mode 100644 index 000000000000..250188b892f4 --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_switch_bar_bg_on.xml @@ -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> diff --git a/packages/SystemUI/res/drawable/settingslib_thumb_disabled.xml b/packages/SystemUI/res/drawable/settingslib_thumb_disabled.xml new file mode 100644 index 000000000000..b41762f7908e --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_thumb_disabled.xml @@ -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> diff --git a/packages/SystemUI/res/drawable/settingslib_thumb_off.xml b/packages/SystemUI/res/drawable/settingslib_thumb_off.xml new file mode 100644 index 000000000000..8b69ad1b2493 --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_thumb_off.xml @@ -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> diff --git a/packages/SystemUI/res/drawable/settingslib_thumb_on.xml b/packages/SystemUI/res/drawable/settingslib_thumb_on.xml new file mode 100644 index 000000000000..0f27fc2f4ad8 --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_thumb_on.xml @@ -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> diff --git a/packages/SystemUI/res/drawable/settingslib_thumb_selector.xml b/packages/SystemUI/res/drawable/settingslib_thumb_selector.xml new file mode 100644 index 000000000000..06bb779b91ef --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_thumb_selector.xml @@ -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> diff --git a/packages/SystemUI/res/drawable/settingslib_track_disabled_background.xml b/packages/SystemUI/res/drawable/settingslib_track_disabled_background.xml new file mode 100644 index 000000000000..15dfcb70e25e --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_track_disabled_background.xml @@ -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> diff --git a/packages/SystemUI/res/drawable/settingslib_track_off_background.xml b/packages/SystemUI/res/drawable/settingslib_track_off_background.xml new file mode 100644 index 000000000000..4d79a6e20776 --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_track_off_background.xml @@ -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> diff --git a/packages/SystemUI/res/drawable/settingslib_track_on_background.xml b/packages/SystemUI/res/drawable/settingslib_track_on_background.xml new file mode 100644 index 000000000000..c12d012a0508 --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_track_on_background.xml @@ -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> diff --git a/packages/SystemUI/res/drawable/settingslib_track_selector.xml b/packages/SystemUI/res/drawable/settingslib_track_selector.xml new file mode 100644 index 000000000000..a38c3b4241a3 --- /dev/null +++ b/packages/SystemUI/res/drawable/settingslib_track_selector.xml @@ -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> diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml new file mode 100644 index 000000000000..6163af09fa6b --- /dev/null +++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml @@ -0,0 +1,366 @@ +<?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="24dp" + android:layout_marginBottom="24dp" + android:layout_height="wrap_content" + android:orientation="vertical"> + + <TextView + android:id="@+id/internet_dialog_title" + android:gravity="center_vertical|center_horizontal" + android:layout_width="wrap_content" + android:layout_height="32dp" + 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="20dp" + android:layout_marginTop="8dp" + 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"/> + + <androidx.core.widget.NestedScrollView + android:id="@+id/scroll_view" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <LinearLayout + android:id="@+id/scroll_layout" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + <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:layout_gravity="center_vertical|start" + 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="19dp" + 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/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_width="wrap_content" + android:layout_height="match_parent" + android:gravity="start|center_vertical"> + <TextView + android:id="@+id/mobile_title" + android:layout_marginLeft="17dp" + 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_marginLeft="17dp" + 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" + android:layout_gravity="end|center_vertical"> + <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_marginBottom="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_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> + </androidx.core.widget.NestedScrollView> +</LinearLayout> diff --git a/packages/SystemUI/res/layout/internet_list_item.xml b/packages/SystemUI/res/layout/internet_list_item.xml new file mode 100644 index 000000000000..cb51ab6a3361 --- /dev/null +++ b/packages/SystemUI/res/layout/internet_list_item.xml @@ -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> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 2260d2175268..bbbaf65f861b 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -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> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 78db2a8a3485..02ff5ce327ec 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1590,4 +1590,35 @@ <!-- The padding between the icon and the text. --> <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> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 0b56f0cce4ef..584eb511154b 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2994,4 +2994,37 @@ <string name="global_actions_change_description" translatable="false"><xliff:g>%1$s</xliff:g></string> <!-- URL for more information about changes in global actions --> <string name="global_actions_change_url" translatable="false"></string> + + <!-- Provider Model: Title of the airplane mode in the internet dialog. [CHAR LIMIT=50] --> + <string name="airplane_mode">Airplane mode</string> + <!-- Provider Model: Default title of the mobile network in the mobile layout. [CHAR LIMIT=50] --> + <string name="mobile_data_settings_title">Mobile data</string> + <!-- Provider Model: Summary text separator for preferences including a short description + (eg. "Connected / 5G"). [CHAR LIMIT=50] --> + <string name="preference_summary_default_combination"><xliff:g id="state" example="Connected">%1$s</xliff:g> / <xliff:g id="networkMode" example="LTE">%2$s</xliff:g></string> + <!-- Provider Model: + Summary indicating that a SIM has an active mobile data connection [CHAR LIMIT=50] --> + <string name="mobile_data_connection_active">Connected</string> + <!-- Provider Model: + Summary indicating that a SIM has no mobile data connection [CHAR LIMIT=50] --> + <string name="mobile_data_off_summary">Internet won\u0027t auto\u2011connect</string> + <!-- Provider Model: + Summary indicating that a active SIM and no network available [CHAR LIMIT=50] --> + <string name="mobile_data_no_connection">No connection</string> + <!-- Provider Model: Summary indicating that no other networks available [CHAR LIMIT=50] --> + <string name="non_carrier_network_unavailable">No other networks available</string> + <!-- Provider Model: Summary indicating that no networks available [CHAR LIMIT=50] --> + <string name="all_network_unavailable">No networks available</string> + <!-- Provider Model: Panel title text for turning on the Wi-Fi networks. [CHAR LIMIT=40] --> + <string name="turn_on_wifi">Wi\u2011Fi</string> + <!-- Provider Model: Title for detail page of wifi network [CHAR LIMIT=30] --> + <string name="pref_title_network_details" msgid="7329759534269363308">"Network details"</string> + <!-- Provider Model: Panel subtitle for tapping a network to connect to internet. [CHAR LIMIT=60] --> + <string name="tap_a_network_to_connect">Tap a network to connect</string> + <!-- Provider Model: Wi-Fi settings. text displayed when Wi-Fi is on and network list is empty [CHAR LIMIT=50]--> + <string name="wifi_empty_list_wifi_on">Searching for networks\u2026</string> + <!-- Provider Model: Failure notification for connect --> + <string name="wifi_failed_connect_message">Failed to connect to network</string> + <!-- Provider Model: Title to see all the networks [CHAR LIMIT=50] --> + <string name="see_all_networks">See all</string> </resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 51eabf60385e..ca6fd4adbc08 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -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> diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index 76f30a80114a..00b33a416df4 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -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); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java index 41a3fb0211a7..65e93c6f31a3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java @@ -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 diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java new file mode 100644 index 000000000000..44c1b7bd7332 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java @@ -0,0 +1,225 @@ +/* + * 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 (wifiEntry.shouldEditBeforeConnect()) { + 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; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java new file mode 100644 index 000000000000..50fb66c10f83 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java @@ -0,0 +1,553 @@ +/* + * 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.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; + +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); + } + } + + @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 layoutParams = window.getAttributes(); + layoutParams.gravity = Gravity.BOTTOM; + // Move down the dialog to overlay the navigation bar. + layoutParams.setFitInsetsTypes( + layoutParams.getFitInsetsTypes() & ~WindowInsets.Type.navigationBars()); + layoutParams.setFitInsetsSides(WindowInsets.Side.all()); + layoutParams.setFitInsetsIgnoringVisibility(true); + window.setAttributes(layoutParams); + 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)); + window.addFlags(FLAG_LAYOUT_NO_LIMITS); + + 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; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java new file mode 100644 index 000000000000..24c2fb1eb3f9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java @@ -0,0 +1,851 @@ +/* + * 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.settingslib.mobile.MobileMappings.getIconKey; +import static com.android.settingslib.mobile.MobileMappings.mapIconSets; + +import android.annotation.ColorInt; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.LayerDrawable; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiManager; +import android.os.Handler; +import android.provider.Settings; +import android.telephony.ServiceState; +import android.telephony.SignalStrength; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyCallback; +import android.telephony.TelephonyDisplayInfo; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.util.Log; +import android.view.Gravity; +import android.widget.Toast; + +import com.android.internal.logging.UiEventLogger; +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.KeyguardUpdateMonitorCallback; +import com.android.settingslib.DeviceInfoUtils; +import com.android.settingslib.Utils; +import com.android.settingslib.graph.SignalDrawable; +import com.android.settingslib.mobile.MobileMappings; +import com.android.settingslib.net.SignalStrengthUtil; +import com.android.systemui.R; +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.NetworkController.AccessPointController; +import com.android.systemui.util.settings.GlobalSettings; +import com.android.wifitrackerlib.MergedCarrierEntry; +import com.android.wifitrackerlib.WifiEntry; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import javax.inject.Inject; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + +public class InternetDialogController implements WifiEntry.DisconnectCallback, + NetworkController.AccessPointController.AccessPointCallback { + + private static final String TAG = "InternetDialogController"; + private static final String ACTION_NETWORK_PROVIDER_SETTINGS = + "android.settings.NETWORK_PROVIDER_SETTINGS"; + private static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key"; + public static final Drawable EMPTY_DRAWABLE = new ColorDrawable(Color.TRANSPARENT); + public static final int NO_CELL_DATA_TYPE_ICON = 0; + private static final int SUBTITLE_TEXT_WIFI_IS_OFF = R.string.wifi_is_off; + private static final int SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT = + R.string.tap_a_network_to_connect; + private static final int SUBTITLE_TEXT_SEARCHING_FOR_NETWORKS = + R.string.wifi_empty_list_wifi_on; + private static final int SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE = + R.string.non_carrier_network_unavailable; + private static final int SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE = + R.string.all_network_unavailable; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + private WifiManager mWifiManager; + private Context mContext; + private ActivityStarter mActivityStarter; + private SubscriptionManager mSubscriptionManager; + private TelephonyManager mTelephonyManager; + private ConnectivityManager mConnectivityManager; + private TelephonyDisplayInfo mTelephonyDisplayInfo = + new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_UNKNOWN, + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE); + private Handler mHandler; + private MobileMappings.Config mConfig = null; + private Executor mExecutor; + private AccessPointController mAccessPointController; + private IntentFilter mWifiStateFilter; + private InternetDialogCallback mCallback; + private List<WifiEntry> mWifiEntry; + private WifiEntry mConnectedEntry; + private UiEventLogger mUiEventLogger; + private BroadcastDispatcher mBroadcastDispatcher; + private KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private GlobalSettings mGlobalSettings; + private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; + + @VisibleForTesting + protected SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangedListener; + @VisibleForTesting + protected InternetTelephonyCallback mInternetTelephonyCallback; + + private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback = + new KeyguardUpdateMonitorCallback() { + @Override + public void onRefreshCarrierInfo() { + mCallback.onRefreshCarrierInfo(); + } + + @Override + public void onSimStateChanged(int subId, int slotId, int simState) { + mCallback.onSimStateChanged(); + } + }; + + protected List<SubscriptionInfo> getSubscriptionInfo() { + return mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(false); + } + + @Inject + public InternetDialogController(@NonNull Context context, UiEventLogger uiEventLogger, + ActivityStarter starter, AccessPointController accessPointController, + SubscriptionManager subscriptionManager, TelephonyManager telephonyManager, + @Nullable WifiManager wifiManager, ConnectivityManager connectivityManager, + @Main Handler handler, @Main Executor mainExecutor, + BroadcastDispatcher broadcastDispatcher, KeyguardUpdateMonitor keyguardUpdateMonitor, + GlobalSettings globalSettings) { + if (DEBUG) { + Log.d(TAG, "Init InternetDialogController"); + } + mHandler = handler; + mExecutor = mainExecutor; + mContext = context; + mGlobalSettings = globalSettings; + mWifiManager = wifiManager; + mTelephonyManager = telephonyManager; + mConnectivityManager = connectivityManager; + mSubscriptionManager = subscriptionManager; + mBroadcastDispatcher = broadcastDispatcher; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mWifiStateFilter = new IntentFilter(WifiManager.NETWORK_STATE_CHANGED_ACTION); + mWifiStateFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); + mUiEventLogger = uiEventLogger; + mActivityStarter = starter; + mAccessPointController = accessPointController; + mConfig = MobileMappings.Config.readConfig(mContext); + } + + void onStart(@NonNull InternetDialogCallback callback) { + if (DEBUG) { + Log.d(TAG, "onStart"); + } + mCallback = callback; + mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback); + mAccessPointController.addAccessPointCallback(this); + mBroadcastDispatcher.registerReceiver(mWifiStateReceiver, mWifiStateFilter, mExecutor); + // Listen the subscription changes + mOnSubscriptionsChangedListener = new InternetOnSubscriptionChangedListener(); + mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor, + mOnSubscriptionsChangedListener); + mDefaultDataSubId = getDefaultDataSubscriptionId(); + mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId); + mInternetTelephonyCallback = new InternetTelephonyCallback(); + mTelephonyManager.registerTelephonyCallback(mExecutor, mInternetTelephonyCallback); + // Listen the connectivity changes + mConnectivityManager.registerNetworkCallback(new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(), new DataConnectivityListener(), mHandler); + scanWifiAccessPoints(); + } + + void onStop() { + if (DEBUG) { + Log.d(TAG, "onStop"); + } + mBroadcastDispatcher.unregisterReceiver(mWifiStateReceiver); + mTelephonyManager.unregisterTelephonyCallback(mInternetTelephonyCallback); + mSubscriptionManager.removeOnSubscriptionsChangedListener( + mOnSubscriptionsChangedListener); + mAccessPointController.removeAccessPointCallback(this); + mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback); + } + + @VisibleForTesting + boolean isAirplaneModeEnabled() { + return mGlobalSettings.getInt(Settings.Global.AIRPLANE_MODE_ON, 0) != 0; + } + + @VisibleForTesting + protected int getDefaultDataSubscriptionId() { + return mSubscriptionManager.getDefaultDataSubscriptionId(); + } + + @VisibleForTesting + protected Intent getSettingsIntent() { + return new Intent(ACTION_NETWORK_PROVIDER_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + } + + CharSequence getDialogTitleText() { + if (isAirplaneModeEnabled()) { + return mContext.getText(R.string.airplane_mode); + } + return mContext.getText(R.string.quick_settings_internet_label); + } + + CharSequence getSubtitleText(boolean isProgressBarVisible) { + if (isAirplaneModeEnabled()) { + return null; + } + + if (!mWifiManager.isWifiEnabled()) { + // When the airplane mode is off and Wi-Fi is disabled. + // Sub-Title: Wi-Fi is off + if (DEBUG) { + Log.d(TAG, "Airplane mode off + Wi-Fi off."); + } + return mContext.getText(SUBTITLE_TEXT_WIFI_IS_OFF); + } + + if (isProgressBarVisible) { + // When the Wi-Fi scan result callback is received + // Sub-Title: Searching for networks... + return mContext.getText(SUBTITLE_TEXT_SEARCHING_FOR_NETWORKS); + } + + final List<ScanResult> wifiList = mWifiManager.getScanResults(); + if (wifiList != null && wifiList.size() != 0) { + return mContext.getText(SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT); + } + + // Sub-Title: + // show non_carrier_network_unavailable + // - while Wi-Fi on + no Wi-Fi item + // - while Wi-Fi on + no Wi-Fi item + mobile data off + // show all_network_unavailable: + // - while Wi-Fi on + no Wi-Fi item + no carrier item + // - while Wi-Fi on + no Wi-Fi item + service is out of service + // - while Wi-Fi on + no Wi-Fi item + mobile data on + no carrier data. + if (DEBUG) { + Log.d(TAG, "No Wi-Fi item."); + } + if (!hasCarrier() || (!isVoiceStateInService() && !isDataStateInService())) { + if (DEBUG) { + Log.d(TAG, "No carrier or service is out of service."); + } + return mContext.getText(SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE); + } + + if (!isMobileDataEnabled()) { + if (DEBUG) { + Log.d(TAG, "Mobile data off"); + } + return mContext.getText(SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE); + } + + if (!activeNetworkIsCellular()) { + if (DEBUG) { + Log.d(TAG, "No carrier data."); + } + return mContext.getText(SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE); + } + + return mContext.getText(SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE); + } + + Drawable getWifiConnectedDrawable(WifiEntry wifiEntry) throws Throwable { + final @ColorInt int tint; + tint = Utils.getColorAttrDefaultColor(mContext, + com.android.internal.R.attr.colorAccentPrimaryVariant); + final Drawable drawable = mContext.getDrawable( + com.android.settingslib.Utils.getWifiIconResource(wifiEntry.getLevel())); + drawable.setTint(tint); + + return drawable; + } + + Drawable getSignalStrengthDrawable() { + Drawable drawable = mContext.getDrawable( + R.drawable.ic_signal_strength_zero_bar_no_internet); + try { + if (mTelephonyManager == null) { + if (DEBUG) { + Log.d(TAG, "TelephonyManager is null"); + } + return drawable; + } + + if (isDataStateInService() || isVoiceStateInService()) { + AtomicReference<Drawable> shared = new AtomicReference<>(); + shared.set(getSignalStrengthDrawableWithLevel()); + drawable = shared.get(); + } + + drawable.setTint( + Utils.getColorAttrDefaultColor(mContext, android.R.attr.colorControlNormal)); + if (activeNetworkIsCellular()) { + drawable.setTint(Utils.getColorAttrDefaultColor(mContext, + com.android.internal.R.attr.colorAccentPrimaryVariant)); + } + + } catch (Throwable e) { + e.printStackTrace(); + } + return drawable; + } + + /** + * To get the signal bar icon with level. + * + * @return The Drawable which is a signal bar icon with level. + */ + Drawable getSignalStrengthDrawableWithLevel() { + final SignalStrength strength = mTelephonyManager.getSignalStrength(); + int level = (strength == null) ? 0 : strength.getLevel(); + int numLevels = SignalStrength.NUM_SIGNAL_STRENGTH_BINS; + if (mSubscriptionManager != null && shouldInflateSignalStrength(mDefaultDataSubId)) { + level += 1; + numLevels += 1; + } + return getSignalStrengthIcon(mContext, level, numLevels, NO_CELL_DATA_TYPE_ICON, false); + } + + Drawable getSignalStrengthIcon(Context context, int level, int numLevels, + int iconType, boolean cutOut) { + Log.d(TAG, "getSignalStrengthIcon"); + final SignalDrawable signalDrawable = new SignalDrawable(context); + signalDrawable.setLevel( + SignalDrawable.getState(level, numLevels, cutOut)); + + // Make the network type drawable + final Drawable networkDrawable = + iconType == NO_CELL_DATA_TYPE_ICON + ? EMPTY_DRAWABLE + : context.getResources().getDrawable(iconType, context.getTheme()); + + // Overlay the two drawables + final Drawable[] layers = {networkDrawable, signalDrawable}; + final int iconSize = + context.getResources().getDimensionPixelSize(R.dimen.signal_strength_icon_size); + + final LayerDrawable icons = new LayerDrawable(layers); + // Set the network type icon at the top left + icons.setLayerGravity(0 /* index of networkDrawable */, Gravity.TOP | Gravity.LEFT); + // Set the signal strength icon at the bottom right + icons.setLayerGravity(1 /* index of SignalDrawable */, Gravity.BOTTOM | Gravity.RIGHT); + icons.setLayerSize(1 /* index of SignalDrawable */, iconSize, iconSize); + icons.setTintList(Utils.getColorAttr(context, android.R.attr.colorControlNormal)); + return icons; + } + + private boolean shouldInflateSignalStrength(int subId) { + return SignalStrengthUtil.shouldInflateSignalStrength(mContext, subId); + } + + private CharSequence getUniqueSubscriptionDisplayName(int subscriptionId, Context context) { + final Map<Integer, CharSequence> displayNames = getUniqueSubscriptionDisplayNames(context); + return displayNames.getOrDefault(subscriptionId, ""); + } + + private Map<Integer, CharSequence> getUniqueSubscriptionDisplayNames(Context context) { + class DisplayInfo { + public SubscriptionInfo subscriptionInfo; + public CharSequence originalName; + public CharSequence uniqueName; + } + + // Map of SubscriptionId to DisplayName + final Supplier<Stream<DisplayInfo>> originalInfos = + () -> getSubscriptionInfo() + .stream() + .filter(i -> { + // Filter out null values. + return (i != null && i.getDisplayName() != null); + }) + .map(i -> { + DisplayInfo info = new DisplayInfo(); + info.subscriptionInfo = i; + info.originalName = i.getDisplayName().toString().trim(); + return info; + }); + + // A Unique set of display names + Set<CharSequence> uniqueNames = new HashSet<>(); + // Return the set of duplicate names + final Set<CharSequence> duplicateOriginalNames = originalInfos.get() + .filter(info -> !uniqueNames.add(info.originalName)) + .map(info -> info.originalName) + .collect(Collectors.toSet()); + + // If a display name is duplicate, append the final 4 digits of the phone number. + // Creates a mapping of Subscription id to original display name + phone number display name + final Supplier<Stream<DisplayInfo>> uniqueInfos = () -> originalInfos.get().map(info -> { + if (duplicateOriginalNames.contains(info.originalName)) { + // This may return null, if the user cannot view the phone number itself. + final String phoneNumber = DeviceInfoUtils.getBidiFormattedPhoneNumber(context, + info.subscriptionInfo); + String lastFourDigits = ""; + if (phoneNumber != null) { + lastFourDigits = (phoneNumber.length() > 4) + ? phoneNumber.substring(phoneNumber.length() - 4) : phoneNumber; + } + + if (TextUtils.isEmpty(lastFourDigits)) { + info.uniqueName = info.originalName; + } else { + info.uniqueName = info.originalName + " " + lastFourDigits; + } + + } else { + info.uniqueName = info.originalName; + } + return info; + }); + + // Check uniqueness a second time. + // We might not have had permission to view the phone numbers. + // There might also be multiple phone numbers whose last 4 digits the same. + uniqueNames.clear(); + final Set<CharSequence> duplicatePhoneNames = uniqueInfos.get() + .filter(info -> !uniqueNames.add(info.uniqueName)) + .map(info -> info.uniqueName) + .collect(Collectors.toSet()); + + return uniqueInfos.get().map(info -> { + if (duplicatePhoneNames.contains(info.uniqueName)) { + info.uniqueName = info.originalName + " " + + info.subscriptionInfo.getSubscriptionId(); + } + return info; + }).collect(Collectors.toMap( + info -> info.subscriptionInfo.getSubscriptionId(), + info -> info.uniqueName)); + } + + CharSequence getMobileNetworkTitle() { + return getUniqueSubscriptionDisplayName(mDefaultDataSubId, mContext); + } + + String getMobileNetworkSummary() { + String description = getNetworkTypeDescription(mContext, mConfig, + mTelephonyDisplayInfo, mDefaultDataSubId); + return getMobileSummary(mContext, mTelephonyManager, description); + } + + /** + * Get currently description of mobile network type. + */ + private String getNetworkTypeDescription(Context context, MobileMappings.Config config, + TelephonyDisplayInfo telephonyDisplayInfo, int subId) { + String iconKey = getIconKey(telephonyDisplayInfo); + + if (mapIconSets(config) == null || mapIconSets(config).get(iconKey) == null) { + if (DEBUG) { + Log.d(TAG, "The description of network type is empty."); + } + return ""; + } + + int resId = mapIconSets(config).get(iconKey).dataContentDescription; + return resId != 0 + ? SubscriptionManager.getResourcesForSubId(context, subId).getString(resId) : ""; + } + + private String getMobileSummary(Context context, TelephonyManager telephonyManager, + String networkTypeDescription) { + if (!isMobileDataEnabled()) { + return context.getString(R.string.mobile_data_off_summary); + } + if (!isDataStateInService()) { + return context.getString(R.string.mobile_data_no_connection); + } + String summary = networkTypeDescription; + if (activeNetworkIsCellular()) { + summary = context.getString(R.string.preference_summary_default_combination, + context.getString(R.string.mobile_data_connection_active), + networkTypeDescription); + } + return summary; + } + + String getConnectedWifiTitle() { + if (getConnectedWifiEntry() == null) { + if (DEBUG) { + Log.d(TAG, "connected entry is null"); + } + return ""; + } + return getConnectedWifiEntry().getTitle(); + } + + String getConnectedWifiSummary() { + if (getConnectedWifiEntry() == null) { + if (DEBUG) { + Log.d(TAG, "connected entry is null"); + } + return ""; + } + return getConnectedWifiEntry().getSummary(false); + } + + void launchNetworkSetting() { + mCallback.dismissDialog(); + mActivityStarter.postStartActivityDismissingKeyguard(getSettingsIntent(), 0); + } + + void connectCarrierNetwork() { + final MergedCarrierEntry mergedCarrierEntry = + mAccessPointController.getMergedCarrierEntry(); + if (mergedCarrierEntry != null && mergedCarrierEntry.canConnect()) { + mergedCarrierEntry.connect(null /* ConnectCallback */); + } + } + + List<WifiEntry> getWifiEntryList() { + return mWifiEntry; + } + + WifiEntry getConnectedWifiEntry() { + return mConnectedEntry; + } + + WifiManager getWifiManager() { + return mWifiManager; + } + + TelephonyManager getTelephonyManager() { + return mTelephonyManager; + } + + SubscriptionManager getSubscriptionManager() { + return mSubscriptionManager; + } + + /** + * @return whether there is the carrier item in the slice. + */ + boolean hasCarrier() { + if (mSubscriptionManager == null) { + if (DEBUG) { + Log.d(TAG, "SubscriptionManager is null, can not check carrier."); + } + return false; + } + + if (isAirplaneModeEnabled() || mTelephonyManager == null + || mSubscriptionManager.getActiveSubscriptionIdList().length <= 0) { + return false; + } + return true; + } + + /** + * Return {@code true} if mobile data is enabled + */ + boolean isMobileDataEnabled() { + if (mTelephonyManager == null || !mTelephonyManager.isDataEnabled()) { + return false; + } + return true; + } + + /** + * Set whether to enable data for {@code subId}, also whether to disable data for other + * subscription + */ + void setMobileDataEnabled(Context context, int subId, boolean enabled, + boolean disableOtherSubscriptions) { + if (mTelephonyManager == null) { + if (DEBUG) { + Log.d(TAG, "TelephonyManager is null, can not set mobile data."); + } + return; + } + + if (mSubscriptionManager == null) { + if (DEBUG) { + Log.d(TAG, "SubscriptionManager is null, can not set mobile data."); + } + return; + } + + mTelephonyManager.setDataEnabled(enabled); + if (disableOtherSubscriptions) { + final List<SubscriptionInfo> subInfoList = + mSubscriptionManager.getActiveSubscriptionInfoList(); + if (subInfoList != null) { + for (SubscriptionInfo subInfo : subInfoList) { + // We never disable mobile data for opportunistic subscriptions. + if (subInfo.getSubscriptionId() != subId && !subInfo.isOpportunistic()) { + context.getSystemService(TelephonyManager.class).createForSubscriptionId( + subInfo.getSubscriptionId()).setDataEnabled(false); + } + } + } + } + } + + boolean isDataStateInService() { + if (mTelephonyManager == null) { + if (DEBUG) { + Log.d(TAG, "TelephonyManager is null, can not detect mobile state."); + } + return false; + } + return mTelephonyManager.getDataState() == TelephonyManager.DATA_CONNECTED; + } + + boolean isVoiceStateInService() { + if (mTelephonyManager == null) { + if (DEBUG) { + Log.d(TAG, "TelephonyManager is null, can not detect voice state."); + } + return false; + } + + final ServiceState serviceState = mTelephonyManager.getServiceState(); + return serviceState != null + && serviceState.getState() == serviceState.STATE_IN_SERVICE; + } + + boolean activeNetworkIsCellular() { + if (mConnectivityManager == null) { + if (DEBUG) { + Log.d(TAG, "ConnectivityManager is null, can not check active network."); + } + return false; + } + + final Network activeNetwork = mConnectivityManager.getActiveNetwork(); + if (activeNetwork == null) { + return false; + } + final NetworkCapabilities networkCapabilities = + mConnectivityManager.getNetworkCapabilities(activeNetwork); + if (networkCapabilities == null) { + return false; + } + return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR); + } + + boolean connect(WifiEntry ap) { + if (ap == null) { + if (DEBUG) { + Log.d(TAG, "No Wi-Fi ap to connect."); + } + return false; + } + + if (ap.getWifiConfiguration() != null) { + if (DEBUG) { + Log.d(TAG, "connect networkId=" + ap.getWifiConfiguration().networkId); + } + } else { + if (DEBUG) { + Log.d(TAG, "connect to unsaved network " + ap.getTitle()); + } + } + ap.connect(new WifiEntryConnectCallback(mActivityStarter, mContext, ap)); + return false; + } + + static class WifiEntryConnectCallback implements WifiEntry.ConnectCallback { + final ActivityStarter mActivityStarter; + final Context mContext; + final WifiEntry mWifiEntry; + + WifiEntryConnectCallback(ActivityStarter activityStarter, Context context, + WifiEntry connectWifiEntry) { + mActivityStarter = activityStarter; + mContext = context; + mWifiEntry = connectWifiEntry; + } + + @Override + public void onConnectResult(@ConnectStatus int status) { + if (DEBUG) { + Log.d(TAG, "onConnectResult " + status); + } + + if (status == WifiEntry.ConnectCallback.CONNECT_STATUS_FAILURE_NO_CONFIG) { + final Intent intent = new Intent("com.android.settings.WIFI_DIALOG") + .putExtra(EXTRA_CHOSEN_WIFI_ENTRY_KEY, mWifiEntry.getKey()); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mActivityStarter.startActivity(intent, true); + } else if (status == CONNECT_STATUS_FAILURE_UNKNOWN) { + Toast.makeText(mContext, R.string.wifi_failed_connect_message, + Toast.LENGTH_SHORT).show(); + } else { + if (DEBUG) { + Log.d(TAG, "connect failure reason=" + status); + } + } + } + } + + void scanWifiAccessPoints() { + mAccessPointController.scanForAccessPoints(); + } + + @Override + public void onAccessPointsChanged(List<WifiEntry> accessPoints) { + if (accessPoints == null) { + return; + } + + boolean hasConnectedWifi = false; + mWifiEntry = accessPoints; + for (WifiEntry wifiEntry : accessPoints) { + if (wifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTED) { + mConnectedEntry = wifiEntry; + hasConnectedWifi = true; + break; + } + } + if (!hasConnectedWifi) { + mConnectedEntry = null; + } + + mCallback.onAccessPointsChanged(mWifiEntry, mConnectedEntry); + } + + @Override + public void onSettingsActivityTriggered(Intent settingsIntent) { + } + + @Override + public void onDisconnectResult(int status) { + } + + private class InternetTelephonyCallback extends TelephonyCallback implements + TelephonyCallback.DataConnectionStateListener, + TelephonyCallback.DisplayInfoListener, + TelephonyCallback.ServiceStateListener, + TelephonyCallback.SignalStrengthsListener { + + @Override + public void onServiceStateChanged(@NonNull ServiceState serviceState) { + mCallback.onServiceStateChanged(serviceState); + } + + @Override + public void onDataConnectionStateChanged(int state, int networkType) { + mCallback.onDataConnectionStateChanged(state, networkType); + } + + @Override + public void onSignalStrengthsChanged(@NonNull SignalStrength signalStrength) { + mCallback.onSignalStrengthsChanged(signalStrength); + } + + @Override + public void onDisplayInfoChanged(@NonNull TelephonyDisplayInfo telephonyDisplayInfo) { + mTelephonyDisplayInfo = telephonyDisplayInfo; + mCallback.onDisplayInfoChanged(telephonyDisplayInfo); + } + } + + private class InternetOnSubscriptionChangedListener + extends SubscriptionManager.OnSubscriptionsChangedListener { + InternetOnSubscriptionChangedListener() { + super(); + } + + @Override + public void onSubscriptionsChanged() { + mDefaultDataSubId = getDefaultDataSubscriptionId(); + if (SubscriptionManager.isUsableSubscriptionId(mDefaultDataSubId)) { + mTelephonyManager.unregisterTelephonyCallback(mInternetTelephonyCallback); + + mTelephonyManager = mTelephonyManager.createForSubscriptionId(mDefaultDataSubId); + mTelephonyManager.registerTelephonyCallback(mHandler::post, + mInternetTelephonyCallback); + mCallback.onSubscriptionsChanged(mDefaultDataSubId); + } + } + } + + private class DataConnectivityListener extends ConnectivityManager.NetworkCallback { + @Override + public void onCapabilitiesChanged(@NonNull Network network, + @NonNull NetworkCapabilities networkCapabilities) { + final Network activeNetwork = mConnectivityManager.getActiveNetwork(); + if (activeNetwork != null && activeNetwork.equals(network)) { + // update UI + mCallback.onCapabilitiesChanged(network, networkCapabilities); + } + } + } + + private final BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + mCallback.onWifiStateReceived(context, intent); + } + }; + + interface InternetDialogCallback { + + void onRefreshCarrierInfo(); + + void onSimStateChanged(); + + void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities); + + void onSubscriptionsChanged(int defaultDataSubId); + + void onServiceStateChanged(ServiceState serviceState); + + void onDataConnectionStateChanged(int state, int networkType); + + void onSignalStrengthsChanged(SignalStrength signalStrength); + + void onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo); + + void dismissDialog(); + + void onAccessPointsChanged(List<WifiEntry> wifiEntryList, WifiEntry connectedEntry); + + void onWifiStateReceived(Context context, Intent intent); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt new file mode 100644 index 000000000000..85e6160e98c9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt @@ -0,0 +1,63 @@ +/* + * 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) + internetDialog?.show() + } + } + + fun destroyDialog() { + if (DEBUG) { + Log.d(TAG, "destroyDialog") + } + internetDialog = null + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogUtil.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogUtil.java new file mode 100644 index 000000000000..6aaba997faad --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogUtil.java @@ -0,0 +1,14 @@ +package com.android.systemui.qs.tiles.dialog; + +import android.content.Context; +import android.util.FeatureFlagUtils; + +public class InternetDialogUtil { + + public static boolean isProviderModelEnabled(Context context) { + if (context == null) { + return false; + } + return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java index ab58286859cc..5a3d72555d76 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java @@ -40,6 +40,7 @@ import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.settings.UserTracker; +import com.android.wifitrackerlib.MergedCarrierEntry; import com.android.wifitrackerlib.WifiEntry; import com.android.wifitrackerlib.WifiPickerTracker; @@ -157,6 +158,15 @@ public class AccessPointControllerImpl } @Override + public MergedCarrierEntry getMergedCarrierEntry() { + if (mWifiPickerTracker == null) { + fireAcccessPointsCallback(Collections.emptyList()); + return null; + } + return mWifiPickerTracker.getMergedCarrierEntry(); + } + + @Override public int getIcon(WifiEntry ap) { int level = ap.getLevel(); return ICONS[Math.max(0, level)]; 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 ef2ca985858d..6b71f46238e4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -23,6 +23,7 @@ import android.telephony.SubscriptionInfo; import com.android.settingslib.net.DataUsageController; import com.android.systemui.demomode.DemoMode; import com.android.systemui.statusbar.policy.NetworkController.SignalCallback; +import com.android.wifitrackerlib.MergedCarrierEntry; import com.android.wifitrackerlib.WifiEntry; import java.util.List; @@ -223,6 +224,7 @@ public interface NetworkController extends CallbackController<SignalCallback>, D void addAccessPointCallback(AccessPointCallback callback); void removeAccessPointCallback(AccessPointCallback callback); void scanForAccessPoints(); + MergedCarrierEntry getMergedCarrierEntry(); int getIcon(WifiEntry ap); boolean connect(WifiEntry ap); boolean canConfigWifi(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index c49de7ab0e5d..075fa174067c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -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); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java new file mode 100644 index 000000000000..a8f6f5361d78 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java @@ -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); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java new file mode 100644 index 000000000000..83e4d00b3a8f --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java @@ -0,0 +1,269 @@ +package com.android.systemui.qs.tiles.dialog; + +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.os.Handler; +import android.telephony.ServiceState; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.text.TextUtils; + +import com.android.internal.logging.UiEventLogger; +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.NetworkController.AccessPointController; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.settings.GlobalSettings; +import com.android.systemui.util.time.FakeSystemClock; +import com.android.wifitrackerlib.WifiEntry; + +import androidx.annotation.Nullable; +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executor; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +public class InternetDialogControllerTest extends SysuiTestCase { + + private static final int SUB_ID = 1; + private static final String CONNECTED_TITLE = "Connected Wi-Fi Title"; + private static final String CONNECTED_SUMMARY = "Connected Wi-Fi Summary"; + + private final UiEventLogger mUiEventLogger = mock(UiEventLogger.class); + private MockInternetDialogController mInternetDialogController; + private InternetDialogController.InternetDialogCallback mCallback = + mock(InternetDialogController.InternetDialogCallback.class); + private ActivityStarter mStarter = mock(ActivityStarter.class); + private WifiManager mWifiManager = mock(WifiManager.class); + private ConnectivityManager mConnectivityManager = mock(ConnectivityManager.class); + private TelephonyManager mTelephonyManager = mock(TelephonyManager.class); + private SubscriptionManager mSubscriptionManager = mock(SubscriptionManager.class); + private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); + @Mock + private Handler mHandler; + @Mock + private GlobalSettings mGlobalSettings; + @Mock + private KeyguardUpdateMonitor mKeyguardUpdateMonitor; + @Mock + private NetworkController.AccessPointController mAccessPointController; + @Mock + private WifiEntry mWifiEntryConnected = mock(WifiEntry.class); + @Mock + private WifiInfo mWifiInfo; + @Mock + private ServiceState mServiceState; + @Mock + private BroadcastDispatcher mBroadcastDispatcher; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(SUB_ID); + when(mWifiManager.getConnectionInfo()).thenReturn(mWifiInfo); + mInternetDialogController = new MockInternetDialogController(mContext, mUiEventLogger, + mStarter, mAccessPointController, mSubscriptionManager, mTelephonyManager, + mWifiManager, mConnectivityManager, mHandler, mExecutor, mBroadcastDispatcher, + mKeyguardUpdateMonitor, mGlobalSettings); + mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor, + mInternetDialogController.mOnSubscriptionsChangedListener); + mInternetDialogController.onStart(mCallback); + } + + @Test + public void getDialogTitleText_withAirplaneModeOn_returnAirplaneMode() { + mInternetDialogController.setAirplaneModeEnabled(true); + + assertTrue(TextUtils.equals(mInternetDialogController.getDialogTitleText(), + getResourcesString("airplane_mode"))); + } + + @Test + public void getDialogTitleText_withAirplaneModeOff_returnInternet() { + mInternetDialogController.setAirplaneModeEnabled(false); + + assertTrue(TextUtils.equals(mInternetDialogController.getDialogTitleText(), + getResourcesString("quick_settings_internet_label"))); + } + + @Test + public void getSubtitleText_withAirplaneModeOn_returnNull() { + mInternetDialogController.setAirplaneModeEnabled(true); + + assertThat(mInternetDialogController.getSubtitleText(false)).isNull(); + } + + @Test + public void getSubtitleText_withWifiOff_returnWifiIsOff() { + mInternetDialogController.setAirplaneModeEnabled(false); + when(mWifiManager.isWifiEnabled()).thenReturn(false); + + assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(false), + getResourcesString("wifi_is_off"))); + } + + @Test + public void getSubtitleText_withWifiOn_returnSearchWifi() { + mInternetDialogController.setAirplaneModeEnabled(false); + when(mWifiManager.isWifiEnabled()).thenReturn(true); + + assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(true), + getResourcesString("wifi_empty_list_wifi_on"))); + } + + @Test + public void getSubtitleText_withWifiEntry_returnTapToConnect() { + mInternetDialogController.setAirplaneModeEnabled(false); + when(mWifiManager.isWifiEnabled()).thenReturn(true); + List<ScanResult> wifiScanResults = mock(ArrayList.class); + doReturn(1).when(wifiScanResults).size(); + when(mWifiManager.getScanResults()).thenReturn(wifiScanResults); + + assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(false), + getResourcesString("tap_a_network_to_connect"))); + } + + @Test + public void getSubtitleText_withNoService_returnNoNetworksAvailable() { + mInternetDialogController.setAirplaneModeEnabled(false); + when(mWifiManager.isWifiEnabled()).thenReturn(true); + List<ScanResult> wifiScanResults = new ArrayList<>(); + doReturn(wifiScanResults).when(mWifiManager).getScanResults(); + when(mWifiManager.getScanResults()).thenReturn(wifiScanResults); + when(mSubscriptionManager.getActiveSubscriptionIdList()) + .thenReturn(new int[] {SUB_ID}); + + doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mServiceState).getState(); + doReturn(mServiceState).when(mTelephonyManager).getServiceState(); + doReturn(TelephonyManager.DATA_DISCONNECTED).when(mTelephonyManager).getDataState(); + + assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(false), + getResourcesString("all_network_unavailable"))); + } + + @Test + public void getSubtitleText_withMobileDataDisabled_returnNoOtherAvailable() { + mInternetDialogController.setAirplaneModeEnabled(false); + when(mWifiManager.isWifiEnabled()).thenReturn(true); + List<ScanResult> wifiScanResults = new ArrayList<>(); + doReturn(wifiScanResults).when(mWifiManager).getScanResults(); + when(mWifiManager.getScanResults()).thenReturn(wifiScanResults); + when(mSubscriptionManager.getActiveSubscriptionIdList()) + .thenReturn(new int[] {SUB_ID}); + + doReturn(ServiceState.STATE_IN_SERVICE).when(mServiceState).getState(); + doReturn(mServiceState).when(mTelephonyManager).getServiceState(); + + when(mTelephonyManager.isDataEnabled()).thenReturn(false); + + assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(false), + getResourcesString("non_carrier_network_unavailable"))); + } + + @Test + public void getConnectedWifiTitle_withNoConnectedEntry_returnNull() { + mInternetDialogController.setConnectedWifiEntry(null); + + assertTrue(TextUtils.equals(mInternetDialogController.getConnectedWifiTitle(), + "")); + } + + @Test + public void getConnectedWifiTitle_withConnectedEntry_returnTitle() { + mInternetDialogController.setConnectedWifiEntry(mWifiEntryConnected); + when(mWifiEntryConnected.getTitle()).thenReturn(CONNECTED_TITLE); + + assertTrue(TextUtils.equals(mInternetDialogController.getConnectedWifiTitle(), + CONNECTED_TITLE)); + } + + @Test + public void getConnectedWifiSummary_withNoConnectedEntry_returnNull() { + mInternetDialogController.setConnectedWifiEntry(null); + + assertTrue(TextUtils.equals(mInternetDialogController.getConnectedWifiSummary(), + "")); + } + + @Test + public void getConnectedWifiSummary_withConnectedEntry_returnSummary() { + mInternetDialogController.setConnectedWifiEntry(mWifiEntryConnected); + when(mWifiEntryConnected.getSummary(false)).thenReturn(CONNECTED_SUMMARY); + + assertTrue(TextUtils.equals(mInternetDialogController.getConnectedWifiSummary(), + CONNECTED_SUMMARY)); + } + + private String getResourcesString(String name) { + return mContext.getResources().getString(getResourcesId(name)); + } + + private int getResourcesId(String name) { + return mContext.getResources().getIdentifier(name, "string", + mContext.getPackageName()); + } + + private class MockInternetDialogController extends InternetDialogController { + + private WifiEntry mConnectedEntry; + private GlobalSettings mGlobalSettings; + private boolean mIsAirplaneModeOn; + + MockInternetDialogController(Context context, UiEventLogger uiEventLogger, + ActivityStarter starter, AccessPointController accessPointController, + SubscriptionManager subscriptionManager, TelephonyManager telephonyManager, + @Nullable WifiManager wifiManager, ConnectivityManager connectivityManager, + @Main Handler handler, @Main Executor mainExecutor, + BroadcastDispatcher broadcastDispatcher, + KeyguardUpdateMonitor keyguardUpdateMonitor, GlobalSettings globalSettings) { + super(context, uiEventLogger, starter, accessPointController, subscriptionManager, + telephonyManager, wifiManager, connectivityManager, handler, mainExecutor, + broadcastDispatcher, keyguardUpdateMonitor, globalSettings); + mGlobalSettings = globalSettings; + } + + @Override + boolean isAirplaneModeEnabled() { + return mIsAirplaneModeOn; + } + + public void setAirplaneModeEnabled(boolean enabled) { + mIsAirplaneModeOn = enabled; + } + + @Override + WifiEntry getConnectedWifiEntry() { + return mConnectedEntry; + } + + public void setConnectedWifiEntry(WifiEntry connectedEntry) { + mConnectedEntry = connectedEntry; + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java new file mode 100644 index 000000000000..d394b0c9bfe2 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java @@ -0,0 +1,246 @@ +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); + mInternetDialog.show(); + 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(); + } + } + } + +} |