Snap for 10213992 from 6cb1f9401d to udc-qpr1-release
Change-Id: Ia57be4477bd96e96f09faf66f391608711f7360c
This commit is contained in:
@@ -864,6 +864,7 @@
|
||||
|
||||
<activity
|
||||
android:name="Settings$LongBackgroundTasksActivity"
|
||||
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
||||
android:exported="true"
|
||||
android:label="@string/long_background_tasks_label">
|
||||
<intent-filter android:priority="1">
|
||||
@@ -1545,6 +1546,7 @@
|
||||
|
||||
<activity
|
||||
android:name="Settings$ManageApplicationsActivity"
|
||||
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
||||
android:exported="true"
|
||||
android:label="@string/applications_settings">
|
||||
<intent-filter android:priority="1">
|
||||
@@ -1607,6 +1609,7 @@
|
||||
|
||||
<activity
|
||||
android:name="Settings$HighPowerApplicationsActivity"
|
||||
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
||||
android:exported="true"
|
||||
android:label="@string/high_power_apps">
|
||||
<intent-filter android:priority="1">
|
||||
@@ -1665,6 +1668,7 @@
|
||||
This is for compatibility with old shortcuts. -->
|
||||
<activity-alias android:name=".RunningServices"
|
||||
android:label="@string/runningservices_settings_title"
|
||||
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
||||
android:exported="true"
|
||||
android:targetActivity="Settings$ManageApplicationsActivity">
|
||||
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
|
||||
@@ -1677,6 +1681,7 @@
|
||||
This is for compatibility with old shortcuts. -->
|
||||
<activity-alias android:name=".applications.StorageUse"
|
||||
android:label="@string/storageuse_settings_title"
|
||||
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
||||
android:exported="true"
|
||||
android:targetActivity="Settings$ManageApplicationsActivity">
|
||||
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
|
||||
@@ -1743,6 +1748,7 @@
|
||||
<!-- Provide direct entry into manage apps showing running services. -->
|
||||
<activity android:name="Settings$RunningServicesActivity"
|
||||
android:exported="true"
|
||||
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
||||
android:label="@string/runningservices_settings_title">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
@@ -1761,6 +1767,7 @@
|
||||
<!-- Provide direct entry into manage apps showing storage usage of apps. -->
|
||||
<activity
|
||||
android:name="Settings$StorageUseActivity"
|
||||
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
||||
android:exported="true"
|
||||
android:label="@string/storageuse_settings_title">
|
||||
<intent-filter android:priority="1">
|
||||
@@ -2105,6 +2112,7 @@
|
||||
|
||||
<activity
|
||||
android:name="Settings$UsageAccessSettingsActivity"
|
||||
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
||||
android:exported="true"
|
||||
android:label="@string/usage_access_title">
|
||||
<intent-filter android:priority="1">
|
||||
@@ -3483,6 +3491,7 @@
|
||||
<activity
|
||||
android:name="Settings$TurnScreenOnSettingsActivity"
|
||||
android:exported="true"
|
||||
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
||||
android:label="@string/turn_screen_on_title">
|
||||
<intent-filter android:priority="1">
|
||||
<action android:name="android.settings.TURN_SCREEN_ON_SETTINGS" />
|
||||
@@ -3662,6 +3671,7 @@
|
||||
<activity android:name="Settings$NotificationAppListActivity"
|
||||
android:label="@string/app_notifications_title"
|
||||
android:icon="@drawable/ic_notifications"
|
||||
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
||||
android:exported="true">
|
||||
<intent-filter android:priority="1">
|
||||
<action android:name="android.settings.ALL_APPS_NOTIFICATION_SETTINGS" />
|
||||
@@ -3676,6 +3686,7 @@
|
||||
<!-- Displays a list of apps available for cloning on the device -->
|
||||
<activity android:name=".Settings$ClonedAppsListActivity"
|
||||
android:label="@string/cloned_apps_dashboard_title"
|
||||
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
||||
android:exported="true">
|
||||
<intent-filter android:priority="1">
|
||||
<action android:name="android.settings.MANAGE_CLONED_APPS_SETTINGS" />
|
||||
@@ -3717,7 +3728,7 @@
|
||||
<!-- Show channel-level notification settings (channel passed in as extras) -->
|
||||
<activity android:name=".notification.app.ChannelPanelActivity"
|
||||
android:label="@string/notification_channel_title"
|
||||
android:theme="@style/Theme.Panel.Material"
|
||||
android:theme="@style/Theme.Panel"
|
||||
android:excludeFromRecents="true"
|
||||
android:configChanges="keyboardHidden|screenSize"
|
||||
android:exported="true">
|
||||
@@ -3941,6 +3952,7 @@
|
||||
|
||||
<activity
|
||||
android:name="Settings$OverlaySettingsActivity"
|
||||
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
||||
android:exported="true"
|
||||
android:label="@string/draw_overlay">
|
||||
<intent-filter android:priority="1">
|
||||
@@ -3978,6 +3990,7 @@
|
||||
|
||||
<activity
|
||||
android:name="Settings$WriteSettingsActivity"
|
||||
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
||||
android:exported="true"
|
||||
android:label="@string/write_settings_title">
|
||||
<intent-filter android:priority="1">
|
||||
@@ -4011,6 +4024,7 @@
|
||||
<activity
|
||||
android:name="Settings$AlarmsAndRemindersActivity"
|
||||
android:exported="true"
|
||||
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
||||
android:label="@string/alarms_and_reminders_label">
|
||||
<intent-filter android:priority="1">
|
||||
<action android:name="android.settings.REQUEST_SCHEDULE_EXACT_ALARM" />
|
||||
@@ -4041,6 +4055,7 @@
|
||||
|
||||
<activity
|
||||
android:name="Settings$ManageExternalSourcesActivity"
|
||||
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
||||
android:exported="true"
|
||||
android:label="@string/install_other_apps">
|
||||
<intent-filter android:priority="1">
|
||||
@@ -4095,6 +4110,7 @@
|
||||
|
||||
<activity
|
||||
android:name="Settings$ManageExternalStorageActivity"
|
||||
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
||||
android:exported="true"
|
||||
android:label="@string/manage_external_storage_title">
|
||||
<intent-filter android:priority="1">
|
||||
@@ -4126,6 +4142,7 @@
|
||||
|
||||
<activity
|
||||
android:name="Settings$MediaManagementAppsActivity"
|
||||
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
||||
android:exported="true"
|
||||
android:label="@string/media_management_apps_title">
|
||||
<intent-filter android:priority="1">
|
||||
|
||||
@@ -15,7 +15,10 @@
|
||||
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">
|
||||
<solid
|
||||
android:color="?androidprv:attr/materialColorSurfaceContainer" />
|
||||
<stroke
|
||||
android:width="2dp"
|
||||
android:color="?android:attr/colorAccent"/>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
android:shape="rectangle">
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="?android:attr/colorAccent"/>
|
||||
android:color="@color/notification_importance_button_unselected"/>
|
||||
|
||||
<corners android:radius="@dimen/rect_button_radius" />
|
||||
</shape>
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<com.google.android.setupdesign.GlifLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/setup_wizard_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout="@layout/sud_glif_blank_template"
|
||||
style="?attr/fingerprint_layout_theme">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:clipToPadding="false"
|
||||
android:clipChildren="false">
|
||||
|
||||
<!-- Both texts are kept as separate text views so it doesn't jump around in portrait.
|
||||
See layouts/fingerprint_enroll_enrolling_base.xml. -->
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="?attr/sudMarginStart"
|
||||
android:layout_marginEnd="@dimen/enroll_margin_end"
|
||||
android:layout_marginBottom="@dimen/sud_content_frame_padding_bottom"
|
||||
android:paddingStart="@dimen/enroll_padding_start"
|
||||
android:paddingEnd="@dimen/enroll_padding_end"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:fillViewport="true">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/sud_layout_icon"
|
||||
style="@style/SudGlifIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:scaleType="fitStart"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:src="@drawable/ic_lock" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/suc_layout_title"
|
||||
style="@style/SudGlifHeaderTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginEnd="0dp" />
|
||||
|
||||
<TextView
|
||||
style="@style/SudDescription.Glif"
|
||||
android:id="@+id/sud_layout_subtitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<include layout="@layout/udfps_enroll_view" />
|
||||
</com.google.android.setupdesign.GlifLayout>
|
||||
@@ -15,7 +15,7 @@
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<com.google.android.setupdesign.GlifLayout
|
||||
<com.android.settings.biometrics.fingerprint.UdfpsEnrollEnrollingView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
@@ -78,4 +78,4 @@
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.setupdesign.GlifLayout>
|
||||
</com.android.settings.biometrics.fingerprint.UdfpsEnrollEnrollingView>
|
||||
|
||||
@@ -1056,8 +1056,10 @@
|
||||
<string name="security_fingerprint_disclaimer_lockscreen_disabled_2">You can still use your fingerprint to authorize purchases and app access.</string>
|
||||
<!-- Text shown in fingerprint enroll when we didn't observe progress for a few seconds. [CHAR LIMIT=100] -->
|
||||
<string name="security_settings_fingerprint_enroll_lift_touch_again">Lift finger, then touch sensor again</string>
|
||||
<!-- Dialog title during fingerprint enrollment to indicate bad sensor calibration. [CHAR LIMIT=100] -->
|
||||
<string name="security_settings_fingerprint_bad_calibration_title">Can\u2019t use fingerprint sensor</string>
|
||||
<!-- Text shown during fingerprint enrollment to indicate bad sensor calibration. [CHAR LIMIT=100] -->
|
||||
<string name="security_settings_fingerprint_bad_calibration">Can\u2019t use fingerprint sensor. Visit a repair provider</string>
|
||||
<string name="security_settings_fingerprint_bad_calibration">Visit a repair provider.</string>
|
||||
<!-- Title for the section that has additional security settings. [CHAR LIMIT=60] -->
|
||||
<string name="security_advanced_settings">More security settings</string>
|
||||
<!-- String for the "More security settings" summary when a work profile is on the device. [CHAR_LIMIT=NONE] -->
|
||||
@@ -9702,12 +9704,6 @@
|
||||
<!-- [CHAR_LIMIT=60] Label for special access screen -->
|
||||
<string name="special_access">Special app access</string>
|
||||
|
||||
<!-- Summary for special access settings [CHAR_LIMIT=NONE] -->
|
||||
<plurals name="special_access_summary">
|
||||
<item quantity="one">1 app can use unrestricted data</item>
|
||||
<item quantity="other"><xliff:g id="count" example="10">%d</xliff:g> apps can use unrestricted data</item>
|
||||
</plurals>
|
||||
|
||||
<!-- Title for the See more preference item in Special app access settings [CHAR LIMIT=30] -->
|
||||
<string name="special_access_more">See more</string>
|
||||
|
||||
|
||||
@@ -227,9 +227,6 @@
|
||||
<item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Panel.Material" parent="Theme.Panel" >
|
||||
<item name="android:switchStyle">@style/Switch.SettingsLib</item>
|
||||
</style>
|
||||
<!-- Material theme for the pages containing TabLayout and ViewPager -->
|
||||
<style name="Theme.TabTheme" parent="@style/Theme.MaterialComponents.DayNight">
|
||||
<item name="colorPrimary">@*android:color/edge_effect_device_default_light</item>
|
||||
|
||||
@@ -105,7 +105,6 @@
|
||||
android:key="special_access"
|
||||
android:fragment="com.android.settings.applications.specialaccess.SpecialAccessSettings"
|
||||
android:title="@string/special_access"
|
||||
android:order="20"
|
||||
settings:controller="com.android.settings.applications.SpecialAppAccessPreferenceController"/>
|
||||
android:order="20"/>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
@@ -66,7 +66,6 @@ public class AppDashboardFragment extends DashboardFragment {
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
use(SpecialAppAccessPreferenceController.class).setSession(getSettingsLifecycle());
|
||||
mAppsPreferenceController = use(AppsPreferenceController.class);
|
||||
mAppsPreferenceController.setFragment(this /* fragment */);
|
||||
getSettingsLifecycle().addObserver(mAppsPreferenceController);
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the
|
||||
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the specific language governing
|
||||
* permissions and limitations under the License.
|
||||
*/
|
||||
package com.android.settings.applications;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settings.datausage.AppStateDataUsageBridge;
|
||||
import com.android.settings.datausage.AppStateDataUsageBridge.DataUsageState;
|
||||
import com.android.settings.datausage.DataSaverBackend;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||
import com.android.settingslib.core.lifecycle.events.OnDestroy;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStart;
|
||||
import com.android.settingslib.core.lifecycle.events.OnStop;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class SpecialAppAccessPreferenceController extends BasePreferenceController implements
|
||||
AppStateBaseBridge.Callback, ApplicationsState.Callbacks, LifecycleObserver, OnStart,
|
||||
OnStop, OnDestroy {
|
||||
|
||||
@VisibleForTesting
|
||||
ApplicationsState.Session mSession;
|
||||
|
||||
private final ApplicationsState mApplicationsState;
|
||||
private final AppStateDataUsageBridge mDataUsageBridge;
|
||||
private final DataSaverBackend mDataSaverBackend;
|
||||
|
||||
private Preference mPreference;
|
||||
private boolean mExtraLoaded;
|
||||
|
||||
|
||||
public SpecialAppAccessPreferenceController(Context context, String key) {
|
||||
super(context, key);
|
||||
mApplicationsState = ApplicationsState.getInstance(
|
||||
(Application) context.getApplicationContext());
|
||||
mDataSaverBackend = new DataSaverBackend(context);
|
||||
mDataUsageBridge = new AppStateDataUsageBridge(mApplicationsState, this, mDataSaverBackend);
|
||||
}
|
||||
|
||||
public void setSession(Lifecycle lifecycle) {
|
||||
mSession = mApplicationsState.newSession(this, lifecycle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
super.displayPreference(screen);
|
||||
mPreference = screen.findPreference(getPreferenceKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
mDataUsageBridge.resume(true /* forceLoadAllApps */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
mDataUsageBridge.pause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
mDataUsageBridge.release();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
updateSummary();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExtraInfoUpdated() {
|
||||
mExtraLoaded = true;
|
||||
updateSummary();
|
||||
}
|
||||
|
||||
private void updateSummary() {
|
||||
if (!mExtraLoaded || mPreference == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ArrayList<ApplicationsState.AppEntry> allApps = mSession.getAllApps();
|
||||
int count = 0;
|
||||
for (ApplicationsState.AppEntry entry : allApps) {
|
||||
if (!ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(entry)) {
|
||||
continue;
|
||||
}
|
||||
if (entry.extraInfo instanceof DataUsageState
|
||||
&& ((DataUsageState) entry.extraInfo).isDataSaverAllowlisted) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
mPreference.setSummary(mContext.getResources().getQuantityString(
|
||||
R.plurals.special_access_summary, count, count));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRunningStateChanged(boolean running) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageListChanged() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> apps) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageIconChanged() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageSizeChanged(String packageName) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAllSizesComputed() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLauncherInfoChanged() {
|
||||
// when the value of the AppEntry.hasLauncherEntry was changed.
|
||||
updateSummary();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadEntriesCompleted() {
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package com.android.settings.applications.specialaccess;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
|
||||
public class DataSaverController extends BasePreferenceController {
|
||||
|
||||
public DataSaverController(Context context, String key) {
|
||||
super(context, key);
|
||||
}
|
||||
|
||||
@AvailabilityStatus
|
||||
public int getAvailabilityStatus() {
|
||||
return mContext.getResources().getBoolean(R.bool.config_show_data_saver)
|
||||
? AVAILABLE : UNSUPPORTED_ON_DEVICE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.settings.applications.specialaccess
|
||||
|
||||
import android.content.Context
|
||||
import android.net.NetworkPolicyManager
|
||||
import android.os.UserHandle
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import com.android.settings.R
|
||||
import com.android.settings.core.BasePreferenceController
|
||||
import com.android.settingslib.spa.framework.util.formatString
|
||||
import com.android.settingslib.spaprivileged.model.app.AppListRepository
|
||||
import com.android.settingslib.spaprivileged.model.app.AppListRepositoryImpl
|
||||
import com.google.common.annotations.VisibleForTesting
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class DataSaverController(context: Context, key: String) : BasePreferenceController(context, key) {
|
||||
|
||||
private lateinit var preference: Preference
|
||||
|
||||
@AvailabilityStatus
|
||||
override fun getAvailabilityStatus(): Int = when {
|
||||
mContext.resources.getBoolean(R.bool.config_show_data_saver) -> AVAILABLE
|
||||
else -> UNSUPPORTED_ON_DEVICE
|
||||
}
|
||||
|
||||
override fun displayPreference(screen: PreferenceScreen) {
|
||||
super.displayPreference(screen)
|
||||
preference = screen.findPreference(preferenceKey)!!
|
||||
}
|
||||
|
||||
fun init(viewLifecycleOwner: LifecycleOwner) {
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
preference.summary = getUnrestrictedSummary(mContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@VisibleForTesting
|
||||
suspend fun getUnrestrictedSummary(
|
||||
context: Context,
|
||||
appListRepository: AppListRepository =
|
||||
AppListRepositoryImpl(context.applicationContext),
|
||||
) = context.formatString(
|
||||
R.string.data_saver_unrestricted_summary,
|
||||
"count" to getAllowCount(context.applicationContext, appListRepository),
|
||||
)
|
||||
|
||||
private suspend fun getAllowCount(context: Context, appListRepository: AppListRepository) =
|
||||
withContext(Dispatchers.IO) {
|
||||
coroutineScope {
|
||||
val appsDeferred = async {
|
||||
appListRepository.loadAndFilterApps(
|
||||
userId = UserHandle.myUserId(),
|
||||
isSystemApp = false,
|
||||
)
|
||||
}
|
||||
val uidsAllowed = NetworkPolicyManager.from(context)
|
||||
.getUidsWithPolicy(NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND)
|
||||
appsDeferred.await().count { app -> app.uid in uidsAllowed }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,10 @@ import static android.app.admin.DevicePolicyResources.Strings.Settings.MANAGE_DE
|
||||
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
@@ -46,6 +50,12 @@ public class SpecialAccessSettings extends DashboardFragment {
|
||||
MANAGE_DEVICE_ADMIN_APPS, R.string.manage_device_admin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
use(DataSaverController.class).init(getViewLifecycleOwner());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.special_access;
|
||||
|
||||
@@ -133,6 +133,7 @@ public abstract class BiometricEnrollBase extends InstrumentedActivity {
|
||||
protected long mChallenge;
|
||||
protected boolean mFromSettingsSummary;
|
||||
protected FooterBarMixin mFooterBarMixin;
|
||||
protected boolean mShouldSetFooterBarBackground = true;
|
||||
@Nullable
|
||||
protected ScreenSizeFoldProvider mScreenSizeFoldProvider;
|
||||
@Nullable
|
||||
@@ -191,6 +192,7 @@ public abstract class BiometricEnrollBase extends InstrumentedActivity {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
initViews();
|
||||
|
||||
if (mShouldSetFooterBarBackground) {
|
||||
@SuppressLint("VisibleForTests")
|
||||
final LinearLayout buttonContainer = mFooterBarMixin != null
|
||||
? mFooterBarMixin.getButtonContainer()
|
||||
@@ -199,6 +201,7 @@ public abstract class BiometricEnrollBase extends InstrumentedActivity {
|
||||
buttonContainer.setBackgroundColor(getBackgroundColor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToWindow() {
|
||||
@@ -331,7 +334,7 @@ public abstract class BiometricEnrollBase extends InstrumentedActivity {
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
private int getBackgroundColor() {
|
||||
public int getBackgroundColor() {
|
||||
final ColorStateList stateList = Utils.getColorAttr(this, android.R.attr.windowBackground);
|
||||
return stateList != null ? stateList.getDefaultColor() : Color.TRANSPARENT;
|
||||
}
|
||||
|
||||
@@ -32,10 +32,8 @@ import android.content.Intent;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Animatable2;
|
||||
import android.graphics.drawable.AnimatedVectorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
@@ -48,22 +46,16 @@ import android.os.VibrationAttributes;
|
||||
import android.os.VibrationEffect;
|
||||
import android.os.Vibrator;
|
||||
import android.text.TextUtils;
|
||||
import android.util.FeatureFlagUtils;
|
||||
import android.util.Log;
|
||||
import android.view.DisplayInfo;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.OrientationEventListener;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
@@ -79,25 +71,20 @@ import com.android.settings.biometrics.BiometricUtils;
|
||||
import com.android.settings.biometrics.BiometricsEnrollEnrolling;
|
||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
import com.android.settingslib.display.DisplayDensityUtils;
|
||||
import com.android.settingslib.udfps.UdfpsOverlayParams;
|
||||
import com.android.settingslib.udfps.UdfpsUtils;
|
||||
|
||||
import com.airbnb.lottie.LottieAnimationView;
|
||||
import com.airbnb.lottie.LottieCompositionFactory;
|
||||
import com.airbnb.lottie.LottieProperty;
|
||||
import com.airbnb.lottie.model.KeyPath;
|
||||
import com.google.android.setupcompat.template.FooterActionButton;
|
||||
import com.google.android.setupcompat.template.FooterBarMixin;
|
||||
import com.google.android.setupcompat.template.FooterButton;
|
||||
import com.google.android.setupcompat.util.WizardManagerHelper;
|
||||
import com.google.android.setupdesign.GlifLayout;
|
||||
import com.google.android.setupdesign.template.DescriptionMixin;
|
||||
import com.google.android.setupdesign.template.HeaderMixin;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Activity which handles the actual enrolling for fingerprint.
|
||||
@@ -176,8 +163,6 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
||||
@VisibleForTesting
|
||||
@Nullable
|
||||
UdfpsEnrollHelper mUdfpsEnrollHelper;
|
||||
// TODO(b/260617060): Do not hard-code mScaleFactor, referring to AuthController.
|
||||
private float mScaleFactor = 1.0f;
|
||||
private ObjectAnimator mProgressAnim;
|
||||
private TextView mErrorText;
|
||||
private Interpolator mFastOutSlowInInterpolator;
|
||||
@@ -206,7 +191,7 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
||||
private boolean mHaveShownSfpsLeftEdgeLottie;
|
||||
private boolean mHaveShownSfpsRightEdgeLottie;
|
||||
private boolean mShouldShowLottie;
|
||||
private UdfpsUtils mUdfpsUtils;
|
||||
|
||||
private ObjectAnimator mHelpAnimation;
|
||||
|
||||
private OrientationEventListener mOrientationEventListener;
|
||||
@@ -251,88 +236,17 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
||||
|
||||
mAccessibilityManager = getSystemService(AccessibilityManager.class);
|
||||
mIsAccessibilityEnabled = mAccessibilityManager.isEnabled();
|
||||
mUdfpsUtils = new UdfpsUtils();
|
||||
|
||||
final boolean isLayoutRtl = (TextUtils.getLayoutDirectionFromLocale(
|
||||
Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL);
|
||||
listenOrientationEvent();
|
||||
|
||||
if (mCanAssumeUdfps) {
|
||||
int rotation = getApplicationContext().getDisplay().getRotation();
|
||||
final GlifLayout layout = (GlifLayout) getLayoutInflater().inflate(
|
||||
final UdfpsEnrollEnrollingView layout =
|
||||
(UdfpsEnrollEnrollingView) getLayoutInflater().inflate(
|
||||
R.layout.udfps_enroll_enrolling, null, false);
|
||||
final UdfpsEnrollView udfpsEnrollView = layout.findViewById(R.id.udfps_animation_view);
|
||||
updateUdfpsEnrollView(udfpsEnrollView, props.get(0));
|
||||
switch (rotation) {
|
||||
case Surface.ROTATION_90:
|
||||
final View sudContent = layout.findViewById(R.id.sud_layout_content);
|
||||
if (sudContent != null) {
|
||||
sudContent.setPadding(sudContent.getPaddingLeft(), 0,
|
||||
sudContent.getPaddingRight(), sudContent.getPaddingBottom());
|
||||
}
|
||||
setUdfpsEnrollHelper();
|
||||
layout.initView(props.get(0), mUdfpsEnrollHelper, mAccessibilityManager);
|
||||
|
||||
final LinearLayout layoutContainer = layout.findViewById(
|
||||
R.id.layout_container);
|
||||
final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.MATCH_PARENT);
|
||||
|
||||
lp.setMarginEnd((int) getResources().getDimension(
|
||||
R.dimen.rotation_90_enroll_margin_end));
|
||||
layoutContainer.setPaddingRelative((int) getResources().getDimension(
|
||||
R.dimen.rotation_90_enroll_padding_start), 0, isLayoutRtl
|
||||
? 0 : (int) getResources().getDimension(
|
||||
R.dimen.rotation_90_enroll_padding_end), 0);
|
||||
layoutContainer.setLayoutParams(lp);
|
||||
|
||||
setOnHoverListener(true, layout, udfpsEnrollView);
|
||||
setContentView(layout, lp);
|
||||
break;
|
||||
|
||||
case Surface.ROTATION_0:
|
||||
case Surface.ROTATION_180:
|
||||
// In the portrait mode, layout_container's height is 0, so it's
|
||||
// always shown at the bottom of the screen.
|
||||
final FrameLayout portraitLayoutContainer = layout.findViewById(
|
||||
R.id.layout_container);
|
||||
|
||||
// In the portrait mode, the title and lottie animation view may
|
||||
// overlap when title needs three lines, so adding some paddings
|
||||
// between them, and adjusting the fp progress view here accordingly.
|
||||
final int layoutLottieAnimationPadding = (int) getResources()
|
||||
.getDimension(R.dimen.udfps_lottie_padding_top);
|
||||
portraitLayoutContainer.setPadding(0,
|
||||
layoutLottieAnimationPadding, 0, 0);
|
||||
final ImageView progressView = udfpsEnrollView.findViewById(
|
||||
R.id.udfps_enroll_animation_fp_progress_view);
|
||||
progressView.setPadding(0, -(layoutLottieAnimationPadding),
|
||||
0, layoutLottieAnimationPadding);
|
||||
final ImageView fingerprintView = udfpsEnrollView.findViewById(
|
||||
R.id.udfps_enroll_animation_fp_view);
|
||||
fingerprintView.setPadding(0, -layoutLottieAnimationPadding,
|
||||
0, layoutLottieAnimationPadding);
|
||||
|
||||
// TODO(b/260970216) Instead of hiding the description text view, we should
|
||||
// make the header view scrollable if the text is too long.
|
||||
// If description text view has overlap with udfps progress view, hide it.
|
||||
View view = layout.getDescriptionTextView();
|
||||
layout.getViewTreeObserver().addOnDrawListener(() -> {
|
||||
if (view.getVisibility() == View.VISIBLE
|
||||
&& hasOverlap(view, udfpsEnrollView)) {
|
||||
view.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
|
||||
setOnHoverListener(false, layout, udfpsEnrollView);
|
||||
setContentView(layout);
|
||||
break;
|
||||
|
||||
case Surface.ROTATION_270:
|
||||
default:
|
||||
setOnHoverListener(true, layout, udfpsEnrollView);
|
||||
setContentView(layout);
|
||||
break;
|
||||
}
|
||||
setDescriptionText(R.string.security_settings_udfps_enroll_start_message);
|
||||
} else if (mCanAssumeSfps) {
|
||||
setContentView(R.layout.sfps_enroll_enrolling);
|
||||
@@ -372,22 +286,11 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
||||
.build()
|
||||
);
|
||||
|
||||
if (FeatureFlagUtils.isEnabled(getApplicationContext(),
|
||||
FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS)) {
|
||||
// Remove the space view and make the width of footer button container WRAP_CONTENT
|
||||
// to avoid hiding the udfps view progress bar bottom.
|
||||
final LinearLayout buttonContainer = mFooterBarMixin.getButtonContainer();
|
||||
View spaceView = null;
|
||||
for (int i = 0; i < buttonContainer.getChildCount(); i++) {
|
||||
if (!(buttonContainer.getChildAt(i) instanceof FooterActionButton)) {
|
||||
spaceView = buttonContainer.getChildAt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (spaceView != null) {
|
||||
spaceView.setVisibility(View.GONE);
|
||||
buttonContainer.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
}
|
||||
// If it's udfps, set the background color only for secondary button if necessary.
|
||||
if (mCanAssumeUdfps) {
|
||||
mShouldSetFooterBarBackground = false;
|
||||
((UdfpsEnrollEnrollingView) getLayout()).setSecondaryButtonBackground(
|
||||
getBackgroundColor());
|
||||
}
|
||||
|
||||
final LayerDrawable fingerprintDrawable = mProgressBar != null
|
||||
@@ -1230,30 +1133,7 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
||||
}
|
||||
}
|
||||
|
||||
private UdfpsEnrollView updateUdfpsEnrollView(UdfpsEnrollView udfpsEnrollView,
|
||||
FingerprintSensorPropertiesInternal udfpsProps) {
|
||||
DisplayInfo displayInfo = new DisplayInfo();
|
||||
getDisplay().getDisplayInfo(displayInfo);
|
||||
mScaleFactor = mUdfpsUtils.getScaleFactor(displayInfo);
|
||||
Rect udfpsBounds = udfpsProps.getLocation().getRect();
|
||||
udfpsBounds.scale(mScaleFactor);
|
||||
|
||||
final Rect overlayBounds = new Rect(
|
||||
0, /* left */
|
||||
displayInfo.getNaturalHeight() / 2, /* top */
|
||||
displayInfo.getNaturalWidth(), /* right */
|
||||
displayInfo.getNaturalHeight() /* botom */);
|
||||
|
||||
UdfpsOverlayParams params = new UdfpsOverlayParams(
|
||||
udfpsBounds,
|
||||
overlayBounds,
|
||||
displayInfo.getNaturalWidth(),
|
||||
displayInfo.getNaturalHeight(),
|
||||
mScaleFactor,
|
||||
displayInfo.rotation);
|
||||
|
||||
udfpsEnrollView.setOverlayParams(params);
|
||||
|
||||
private void setUdfpsEnrollHelper() {
|
||||
mUdfpsEnrollHelper = (UdfpsEnrollHelper) getSupportFragmentManager().findFragmentByTag(
|
||||
FingerprintEnrollEnrolling.TAG_UDFPS_HELPER);
|
||||
if (mUdfpsEnrollHelper == null) {
|
||||
@@ -1263,57 +1143,6 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
||||
.add(mUdfpsEnrollHelper, FingerprintEnrollEnrolling.TAG_UDFPS_HELPER)
|
||||
.commitAllowingStateLoss();
|
||||
}
|
||||
udfpsEnrollView.setEnrollHelper(mUdfpsEnrollHelper);
|
||||
|
||||
return udfpsEnrollView;
|
||||
}
|
||||
|
||||
private void setOnHoverListener(boolean isLandscape, GlifLayout enrollLayout,
|
||||
UdfpsEnrollView udfpsEnrollView) {
|
||||
if (!mIsAccessibilityEnabled) return;
|
||||
|
||||
final Context context = getApplicationContext();
|
||||
final View.OnHoverListener onHoverListener = (v, event) -> {
|
||||
// Map the touch to portrait mode if the device is in
|
||||
// landscape mode.
|
||||
final Point scaledTouch =
|
||||
mUdfpsUtils.getTouchInNativeCoordinates(event.getPointerId(0),
|
||||
event, udfpsEnrollView.getOverlayParams());
|
||||
|
||||
if (mUdfpsUtils.isWithinSensorArea(event.getPointerId(0), event,
|
||||
udfpsEnrollView.getOverlayParams())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final String theStr = mUdfpsUtils.onTouchOutsideOfSensorArea(
|
||||
mAccessibilityManager.isTouchExplorationEnabled(), context,
|
||||
scaledTouch.x, scaledTouch.y, udfpsEnrollView.getOverlayParams());
|
||||
if (theStr != null) {
|
||||
v.announceForAccessibility(theStr);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
enrollLayout.findManagedViewById(isLandscape ? R.id.sud_landscape_content_area
|
||||
: R.id.sud_layout_content).setOnHoverListener(onHoverListener);
|
||||
}
|
||||
|
||||
|
||||
@VisibleForTesting boolean hasOverlap(View view1, View view2) {
|
||||
int[] firstPosition = new int[2];
|
||||
int[] secondPosition = new int[2];
|
||||
|
||||
view1.getLocationOnScreen(firstPosition);
|
||||
view2.getLocationOnScreen(secondPosition);
|
||||
|
||||
// Rect constructor parameters: left, top, right, bottom
|
||||
Rect rectView1 = new Rect(firstPosition[0], firstPosition[1],
|
||||
firstPosition[0] + view1.getMeasuredWidth(),
|
||||
firstPosition[1] + view1.getMeasuredHeight());
|
||||
Rect rectView2 = new Rect(secondPosition[0], secondPosition[1],
|
||||
secondPosition[0] + view2.getMeasuredWidth(),
|
||||
secondPosition[1] + view2.getMeasuredHeight());
|
||||
return rectView1.intersect(rectView2);
|
||||
}
|
||||
|
||||
public static class IconTouchDialog extends InstrumentedDialogFragment {
|
||||
|
||||
@@ -163,6 +163,8 @@ public class FingerprintErrorDialog extends InstrumentedDialogFragment {
|
||||
switch (errMsgId) {
|
||||
case FingerprintManager.FINGERPRINT_ERROR_TIMEOUT:
|
||||
return R.string.security_settings_fingerprint_enroll_error_dialog_title;
|
||||
case FingerprintManager.FINGERPRINT_ERROR_BAD_CALIBRATION:
|
||||
return R.string.security_settings_fingerprint_bad_calibration_title;
|
||||
default:
|
||||
return R.string
|
||||
.security_settings_fingerprint_enroll_error_unable_to_process_dialog_title;
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.settings.biometrics.fingerprint;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.DisplayInfo;
|
||||
import android.view.Gravity;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.settings.R;
|
||||
import com.android.settingslib.udfps.UdfpsOverlayParams;
|
||||
import com.android.settingslib.udfps.UdfpsUtils;
|
||||
|
||||
import com.google.android.setupcompat.template.FooterBarMixin;
|
||||
import com.google.android.setupdesign.GlifLayout;
|
||||
import com.google.android.setupdesign.view.BottomScrollView;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* View for udfps enrolling.
|
||||
*/
|
||||
public class UdfpsEnrollEnrollingView extends GlifLayout {
|
||||
private final UdfpsUtils mUdfpsUtils;
|
||||
private final Context mContext;
|
||||
// We don't need to listen to onConfigurationChanged() for mRotation here because
|
||||
// FingerprintEnrollEnrolling is always recreated once the configuration is changed.
|
||||
private final int mRotation;
|
||||
private final boolean mIsLandscape;
|
||||
private final boolean mShouldUseReverseLandscape;
|
||||
private UdfpsEnrollView mUdfpsEnrollView;
|
||||
private View mHeaderView;
|
||||
private AccessibilityManager mAccessibilityManager;
|
||||
|
||||
|
||||
public UdfpsEnrollEnrollingView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mContext = context;
|
||||
mRotation = mContext.getDisplay().getRotation();
|
||||
mIsLandscape = mRotation == Surface.ROTATION_90 || mRotation == Surface.ROTATION_270;
|
||||
final boolean isLayoutRtl = (TextUtils.getLayoutDirectionFromLocale(Locale.getDefault())
|
||||
== View.LAYOUT_DIRECTION_RTL);
|
||||
mShouldUseReverseLandscape = (mRotation == Surface.ROTATION_90 && isLayoutRtl)
|
||||
|| (mRotation == Surface.ROTATION_270 && !isLayoutRtl);
|
||||
|
||||
mUdfpsUtils = new UdfpsUtils();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mHeaderView = findViewById(R.id.sud_landscape_header_area);
|
||||
mUdfpsEnrollView = findViewById(R.id.udfps_animation_view);
|
||||
}
|
||||
|
||||
void initView(FingerprintSensorPropertiesInternal udfpsProps,
|
||||
UdfpsEnrollHelper udfpsEnrollHelper,
|
||||
AccessibilityManager accessibilityManager) {
|
||||
mAccessibilityManager = accessibilityManager;
|
||||
initUdfpsEnrollView(mUdfpsEnrollView, udfpsProps, udfpsEnrollHelper);
|
||||
|
||||
if (!mIsLandscape) {
|
||||
adjustPortraitPaddings();
|
||||
} else if (mShouldUseReverseLandscape) {
|
||||
swapHeaderAndContent();
|
||||
}
|
||||
setOnHoverListener();
|
||||
}
|
||||
|
||||
void setSecondaryButtonBackground(@ColorInt int color) {
|
||||
// Set the button background only when the button is not under udfps overlay to avoid UI
|
||||
// overlap.
|
||||
if (!mIsLandscape || mShouldUseReverseLandscape) {
|
||||
return;
|
||||
}
|
||||
final Button secondaryButtonView =
|
||||
getMixin(FooterBarMixin.class).getSecondaryButtonView();
|
||||
secondaryButtonView.setBackgroundColor(color);
|
||||
if (mRotation == Surface.ROTATION_90) {
|
||||
secondaryButtonView.setGravity(Gravity.START);
|
||||
} else {
|
||||
secondaryButtonView.setGravity(Gravity.END);
|
||||
}
|
||||
mHeaderView.post(() -> {
|
||||
secondaryButtonView.setLayoutParams(
|
||||
new LinearLayout.LayoutParams(mHeaderView.getMeasuredWidth(),
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
});
|
||||
}
|
||||
|
||||
private void initUdfpsEnrollView(UdfpsEnrollView udfpsEnrollView,
|
||||
FingerprintSensorPropertiesInternal udfpsProps,
|
||||
UdfpsEnrollHelper udfpsEnrollHelper) {
|
||||
DisplayInfo displayInfo = new DisplayInfo();
|
||||
mContext.getDisplay().getDisplayInfo(displayInfo);
|
||||
|
||||
final float scaleFactor = mUdfpsUtils.getScaleFactor(displayInfo);
|
||||
Rect udfpsBounds = udfpsProps.getLocation().getRect();
|
||||
udfpsBounds.scale(scaleFactor);
|
||||
|
||||
final Rect overlayBounds = new Rect(
|
||||
0, /* left */
|
||||
displayInfo.getNaturalHeight() / 2, /* top */
|
||||
displayInfo.getNaturalWidth(), /* right */
|
||||
displayInfo.getNaturalHeight() /* botom */);
|
||||
|
||||
UdfpsOverlayParams params = new UdfpsOverlayParams(
|
||||
udfpsBounds,
|
||||
overlayBounds,
|
||||
displayInfo.getNaturalWidth(),
|
||||
displayInfo.getNaturalHeight(),
|
||||
scaleFactor,
|
||||
displayInfo.rotation);
|
||||
|
||||
udfpsEnrollView.setOverlayParams(params);
|
||||
udfpsEnrollView.setEnrollHelper(udfpsEnrollHelper);
|
||||
}
|
||||
|
||||
private void adjustPortraitPaddings() {
|
||||
// In the portrait mode, layout_container's height is 0, so it's
|
||||
// always shown at the bottom of the screen.
|
||||
final FrameLayout portraitLayoutContainer = findViewById(R.id.layout_container);
|
||||
|
||||
// In the portrait mode, the title and lottie animation view may
|
||||
// overlap when title needs three lines, so adding some paddings
|
||||
// between them, and adjusting the fp progress view here accordingly.
|
||||
final int layoutLottieAnimationPadding = (int) getResources()
|
||||
.getDimension(R.dimen.udfps_lottie_padding_top);
|
||||
portraitLayoutContainer.setPadding(0,
|
||||
layoutLottieAnimationPadding, 0, 0);
|
||||
final ImageView progressView = mUdfpsEnrollView.findViewById(
|
||||
R.id.udfps_enroll_animation_fp_progress_view);
|
||||
progressView.setPadding(0, -(layoutLottieAnimationPadding),
|
||||
0, layoutLottieAnimationPadding);
|
||||
final ImageView fingerprintView = mUdfpsEnrollView.findViewById(
|
||||
R.id.udfps_enroll_animation_fp_view);
|
||||
fingerprintView.setPadding(0, -layoutLottieAnimationPadding,
|
||||
0, layoutLottieAnimationPadding);
|
||||
|
||||
// TODO(b/260970216) Instead of hiding the description text view, we should
|
||||
// make the header view scrollable if the text is too long.
|
||||
// If description text view has overlap with udfps progress view, hide it.
|
||||
final View descView = getDescriptionTextView();
|
||||
getViewTreeObserver().addOnDrawListener(() -> {
|
||||
if (descView.getVisibility() == View.VISIBLE
|
||||
&& hasOverlap(descView, mUdfpsEnrollView)) {
|
||||
descView.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setOnHoverListener() {
|
||||
if (!mAccessibilityManager.isEnabled()) return;
|
||||
|
||||
final View.OnHoverListener onHoverListener = (v, event) -> {
|
||||
// Map the touch to portrait mode if the device is in
|
||||
// landscape mode.
|
||||
final Point scaledTouch =
|
||||
mUdfpsUtils.getTouchInNativeCoordinates(event.getPointerId(0),
|
||||
event, mUdfpsEnrollView.getOverlayParams());
|
||||
|
||||
if (mUdfpsUtils.isWithinSensorArea(event.getPointerId(0), event,
|
||||
mUdfpsEnrollView.getOverlayParams())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final String theStr = mUdfpsUtils.onTouchOutsideOfSensorArea(
|
||||
mAccessibilityManager.isTouchExplorationEnabled(), mContext,
|
||||
scaledTouch.x, scaledTouch.y, mUdfpsEnrollView.getOverlayParams());
|
||||
if (theStr != null) {
|
||||
v.announceForAccessibility(theStr);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
findManagedViewById(mIsLandscape ? R.id.sud_landscape_content_area
|
||||
: R.id.sud_layout_content).setOnHoverListener(onHoverListener);
|
||||
}
|
||||
|
||||
private void swapHeaderAndContent() {
|
||||
// Reverse header and body
|
||||
ViewGroup parentView = (ViewGroup) mHeaderView.getParent();
|
||||
parentView.removeView(mHeaderView);
|
||||
parentView.addView(mHeaderView);
|
||||
|
||||
// Hide scroll indicators
|
||||
BottomScrollView headerScrollView = mHeaderView.findViewById(R.id.sud_header_scroll_view);
|
||||
headerScrollView.setScrollIndicators(0);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
boolean hasOverlap(View view1, View view2) {
|
||||
int[] firstPosition = new int[2];
|
||||
int[] secondPosition = new int[2];
|
||||
|
||||
view1.getLocationOnScreen(firstPosition);
|
||||
view2.getLocationOnScreen(secondPosition);
|
||||
|
||||
// Rect constructor parameters: left, top, right, bottom
|
||||
Rect rectView1 = new Rect(firstPosition[0], firstPosition[1],
|
||||
firstPosition[0] + view1.getMeasuredWidth(),
|
||||
firstPosition[1] + view1.getMeasuredHeight());
|
||||
Rect rectView2 = new Rect(secondPosition[0], secondPosition[1],
|
||||
secondPosition[0] + view2.getMeasuredWidth(),
|
||||
secondPosition[1] + view2.getMeasuredHeight());
|
||||
return rectView1.intersect(rectView2);
|
||||
}
|
||||
}
|
||||
@@ -17,34 +17,22 @@ package com.android.settings.datausage
|
||||
|
||||
import android.app.settings.SettingsEnums
|
||||
import android.content.Context
|
||||
import android.net.NetworkPolicyManager
|
||||
import android.os.Bundle
|
||||
import android.os.UserHandle
|
||||
import android.telephony.SubscriptionManager
|
||||
import android.view.View
|
||||
import android.widget.Switch
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.Preference
|
||||
import com.android.settings.R
|
||||
import com.android.settings.SettingsActivity
|
||||
import com.android.settings.SettingsPreferenceFragment
|
||||
import com.android.settings.applications.specialaccess.DataSaverController
|
||||
import com.android.settings.dashboard.DashboardFragment
|
||||
import com.android.settings.search.BaseSearchIndexProvider
|
||||
import com.android.settings.widget.SettingsMainSwitchBar
|
||||
import com.android.settingslib.search.SearchIndexable
|
||||
import com.android.settingslib.spa.framework.util.formatString
|
||||
import com.android.settingslib.spaprivileged.model.app.AppListRepository
|
||||
import com.android.settingslib.spaprivileged.model.app.AppListRepositoryImpl
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@SearchIndexable
|
||||
class DataSaverSummary : SettingsPreferenceFragment() {
|
||||
class DataSaverSummary : DashboardFragment() {
|
||||
private lateinit var switchBar: SettingsMainSwitchBar
|
||||
private lateinit var dataSaverBackend: DataSaverBackend
|
||||
private lateinit var unrestrictedAccess: Preference
|
||||
|
||||
// Flag used to avoid infinite loop due if user switch it on/off too quick.
|
||||
private var switching = false
|
||||
@@ -57,8 +45,6 @@ class DataSaverSummary : SettingsPreferenceFragment() {
|
||||
return
|
||||
}
|
||||
|
||||
addPreferencesFromResource(R.xml.data_saver)
|
||||
unrestrictedAccess = findPreference(KEY_UNRESTRICTED_ACCESS)!!
|
||||
dataSaverBackend = DataSaverBackend(requireContext())
|
||||
}
|
||||
|
||||
@@ -73,12 +59,14 @@ class DataSaverSummary : SettingsPreferenceFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
use(DataSaverController::class.java).init(viewLifecycleOwner)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
dataSaverBackend.addListener(dataSaverBackendListener)
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
unrestrictedAccess.summary = getUnrestrictedSummary(requireContext())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
@@ -95,9 +83,10 @@ class DataSaverSummary : SettingsPreferenceFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPreferenceScreenResId() = R.xml.data_saver
|
||||
override fun getMetricsCategory() = SettingsEnums.DATA_SAVER_SUMMARY
|
||||
|
||||
override fun getHelpResource() = R.string.help_url_data_saver
|
||||
override fun getLogTag() = TAG
|
||||
|
||||
private val dataSaverBackendListener = object : DataSaverBackend.Listener {
|
||||
override fun onDataSaverChanged(isDataSaving: Boolean) {
|
||||
@@ -109,32 +98,7 @@ class DataSaverSummary : SettingsPreferenceFragment() {
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val KEY_UNRESTRICTED_ACCESS = "unrestricted_access"
|
||||
|
||||
@VisibleForTesting
|
||||
suspend fun getUnrestrictedSummary(
|
||||
context: Context,
|
||||
appListRepository: AppListRepository =
|
||||
AppListRepositoryImpl(context.applicationContext),
|
||||
) = context.formatString(
|
||||
R.string.data_saver_unrestricted_summary,
|
||||
"count" to getAllowCount(context.applicationContext, appListRepository),
|
||||
)
|
||||
|
||||
private suspend fun getAllowCount(context: Context, appListRepository: AppListRepository) =
|
||||
withContext(Dispatchers.IO) {
|
||||
coroutineScope {
|
||||
val appsDeferred = async {
|
||||
appListRepository.loadAndFilterApps(
|
||||
userId = UserHandle.myUserId(),
|
||||
isSystemApp = false,
|
||||
)
|
||||
}
|
||||
val uidsAllowed = NetworkPolicyManager.from(context)
|
||||
.getUidsWithPolicy(NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND)
|
||||
appsDeferred.await().count { app -> app.uid in uidsAllowed }
|
||||
}
|
||||
}
|
||||
private const val TAG = "DataSaverSummary"
|
||||
|
||||
private fun Context.isDataSaverVisible(): Boolean =
|
||||
resources.getBoolean(R.bool.config_show_data_saver)
|
||||
|
||||
@@ -354,13 +354,18 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
|
||||
final NfcVerboseVendorLogPreferenceController nfcVerboseLogController =
|
||||
getDevelopmentOptionsController(
|
||||
NfcVerboseVendorLogPreferenceController.class);
|
||||
final GraphicsDriverEnableAngleAsSystemDriverController enableAngleController =
|
||||
getDevelopmentOptionsController(
|
||||
GraphicsDriverEnableAngleAsSystemDriverController.class);
|
||||
// If hardware offload isn't default value, we must reboot after disable
|
||||
// developer options. Show a dialog for the user to confirm.
|
||||
if ((a2dpController == null || a2dpController.isDefaultValue())
|
||||
&& (leAudioController == null || leAudioController.isDefaultValue())
|
||||
&& (nfcSnoopLogController == null || nfcSnoopLogController.isDefaultValue())
|
||||
&& (nfcVerboseLogController == null
|
||||
|| nfcVerboseLogController.isDefaultValue())) {
|
||||
|| nfcVerboseLogController.isDefaultValue())
|
||||
&& (enableAngleController == null
|
||||
|| enableAngleController.isDefaultValue())) {
|
||||
disableDeveloperOptions();
|
||||
} else {
|
||||
DisableDevSettingsDialogFragment.show(this /* host */);
|
||||
|
||||
@@ -45,6 +45,10 @@ public class DisableDevSettingsDialogFragment extends InstrumentedDialogFragment
|
||||
public static void show(DevelopmentSettingsDashboardFragment host) {
|
||||
final DisableDevSettingsDialogFragment dialog = new DisableDevSettingsDialogFragment();
|
||||
dialog.setTargetFragment(host, 0 /* requestCode */);
|
||||
// We need to handle data changes and switch state based on which button user clicks,
|
||||
// therefore we should enforce user to click one of the buttons
|
||||
// by disallowing dialog dismiss through tapping outside of dialog bounds.
|
||||
dialog.setCancelable(false);
|
||||
final FragmentManager manager = host.getActivity().getSupportFragmentManager();
|
||||
dialog.show(manager, TAG);
|
||||
}
|
||||
|
||||
@@ -81,6 +81,11 @@ public class GraphicsDriverEnableAngleAsSystemDriverController
|
||||
this(context, fragment, new Injector());
|
||||
}
|
||||
|
||||
private boolean isAngleSupported() {
|
||||
return TextUtils.equals(
|
||||
mSystemProperties.get(PROPERTY_RO_GFX_ANGLE_SUPPORTED, ""), "true");
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
GraphicsDriverEnableAngleAsSystemDriverController(
|
||||
Context context, DevelopmentSettingsDashboardFragment fragment, Injector injector) {
|
||||
@@ -118,38 +123,44 @@ public class GraphicsDriverEnableAngleAsSystemDriverController
|
||||
this);
|
||||
}
|
||||
|
||||
/** Return the default value of "persist.graphics.egl" */
|
||||
public boolean isDefaultValue() {
|
||||
if (!isAngleSupported()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final String currentGlesDriver =
|
||||
mSystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL, "");
|
||||
// default value of "persist.graphics.egl" is ""
|
||||
return TextUtils.isEmpty(currentGlesDriver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
super.updateState(preference);
|
||||
if (isAngleSupported()) {
|
||||
// set switch on if "persist.graphics.egl" is "angle" and angle is built in /vendor
|
||||
// set switch off otherwise.
|
||||
final String currentGlesDriver =
|
||||
mSystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL, "");
|
||||
final boolean isAngle = TextUtils.equals(ANGLE_DRIVER_SUFFIX, currentGlesDriver);
|
||||
final boolean isAngleSupported =
|
||||
TextUtils.equals(
|
||||
mSystemProperties.get(PROPERTY_RO_GFX_ANGLE_SUPPORTED, ""), "true");
|
||||
((SwitchPreference) mPreference).setChecked(isAngle && isAngleSupported);
|
||||
((SwitchPreference) mPreference).setEnabled(isAngleSupported);
|
||||
((SwitchPreference) mPreference).setChecked(isAngle);
|
||||
} else {
|
||||
mPreference.setEnabled(false);
|
||||
((SwitchPreference) mPreference).setChecked(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDeveloperOptionsSwitchEnabled() {
|
||||
// only enable the switch if ro.gfx.angle.supported is true
|
||||
// we use ro.gfx.angle.supported to indicate if ANGLE libs are installed under /vendor
|
||||
final boolean isAngleSupported =
|
||||
TextUtils.equals(
|
||||
mSystemProperties.get(PROPERTY_RO_GFX_ANGLE_SUPPORTED, ""), "true");
|
||||
((SwitchPreference) mPreference).setEnabled(isAngleSupported);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDeveloperOptionsSwitchDisabled() {
|
||||
// 1) set the persist.graphics.egl empty string
|
||||
// 1) disable the switch
|
||||
super.onDeveloperOptionsSwitchDisabled();
|
||||
if (isAngleSupported()) {
|
||||
// 2) set the persist.graphics.egl empty string
|
||||
GraphicsEnvironment.getInstance().toggleAngleAsSystemDriver(false);
|
||||
// 2) reset the switch
|
||||
// 3) reset the switch
|
||||
((SwitchPreference) mPreference).setChecked(false);
|
||||
// 3) disable switch
|
||||
((SwitchPreference) mPreference).setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void toggleSwitchBack() {
|
||||
|
||||
@@ -88,7 +88,7 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions
|
||||
private List<MobileNetworkInfoEntity> mMobileNetworkInfoEntityList = new ArrayList<>();
|
||||
private Context mContext;
|
||||
private AirplaneModeObserver mAirplaneModeObserver;
|
||||
private Uri mAirplaneModeSettingUri;
|
||||
private DataRoamingObserver mDataRoamingObserver;
|
||||
private MetricsFeatureProvider mMetricsFeatureProvider;
|
||||
private Map<Integer, MobileDataContentObserver> mDataContentObserverMap = new HashMap<>();
|
||||
private int mPhysicalSlotIndex = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
|
||||
@@ -127,10 +127,13 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions
|
||||
mUiccInfoDao = mMobileNetworkDatabase.mUiccInfoDao();
|
||||
mMobileNetworkInfoDao = mMobileNetworkDatabase.mMobileNetworkInfoDao();
|
||||
mAirplaneModeObserver = new AirplaneModeObserver(new Handler(Looper.getMainLooper()));
|
||||
mAirplaneModeSettingUri = Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON);
|
||||
mDataRoamingObserver = new DataRoamingObserver(new Handler(Looper.getMainLooper()));
|
||||
}
|
||||
|
||||
private class AirplaneModeObserver extends ContentObserver {
|
||||
private Uri mAirplaneModeSettingUri =
|
||||
Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON);
|
||||
|
||||
AirplaneModeObserver(Handler handler) {
|
||||
super(handler);
|
||||
}
|
||||
@@ -155,6 +158,46 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions
|
||||
}
|
||||
}
|
||||
|
||||
private class DataRoamingObserver extends ContentObserver {
|
||||
private int mRegSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||
private String mBaseField = Settings.Global.DATA_ROAMING;
|
||||
|
||||
DataRoamingObserver(Handler handler) {
|
||||
super(handler);
|
||||
}
|
||||
|
||||
public void register(Context context, int subId) {
|
||||
mRegSubId = subId;
|
||||
String lastField = mBaseField;
|
||||
createTelephonyManagerBySubId(subId);
|
||||
TelephonyManager tm = mTelephonyManagerMap.get(subId);
|
||||
if (tm.getSimCount() != 1) {
|
||||
lastField += subId;
|
||||
}
|
||||
context.getContentResolver().registerContentObserver(
|
||||
Settings.Global.getUriFor(lastField), false, this);
|
||||
}
|
||||
|
||||
public void unRegister(Context context) {
|
||||
context.getContentResolver().unregisterContentObserver(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
TelephonyManager tm = mTelephonyManagerMap.get(mRegSubId);
|
||||
if (tm == null) {
|
||||
return;
|
||||
}
|
||||
sExecutor.execute(() -> {
|
||||
insertMobileNetworkInfo(mContext, mRegSubId, tm);
|
||||
});
|
||||
boolean isDataRoamingEnabled = tm.isDataRoamingEnabled();
|
||||
for (MobileNetworkCallback callback : sCallbacks) {
|
||||
callback.onDataRoamingChanged(mRegSubId, isDataRoamingEnabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all callbacks and listener.
|
||||
*
|
||||
@@ -180,6 +223,7 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions
|
||||
if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
|
||||
addRegisterBySubId(subId);
|
||||
createTelephonyManagerBySubId(subId);
|
||||
mDataRoamingObserver.register(mContext, subId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,6 +295,7 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions
|
||||
if (sCallbacks.isEmpty()) {
|
||||
mSubscriptionManager.removeOnSubscriptionsChangedListener(this);
|
||||
mAirplaneModeObserver.unRegister(mContext);
|
||||
mDataRoamingObserver.unRegister(mContext);
|
||||
mDataContentObserverMap.forEach((id, observer) -> {
|
||||
observer.unRegister(mContext);
|
||||
});
|
||||
@@ -709,6 +754,12 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions
|
||||
default void onAirplaneModeChanged(boolean enabled) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify clients data roaming changed of subscription.
|
||||
*/
|
||||
default void onDataRoamingChanged(int subId, boolean enabled) {
|
||||
}
|
||||
|
||||
default void onCallStateChanged(int state) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ import com.android.settings.wifi.WifiPickerTrackerHelper;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.mobile.dataservice.MobileNetworkInfoEntity;
|
||||
import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity;
|
||||
import com.android.settingslib.mobile.dataservice.UiccInfoEntity;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
|
||||
@@ -441,8 +440,10 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings impleme
|
||||
/** suppress full page if user is not admin */
|
||||
@Override
|
||||
protected boolean isPageSearchEnabled(Context context) {
|
||||
return SubscriptionUtil.isSimHardwareVisible(context) &&
|
||||
context.getSystemService(UserManager.class).isAdminUser();
|
||||
boolean isAirplaneOff = Settings.Global.getInt(context.getContentResolver(),
|
||||
Settings.Global.AIRPLANE_MODE_ON, 0) == 0;
|
||||
return isAirplaneOff && SubscriptionUtil.isSimHardwareVisible(context)
|
||||
&& context.getSystemService(UserManager.class).isAdminUser();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.os.PersistableBundle;
|
||||
import android.telephony.CarrierConfigManager;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
@@ -34,6 +35,7 @@ import com.android.settings.network.telephony.TelephonyConstants.TelephonyManage
|
||||
*/
|
||||
public class PreferredNetworkModePreferenceController extends TelephonyBasePreferenceController
|
||||
implements ListPreference.OnPreferenceChangeListener {
|
||||
private static final String TAG = "PrefNetworkModeCtrl";
|
||||
|
||||
private CarrierConfigCache mCarrierConfigCache;
|
||||
private TelephonyManager mTelephonyManager;
|
||||
@@ -99,6 +101,10 @@ public class PreferredNetworkModePreferenceController extends TelephonyBasePrefe
|
||||
}
|
||||
|
||||
private int getPreferredNetworkMode() {
|
||||
if (mTelephonyManager == null) {
|
||||
Log.w(TAG, "TelephonyManager is null");
|
||||
return TelephonyManagerConstants.NETWORK_MODE_UNKNOWN;
|
||||
}
|
||||
return MobileNetworkUtils.getNetworkTypeFromRaf(
|
||||
(int) mTelephonyManager.getAllowedNetworkTypesForReason(
|
||||
TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER));
|
||||
|
||||
@@ -21,28 +21,23 @@ import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.PersistableBundle;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.CarrierConfigManager;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.lifecycle.LifecycleObserver;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.OnLifecycleEvent;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.network.GlobalSettingsChangeListener;
|
||||
import com.android.settings.network.MobileNetworkRepository;
|
||||
import com.android.settingslib.RestrictedSwitchPreference;
|
||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||
import com.android.settingslib.mobile.dataservice.MobileNetworkInfoEntity;
|
||||
import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity;
|
||||
import com.android.settingslib.mobile.dataservice.UiccInfoEntity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -52,7 +47,6 @@ import java.util.List;
|
||||
*/
|
||||
public class RoamingPreferenceController extends TelephonyTogglePreferenceController implements
|
||||
LifecycleObserver, MobileNetworkRepository.MobileNetworkCallback {
|
||||
|
||||
private static final String TAG = "RoamingController";
|
||||
private static final String DIALOG_TAG = "MobileDataDialog";
|
||||
|
||||
@@ -63,15 +57,6 @@ public class RoamingPreferenceController extends TelephonyTogglePreferenceContro
|
||||
protected LifecycleOwner mLifecycleOwner;
|
||||
private List<MobileNetworkInfoEntity> mMobileNetworkInfoEntityList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* There're 2 listeners both activated at the same time.
|
||||
* For project that access DATA_ROAMING, only first listener is functional.
|
||||
* For project that access "DATA_ROAMING + subId", first listener will be stopped when receiving
|
||||
* any onChange from second listener.
|
||||
*/
|
||||
private GlobalSettingsChangeListener mListener;
|
||||
private GlobalSettingsChangeListener mListenerForSubId;
|
||||
|
||||
@VisibleForTesting
|
||||
FragmentManager mFragmentManager;
|
||||
MobileNetworkInfoEntity mMobileNetworkInfoEntity;
|
||||
@@ -102,34 +87,11 @@ public class RoamingPreferenceController extends TelephonyTogglePreferenceContro
|
||||
public void onStart() {
|
||||
mMobileNetworkRepository.addRegister(mLifecycleOwner, this, mSubId);
|
||||
mMobileNetworkRepository.updateEntity();
|
||||
if (mListener == null) {
|
||||
mListener = new GlobalSettingsChangeListener(mContext,
|
||||
Settings.Global.DATA_ROAMING) {
|
||||
public void onChanged(String field) {
|
||||
updateState(mSwitchPreference);
|
||||
}
|
||||
};
|
||||
}
|
||||
stopMonitorSubIdSpecific();
|
||||
|
||||
if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
mListenerForSubId = new GlobalSettingsChangeListener(mContext,
|
||||
Settings.Global.DATA_ROAMING + mSubId) {
|
||||
public void onChanged(String field) {
|
||||
stopMonitor();
|
||||
updateState(mSwitchPreference);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(ON_STOP)
|
||||
public void onStop() {
|
||||
mMobileNetworkRepository.removeRegister(this);
|
||||
stopMonitor();
|
||||
stopMonitorSubIdSpecific();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -219,20 +181,6 @@ public class RoamingPreferenceController extends TelephonyTogglePreferenceContro
|
||||
dialogFragment.show(mFragmentManager, DIALOG_TAG);
|
||||
}
|
||||
|
||||
private void stopMonitor() {
|
||||
if (mListener != null) {
|
||||
mListener.close();
|
||||
mListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void stopMonitorSubIdSpecific() {
|
||||
if (mListenerForSubId != null) {
|
||||
mListenerForSubId.close();
|
||||
mListenerForSubId = null;
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void setMobileNetworkInfoEntity(MobileNetworkInfoEntity mobileNetworkInfoEntity) {
|
||||
mMobileNetworkInfoEntity = mobileNetworkInfoEntity;
|
||||
@@ -251,4 +199,13 @@ public class RoamingPreferenceController extends TelephonyTogglePreferenceContro
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataRoamingChanged(int subId, boolean enabled) {
|
||||
if (subId != mSubId) {
|
||||
Log.d(TAG, "onDataRoamingChanged - wrong subId : " + subId + " / " + enabled);
|
||||
return;
|
||||
}
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserManager;
|
||||
import android.print.PrintJob;
|
||||
import android.print.PrintJobId;
|
||||
import android.print.PrintJobInfo;
|
||||
@@ -45,6 +46,7 @@ import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.loader.app.LoaderManager.LoaderCallbacks;
|
||||
import androidx.loader.content.AsyncTaskLoader;
|
||||
import androidx.loader.content.Loader;
|
||||
@@ -92,6 +94,22 @@ public class PrintSettingsFragment extends ProfileSettingsPreferenceFragment
|
||||
private PrintServicesController mPrintServicesController;
|
||||
|
||||
private Button mAddNewServiceButton;
|
||||
@VisibleForTesting
|
||||
boolean mIsUiRestricted;
|
||||
|
||||
public PrintSettingsFragment() {
|
||||
super(UserManager.DISALLOW_PRINTING);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLogTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPreferenceScreenResId() {
|
||||
return R.xml.print_settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
@@ -107,12 +125,19 @@ public class PrintSettingsFragment extends ProfileSettingsPreferenceFragment
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View root = super.onCreateView(inflater, container, savedInstanceState);
|
||||
addPreferencesFromResource(R.xml.print_settings);
|
||||
mIsUiRestricted = isUiRestricted();
|
||||
setupPreferences();
|
||||
return root;
|
||||
}
|
||||
|
||||
mActivePrintJobsCategory = (PreferenceCategory) findPreference(
|
||||
PRINT_JOBS_CATEGORY);
|
||||
mPrintServicesCategory = (PreferenceCategory) findPreference(
|
||||
PRINT_SERVICES_CATEGORY);
|
||||
@VisibleForTesting
|
||||
void setupPreferences() {
|
||||
if (mIsUiRestricted) {
|
||||
return;
|
||||
}
|
||||
|
||||
mActivePrintJobsCategory = (PreferenceCategory) findPreference(PRINT_JOBS_CATEGORY);
|
||||
mPrintServicesCategory = (PreferenceCategory) findPreference(PRINT_SERVICES_CATEGORY);
|
||||
getPreferenceScreen().removePreference(mActivePrintJobsCategory);
|
||||
|
||||
mPrintJobsController = new PrintJobsController();
|
||||
@@ -120,20 +145,20 @@ public class PrintSettingsFragment extends ProfileSettingsPreferenceFragment
|
||||
|
||||
mPrintServicesController = new PrintServicesController();
|
||||
getLoaderManager().initLoader(LOADER_ID_PRINT_SERVICES, null, mPrintServicesController);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
setHasOptionsMenu(true);
|
||||
startSubSettingsIfNeeded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
setupEmptyViews();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setupEmptyViews() {
|
||||
if (mIsUiRestricted) {
|
||||
return;
|
||||
}
|
||||
|
||||
ViewGroup contentRoot = (ViewGroup) getListView().getParent();
|
||||
View emptyView = getActivity().getLayoutInflater().inflate(
|
||||
R.layout.empty_print_state, contentRoot, false);
|
||||
@@ -152,6 +177,23 @@ public class PrintSettingsFragment extends ProfileSettingsPreferenceFragment
|
||||
setEmptyView(emptyView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
startSettings();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void startSettings() {
|
||||
if (mIsUiRestricted) {
|
||||
getPreferenceScreen().removeAll();
|
||||
return;
|
||||
}
|
||||
|
||||
setHasOptionsMenu(true);
|
||||
startSubSettingsIfNeeded();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getIntentActionString() {
|
||||
return Settings.ACTION_PRINT_SETTINGS;
|
||||
|
||||
@@ -27,13 +27,17 @@ import android.widget.AdapterView;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.SettingsPreferenceFragment;
|
||||
import com.android.settings.dashboard.RestrictedDashboardFragment;
|
||||
import com.android.settings.dashboard.profileselector.UserAdapter;
|
||||
|
||||
/**
|
||||
* Base fragment class for per profile settings.
|
||||
*/
|
||||
public abstract class ProfileSettingsPreferenceFragment extends SettingsPreferenceFragment {
|
||||
public abstract class ProfileSettingsPreferenceFragment extends RestrictedDashboardFragment {
|
||||
|
||||
public ProfileSettingsPreferenceFragment(String restrictionKey) {
|
||||
super(restrictionKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
|
||||
@@ -84,8 +84,10 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
|
||||
WifiTetherSSIDPreferenceController mSSIDPreferenceController;
|
||||
@VisibleForTesting
|
||||
WifiTetherPasswordPreferenceController mPasswordPreferenceController;
|
||||
private WifiTetherSecurityPreferenceController mSecurityPreferenceController;
|
||||
private WifiTetherMaximizeCompatibilityPreferenceController mMaxCompatibilityPrefController;
|
||||
@VisibleForTesting
|
||||
WifiTetherSecurityPreferenceController mSecurityPreferenceController;
|
||||
@VisibleForTesting
|
||||
WifiTetherMaximizeCompatibilityPreferenceController mMaxCompatibilityPrefController;
|
||||
@VisibleForTesting
|
||||
WifiTetherAutoOffPreferenceController mWifiTetherAutoOffPreferenceController;
|
||||
|
||||
@@ -276,15 +278,16 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
|
||||
SoftApConfiguration buildNewConfig() {
|
||||
SoftApConfiguration currentConfig = mWifiTetherViewModel.getSoftApConfiguration();
|
||||
SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder(currentConfig);
|
||||
int securityType = (mWifiTetherViewModel.isSpeedFeatureAvailable())
|
||||
configBuilder.setSsid(mSSIDPreferenceController.getSSID());
|
||||
int securityType =
|
||||
mWifiTetherViewModel.isSpeedFeatureAvailable()
|
||||
? currentConfig.getSecurityType()
|
||||
: mSecurityPreferenceController.getSecurityType();
|
||||
configBuilder.setSsid(mSSIDPreferenceController.getSSID());
|
||||
if (securityType != SoftApConfiguration.SECURITY_TYPE_OPEN) {
|
||||
configBuilder.setPassphrase(
|
||||
mPasswordPreferenceController.getPasswordValidated(securityType),
|
||||
securityType);
|
||||
}
|
||||
String passphrase =
|
||||
securityType == SoftApConfiguration.SECURITY_TYPE_OPEN
|
||||
? null
|
||||
: mPasswordPreferenceController.getPasswordValidated(securityType);
|
||||
configBuilder.setPassphrase(passphrase, securityType);
|
||||
if (!mWifiTetherViewModel.isSpeedFeatureAvailable()) {
|
||||
mMaxCompatibilityPrefController.setupMaximizeCompatibility(configBuilder);
|
||||
}
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.applications;
|
||||
|
||||
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.anyInt;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ModuleInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.datausage.AppStateDataUsageBridge;
|
||||
import com.android.settings.testutils.shadow.ShadowApplicationsState;
|
||||
import com.android.settings.testutils.shadow.ShadowUserManager;
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {ShadowUserManager.class, ShadowApplicationsState.class})
|
||||
public class SpecialAppAccessPreferenceControllerTest {
|
||||
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private ApplicationsState.Session mSession;
|
||||
@Mock
|
||||
private PreferenceScreen mScreen;
|
||||
@Mock
|
||||
private PackageManager mPackageManager;
|
||||
|
||||
private SpecialAppAccessPreferenceController mController;
|
||||
private Preference mPreference;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
when(mContext.getApplicationContext()).thenReturn(mContext);
|
||||
ShadowUserManager.getShadow().setProfileIdsWithDisabled(new int[]{0});
|
||||
doReturn(mPackageManager).when(mContext).getPackageManager();
|
||||
doReturn(new ArrayList<ModuleInfo>()).when(mPackageManager).getInstalledModules(anyInt());
|
||||
mController = new SpecialAppAccessPreferenceController(mContext, "test_key");
|
||||
mPreference = new Preference(mContext);
|
||||
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
|
||||
|
||||
mController.mSession = mSession;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAvailabilityState_unsearchable() {
|
||||
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_shouldSetSummary() {
|
||||
final ArrayList<ApplicationsState.AppEntry> apps = new ArrayList<>();
|
||||
final ApplicationsState.AppEntry entry = mock(ApplicationsState.AppEntry.class);
|
||||
entry.hasLauncherEntry = true;
|
||||
entry.info = new ApplicationInfo();
|
||||
entry.extraInfo = new AppStateDataUsageBridge.DataUsageState(
|
||||
true /* allowlisted */, false /* denylisted */);
|
||||
apps.add(entry);
|
||||
when(mSession.getAllApps()).thenReturn(apps);
|
||||
|
||||
mController.displayPreference(mScreen);
|
||||
mController.onExtraInfoUpdated();
|
||||
|
||||
assertThat(mPreference.getSummary())
|
||||
.isEqualTo(mContext.getResources().getQuantityString(
|
||||
R.plurals.special_access_summary, 1, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateState_wrongExtraInfo_shouldNotIncludeInSummary() {
|
||||
final ArrayList<ApplicationsState.AppEntry> apps = new ArrayList<>();
|
||||
final ApplicationsState.AppEntry entry = mock(ApplicationsState.AppEntry.class);
|
||||
entry.hasLauncherEntry = true;
|
||||
entry.info = new ApplicationInfo();
|
||||
entry.extraInfo = new AppStateNotificationBridge.NotificationsSentState();
|
||||
apps.add(entry);
|
||||
when(mSession.getAllApps()).thenReturn(apps);
|
||||
|
||||
mController.displayPreference(mScreen);
|
||||
mController.onExtraInfoUpdated();
|
||||
|
||||
assertThat(mPreference.getSummary())
|
||||
.isEqualTo(mContext.getResources().getQuantityString(
|
||||
R.plurals.special_access_summary, 0, 0));
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.applications.specialaccess;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class DataSaverControllerTest {
|
||||
|
||||
private Context mContext;
|
||||
private Resources mResources;
|
||||
private DataSaverController mController;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = spy(RuntimeEnvironment.application.getApplicationContext());
|
||||
|
||||
mResources = spy(mContext.getResources());
|
||||
when(mContext.getResources()).thenReturn(mResources);
|
||||
|
||||
mController = new DataSaverController(mContext, "key");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataSaver_byDefault_shouldBeShown() {
|
||||
when(mResources.getBoolean(R.bool.config_show_data_saver)).thenReturn(true);
|
||||
assertThat(mController.isAvailable()).isTrue();
|
||||
}
|
||||
|
||||
@Ignore
|
||||
@Test
|
||||
@Config(qualifiers = "mcc999")
|
||||
public void testDataSaver_ifDisabledByCarrier_shouldNotBeShown() {
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataSaver_ifDisabled_shouldNotBeShown() {
|
||||
when(mResources.getBoolean(R.bool.config_show_data_saver)).thenReturn(false);
|
||||
assertThat(mController.isAvailable()).isFalse();
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,7 @@ import android.os.Vibrator;
|
||||
import android.view.Display;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
@@ -314,11 +315,17 @@ public class FingerprintEnrollEnrollingTest {
|
||||
@Test
|
||||
public void fingerprintUdfpsOverlayEnrollment_descriptionViewGoneWithOverlap() {
|
||||
initializeActivityWithoutCreate(TYPE_UDFPS_OPTICAL);
|
||||
doReturn(true).when(mActivity).hasOverlap(any(), any());
|
||||
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
|
||||
createActivity();
|
||||
|
||||
final GlifLayout defaultLayout = spy(mActivity.findViewById(R.id.setup_wizard_layout));
|
||||
final UdfpsEnrollEnrollingView defaultLayout = spy(
|
||||
mActivity.findViewById(R.id.setup_wizard_layout));
|
||||
doReturn(true).when(defaultLayout).hasOverlap(any(), any());
|
||||
|
||||
// Somehow spy doesn't work, and we need to call initView manually.
|
||||
defaultLayout.initView(mFingerprintManager.getSensorPropertiesInternal().get(0),
|
||||
mActivity.mUdfpsEnrollHelper,
|
||||
mActivity.getSystemService(AccessibilityManager.class));
|
||||
final TextView descriptionTextView = defaultLayout.getDescriptionTextView();
|
||||
|
||||
defaultLayout.getViewTreeObserver().dispatchOnDraw();
|
||||
@@ -328,11 +335,17 @@ public class FingerprintEnrollEnrollingTest {
|
||||
@Test
|
||||
public void fingerprintUdfpsOverlayEnrollment_descriptionViewVisibleWithoutOverlap() {
|
||||
initializeActivityWithoutCreate(TYPE_UDFPS_OPTICAL);
|
||||
doReturn(false).when(mActivity).hasOverlap(any(), any());
|
||||
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
|
||||
createActivity();
|
||||
|
||||
final GlifLayout defaultLayout = spy(mActivity.findViewById(R.id.setup_wizard_layout));
|
||||
final UdfpsEnrollEnrollingView defaultLayout = spy(
|
||||
mActivity.findViewById(R.id.setup_wizard_layout));
|
||||
doReturn(false).when(defaultLayout).hasOverlap(any(), any());
|
||||
|
||||
// Somehow spy doesn't work, and we need to call initView manually.
|
||||
defaultLayout.initView(mFingerprintManager.getSensorPropertiesInternal().get(0),
|
||||
mActivity.mUdfpsEnrollHelper,
|
||||
mActivity.getSystemService(AccessibilityManager.class));
|
||||
final TextView descriptionTextView = defaultLayout.getDescriptionTextView();
|
||||
|
||||
defaultLayout.getViewTreeObserver().dispatchOnDraw();
|
||||
@@ -578,7 +591,6 @@ public class FingerprintEnrollEnrollingTest {
|
||||
mContext = spy(RuntimeEnvironment.application);
|
||||
mActivity = spy(FingerprintEnrollEnrolling.class);
|
||||
|
||||
when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props);
|
||||
when(mContext.getDisplay()).thenReturn(mMockDisplay);
|
||||
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
|
||||
|
||||
|
||||
@@ -141,6 +141,7 @@ public class GraphicsDriverEnableAngleAsSystemDriverControllerTest {
|
||||
|
||||
@Test
|
||||
public void onDeveloperOptionSwitchDisabled_shouldDisableAngleAsSystemDriver() {
|
||||
ShadowSystemProperties.override(PROPERTY_RO_GFX_ANGLE_SUPPORTED, "true");
|
||||
mController.onDeveloperOptionsSwitchDisabled();
|
||||
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
|
||||
assertThat(systemEGLDriver).isEqualTo("");
|
||||
@@ -148,12 +149,14 @@ public class GraphicsDriverEnableAngleAsSystemDriverControllerTest {
|
||||
|
||||
@Test
|
||||
public void onDeveloperOptionSwitchDisabled_preferenceShouldNotBeChecked() {
|
||||
ShadowSystemProperties.override(PROPERTY_RO_GFX_ANGLE_SUPPORTED, "true");
|
||||
mController.onDeveloperOptionsSwitchDisabled();
|
||||
verify(mPreference).setChecked(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeveloperOptionsSwitchDisabled_preferenceShouldNotBeEnabled() {
|
||||
ShadowSystemProperties.override(PROPERTY_RO_GFX_ANGLE_SUPPORTED, "true");
|
||||
mController.onDeveloperOptionsSwitchDisabled();
|
||||
verify(mPreference).setEnabled(false);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.settings.wifi.tether;
|
||||
|
||||
import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_OPEN;
|
||||
import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE;
|
||||
import static android.view.View.INVISIBLE;
|
||||
import static android.view.View.VISIBLE;
|
||||
@@ -125,9 +126,13 @@ public class WifiTetherSettingsTest {
|
||||
@Mock
|
||||
private WifiTetherSSIDPreferenceController mSSIDPreferenceController;
|
||||
@Mock
|
||||
private WifiTetherSecurityPreferenceController mSecurityPreferenceController;
|
||||
@Mock
|
||||
private WifiTetherPasswordPreferenceController mPasswordPreferenceController;
|
||||
@Mock
|
||||
private WifiTetherAutoOffPreferenceController mWifiTetherAutoOffPreferenceController;
|
||||
@Mock
|
||||
private WifiTetherMaximizeCompatibilityPreferenceController mMaxCompatibilityPrefController;
|
||||
|
||||
private WifiTetherSettings mSettings;
|
||||
|
||||
@@ -156,10 +161,13 @@ public class WifiTetherSettingsTest {
|
||||
mSettings.mMainSwitchBar = mMainSwitchBar;
|
||||
mSettings.mSSIDPreferenceController = mSSIDPreferenceController;
|
||||
when(mSSIDPreferenceController.getSSID()).thenReturn(SSID);
|
||||
mSettings.mSecurityPreferenceController = mSecurityPreferenceController;
|
||||
when(mSecurityPreferenceController.getSecurityType()).thenReturn(SECURITY_TYPE_WPA3_SAE);
|
||||
mSettings.mPasswordPreferenceController = mPasswordPreferenceController;
|
||||
when(mPasswordPreferenceController.getPasswordValidated(anyInt())).thenReturn(PASSWORD);
|
||||
mSettings.mWifiTetherAutoOffPreferenceController = mWifiTetherAutoOffPreferenceController;
|
||||
when(mWifiTetherAutoOffPreferenceController.isEnabled()).thenReturn(true);
|
||||
mSettings.mMaxCompatibilityPrefController = mMaxCompatibilityPrefController;
|
||||
mSettings.mWifiTetherViewModel = mWifiTetherViewModel;
|
||||
when(mSettings.findPreference(KEY_WIFI_HOTSPOT_SECURITY)).thenReturn(mWifiHotspotSecurity);
|
||||
when(mSettings.findPreference(KEY_WIFI_HOTSPOT_SPEED)).thenReturn(mWifiHotspotSpeed);
|
||||
@@ -359,6 +367,23 @@ public class WifiTetherSettingsTest {
|
||||
assertThat(newConfig.getBand()).isEqualTo(currentConfig.getBand());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildNewConfig_securityTypeChangeToOpen_setSecurityTypeCorrectly() {
|
||||
SoftApConfiguration currentConfig = new SoftApConfiguration.Builder()
|
||||
.setPassphrase(PASSWORD, SECURITY_TYPE_WPA3_SAE)
|
||||
.setBand(BAND_2GHZ_5GHZ_6GHZ)
|
||||
.build();
|
||||
when(mWifiTetherViewModel.getSoftApConfiguration()).thenReturn(currentConfig);
|
||||
when(mWifiTetherViewModel.isSpeedFeatureAvailable()).thenReturn(false);
|
||||
doNothing().when(mMaxCompatibilityPrefController)
|
||||
.setupMaximizeCompatibility(any(SoftApConfiguration.Builder.class));
|
||||
|
||||
when(mSecurityPreferenceController.getSecurityType()).thenReturn(SECURITY_TYPE_OPEN);
|
||||
SoftApConfiguration newConfig = mSettings.buildNewConfig();
|
||||
|
||||
assertThat(newConfig.getSecurityType()).isEqualTo(SECURITY_TYPE_OPEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onRestartingChanged_restartingFalse_setLoadingFalse() {
|
||||
doNothing().when(mSettings).setLoading(anyBoolean(), anyBoolean());
|
||||
|
||||
@@ -14,15 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.settings.datausage
|
||||
package com.android.settings.applications.specialaccess
|
||||
|
||||
import android.content.Context
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.res.Resources
|
||||
import android.net.NetworkPolicyManager
|
||||
import android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.android.settings.datausage.DataSaverSummary.Companion.getUnrestrictedSummary
|
||||
import com.android.settings.R
|
||||
import com.android.settings.applications.specialaccess.DataSaverController.Companion.getUnrestrictedSummary
|
||||
import com.android.settings.core.BasePreferenceController.AVAILABLE
|
||||
import com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE
|
||||
import com.android.settingslib.spaprivileged.model.app.AppListRepository
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
@@ -41,20 +45,41 @@ import org.mockito.Mockito.`when` as whenever
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class DataSaverSummaryTest {
|
||||
class DataSaverControllerTest {
|
||||
@get:Rule
|
||||
val mockito: MockitoRule = MockitoJUnit.rule()
|
||||
|
||||
@Spy
|
||||
private val context: Context = ApplicationProvider.getApplicationContext()
|
||||
|
||||
@Spy
|
||||
private val resources: Resources = context.resources
|
||||
|
||||
@Mock
|
||||
private lateinit var networkPolicyManager: NetworkPolicyManager
|
||||
|
||||
@Mock
|
||||
private lateinit var dataSaverController: DataSaverController
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
whenever(context.applicationContext).thenReturn(context)
|
||||
whenever(context.resources).thenReturn(resources)
|
||||
whenever(NetworkPolicyManager.from(context)).thenReturn(networkPolicyManager)
|
||||
|
||||
dataSaverController = DataSaverController(context, "key")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getAvailabilityStatus_whenConfigOn_available() {
|
||||
whenever(resources.getBoolean(R.bool.config_show_data_saver)).thenReturn(true)
|
||||
assertThat(dataSaverController.availabilityStatus).isEqualTo(AVAILABLE)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getAvailabilityStatus_whenConfigOff_unsupportedOnDevice() {
|
||||
whenever(resources.getBoolean(R.bool.config_show_data_saver)).thenReturn(false)
|
||||
assertThat(dataSaverController.availabilityStatus).isEqualTo(UNSUPPORTED_ON_DEVICE)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -57,7 +57,7 @@ public class GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest {
|
||||
private GraphicsDriverEnableAngleAsSystemDriverController mController;
|
||||
|
||||
// Signal to wait for SystemProperty values changed
|
||||
private class PropertyChangeSignal {
|
||||
private static class PropertyChangeSignal {
|
||||
private CountDownLatch mCountDownLatch;
|
||||
|
||||
private Runnable mCountDownJob;
|
||||
@@ -217,23 +217,7 @@ public class GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeveloperOptionSwitchEnabled_angleSupported_PreferenceShouldEnabled() {
|
||||
when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
|
||||
.thenReturn("true");
|
||||
mController.onDeveloperOptionsSwitchEnabled();
|
||||
assertThat(mPreference.isEnabled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeveloperOptionSwitchEnabled_angleNotSupported_PrefenceShouldDisabled() {
|
||||
when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
|
||||
.thenReturn("false");
|
||||
mController.onDeveloperOptionsSwitchEnabled();
|
||||
assertThat(mPreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeveloperOptionSwitchDisabled_angleIsNotSystemGLESDriver() {
|
||||
public void onDeveloperOptionSwitchDisabled_angleShouldNotBeSystemGLESDriver() {
|
||||
// Add a callback when SystemProperty changes.
|
||||
// This allows the thread to wait until
|
||||
// GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
|
||||
@@ -242,6 +226,8 @@ public class GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest {
|
||||
|
||||
// Test that onDeveloperOptionSwitchDisabled,
|
||||
// persist.graphics.egl updates to ""
|
||||
when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
|
||||
.thenReturn("true");
|
||||
mController.onDeveloperOptionsSwitchDisabled();
|
||||
propertyChangeSignal1.wait(100);
|
||||
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
|
||||
@@ -253,12 +239,16 @@ public class GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest {
|
||||
|
||||
@Test
|
||||
public void onDeveloperOptionSwitchDisabled_PreferenceShouldNotBeChecked() {
|
||||
when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
|
||||
.thenReturn("true");
|
||||
mController.onDeveloperOptionsSwitchDisabled();
|
||||
assertThat(mPreference.isChecked()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onDeveloperOptionSwitchDisabled_PreferenceShouldDisabled() {
|
||||
when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
|
||||
.thenReturn("true");
|
||||
mController.onDeveloperOptionsSwitchDisabled();
|
||||
assertThat(mPreference.isEnabled()).isFalse();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.settings.print;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Looper;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class PrintSettingsFragmentTest {
|
||||
@Rule
|
||||
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
|
||||
@Spy
|
||||
private final Context mContext = ApplicationProvider.getApplicationContext();
|
||||
|
||||
private PrintSettingsFragment mFragment;
|
||||
private PreferenceManager mPreferenceManager;
|
||||
private PreferenceScreen mPreferenceScreen;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
if (Looper.myLooper() == null) {
|
||||
Looper.prepare();
|
||||
}
|
||||
mPreferenceManager = new PreferenceManager(mContext);
|
||||
mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext);
|
||||
|
||||
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
|
||||
mFragment = spy(new PrintSettingsFragment());
|
||||
doReturn(mPreferenceScreen).when(mFragment).getPreferenceScreen();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setupPreferences_uiIsRestricted_doNotAddPreferences() {
|
||||
mFragment.mIsUiRestricted = true;
|
||||
|
||||
mFragment.setupPreferences();
|
||||
|
||||
verify(mFragment, never()).findPreference(any(CharSequence.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setupEmptyViews_uiIsRestricted_doNotSetEmptyView() {
|
||||
mFragment.mIsUiRestricted = true;
|
||||
|
||||
mFragment.setupEmptyViews();
|
||||
|
||||
verify(mFragment, never()).setEmptyView(any(View.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void startSettings_uiIsRestricted_removeAllPreferences() {
|
||||
mFragment.mIsUiRestricted = true;
|
||||
|
||||
mFragment.startSettings();
|
||||
|
||||
assertThat(mPreferenceScreen.getPreferenceCount()).isEqualTo(0);
|
||||
verify(mFragment, never()).setHasOptionsMenu(true);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user