Loading AndroidManifest.xml +1 −1 Original line number Diff line number Diff line Loading @@ -436,7 +436,7 @@ android:exported="true" android:permission="android.permission.TETHER_PRIVILEGED" /> <activity android:name="TetherProvisioningActivity" <activity android:name="network.TetherProvisioningActivity" android:exported="true" android:permission="android.permission.TETHER_PRIVILEGED" android:excludeFromRecents="true" Loading src/com/android/settings/Utils.java +10 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,7 @@ import android.provider.Settings; import androidx.annotation.StringRes; import androidx.preference.Preference; import androidx.preference.PreferenceGroup; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.Spannable; import android.text.SpannableString; Loading Loading @@ -966,4 +967,13 @@ public final class Utils extends com.android.settingslib.Utils { return packageManager.getDefaultActivityIcon(); } } /** Get {@link Resources} by subscription id if subscription id is valid. */ public static Resources getResourcesForSubId(Context context, int subId) { if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { return SubscriptionManager.getResourcesForSubId(context, subId); } else { return context.getResources(); } } } src/com/android/settings/TetherProvisioningActivity.java→src/com/android/settings/network/TetherProvisioningActivity.java +8 −2 Original line number Diff line number Diff line Loading @@ -14,17 +14,21 @@ * limitations under the License. */ package com.android.settings; package com.android.settings.network; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; import android.net.ConnectivityManager; import android.os.Bundle; import android.os.ResultReceiver; import android.os.UserHandle; import android.telephony.SubscriptionManager; import android.util.Log; import com.android.settings.Utils; /** * Activity which acts as a proxy to the tether provisioning app for sanity checks and permission * restrictions. Specifically, the provisioning apps require Loading @@ -47,7 +51,9 @@ public class TetherProvisioningActivity extends Activity { int tetherType = getIntent().getIntExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, ConnectivityManager.TETHERING_INVALID); String[] provisionApp = getResources().getStringArray( final int subId = SubscriptionManager.getDefaultDataSubscriptionId(); final Resources res = Utils.getResourcesForSubId(this, subId); final String[] provisionApp = res.getStringArray( com.android.internal.R.array.config_mobile_hotspot_provision_app); Intent intent = new Intent(Intent.ACTION_MAIN); Loading src/com/android/settings/wifi/tether/TetherService.java +34 −15 Original line number Diff line number Diff line Loading @@ -32,16 +32,20 @@ import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.net.ConnectivityManager; import android.os.IBinder; import android.os.ResultReceiver; import android.os.SystemClock; import android.telephony.SubscriptionManager; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.Utils; import java.util.ArrayList; import java.util.List; Loading @@ -65,7 +69,7 @@ public class TetherService extends Service { private int mCurrentTypeIndex; private boolean mInProvisionCheck; private UsageStatsManagerWrapper mUsageManagerWrapper; private TetherServiceWrapper mWrapper; private ArrayList<Integer> mCurrentTethers; private ArrayMap<Integer, List<ResultReceiver>> mPendingCallbacks; private HotspotOffReceiver mHotspotReceiver; Loading @@ -79,7 +83,7 @@ public class TetherService extends Service { public void onCreate() { super.onCreate(); if (DEBUG) Log.d(TAG, "Creating TetherService"); String provisionResponse = getResources().getString( String provisionResponse = getResourceForDefaultDataSubId().getString( com.android.internal.R.string.config_mobile_hotspot_provision_response); registerReceiver(mReceiver, new IntentFilter(provisionResponse), android.Manifest.permission.CONNECTIVITY_INTERNAL, null); Loading @@ -91,9 +95,6 @@ public class TetherService extends Service { mPendingCallbacks.put(ConnectivityManager.TETHERING_USB, new ArrayList<ResultReceiver>()); mPendingCallbacks.put( ConnectivityManager.TETHERING_BLUETOOTH, new ArrayList<ResultReceiver>()); if (mUsageManagerWrapper == null) { mUsageManagerWrapper = new UsageStatsManagerWrapper(this); } mHotspotReceiver = new HotspotOffReceiver(this); } Loading Loading @@ -258,7 +259,7 @@ public class TetherService extends Service { } private Intent getProvisionBroadcastIntent(int index) { String provisionAction = getResources().getString( String provisionAction = getResourceForDefaultDataSubId().getString( com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui); Intent intent = new Intent(provisionAction); int type = mCurrentTethers.get(index); Loading @@ -282,7 +283,7 @@ public class TetherService extends Service { for (ResolveInfo resolver : resolvers) { if (resolver.activityInfo.applicationInfo.isSystemApp()) { String packageName = resolver.activityInfo.packageName; mUsageManagerWrapper.setAppInactive(packageName, false); getTetherServiceWrapper().setAppInactive(packageName, false); } } } Loading @@ -294,7 +295,7 @@ public class TetherService extends Service { PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0); AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); int period = getResources().getInteger( int period = getResourceForDefaultDataSubId().getInteger( com.android.internal.R.integer.config_mobile_hotspot_provision_check_period); long periodMs = period * MS_PER_HOUR; long firstTime = SystemClock.elapsedRealtime() + periodMs; Loading Loading @@ -347,7 +348,7 @@ public class TetherService extends Service { @Override public void onReceive(Context context, Intent intent) { if (DEBUG) Log.d(TAG, "Got provision result " + intent); String provisionResponse = getResources().getString( String provisionResponse = getResourceForDefaultDataSubId().getString( com.android.internal.R.string.config_mobile_hotspot_provision_response); if (provisionResponse.equals(intent.getAction())) { Loading Loading @@ -385,19 +386,27 @@ public class TetherService extends Service { }; @VisibleForTesting void setUsageStatsManagerWrapper(UsageStatsManagerWrapper wrapper) { mUsageManagerWrapper = wrapper; void setTetherServiceWrapper(TetherServiceWrapper wrapper) { mWrapper = wrapper; } private TetherServiceWrapper getTetherServiceWrapper() { if (mWrapper == null) { mWrapper = new TetherServiceWrapper(this); } return mWrapper; } /** * A static helper class used for tests. UsageStatsManager cannot be mocked out becasue * it's marked final. This class can be mocked out instead. * A static helper class used for tests. UsageStatsManager cannot be mocked out because * it's marked final. Static method SubscriptionManager#getResourcesForSubId also cannot * be mocked. This class can be mocked out instead. */ @VisibleForTesting public static class UsageStatsManagerWrapper { public static class TetherServiceWrapper { private final UsageStatsManager mUsageStatsManager; UsageStatsManagerWrapper(Context context) { TetherServiceWrapper(Context context) { mUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE); } Loading @@ -405,5 +414,15 @@ public class TetherService extends Service { void setAppInactive(String packageName, boolean isInactive) { mUsageStatsManager.setAppInactive(packageName, isInactive); } int getDefaultDataSubscriptionId() { return SubscriptionManager.getDefaultDataSubscriptionId(); } } @VisibleForTesting Resources getResourceForDefaultDataSubId() { final int subId = getTetherServiceWrapper().getDefaultDataSubscriptionId(); return Utils.getResourcesForSubId(this, subId); } } tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java +15 −10 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import static android.net.ConnectivityManager.TETHERING_USB; import static android.net.ConnectivityManager.TETHERING_WIFI; import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import android.app.Activity; import android.app.AlarmManager; Loading Loading @@ -82,7 +83,7 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> { private TetherService mService; private MockResources mResources; private FakeUsageStatsManagerWrapper mUsageStatsManagerWrapper; private MockTetherServiceWrapper mWrapper; int mLastReceiverResultCode = BOGUS_RECEIVER_RESULT; private int mLastTetherRequestType = TETHERING_INVALID; private int mProvisionResponse = BOGUS_RECEIVER_RESULT; Loading Loading @@ -124,7 +125,7 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> { when(mPrefs.edit()).thenReturn(mPrefEditor); when(mPrefEditor.putString(eq(CURRENT_TYPES), mStoredTypes.capture())).thenReturn( mPrefEditor); mUsageStatsManagerWrapper = new FakeUsageStatsManagerWrapper(mContext); mWrapper = new MockTetherServiceWrapper(mContext); ResolveInfo systemAppResolveInfo = new ResolveInfo(); ActivityInfo systemActivityInfo = new ActivityInfo(); Loading @@ -145,6 +146,8 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> { resolvers.add(systemAppResolveInfo); when(mPackageManager.queryBroadcastReceivers( any(Intent.class), eq(PackageManager.MATCH_ALL))).thenReturn(resolvers); setupService(); getService().setTetherServiceWrapper(mWrapper); } @Override Loading @@ -170,16 +173,13 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> { } public void testStartKeepsProvisionAppActive() { setupService(); getService().setUsageStatsManagerWrapper(mUsageStatsManagerWrapper); runProvisioningForType(TETHERING_WIFI); assertTrue(waitForProvisionRequest(TETHERING_WIFI)); assertTrue(waitForProvisionResponse(TETHER_ERROR_NO_ERROR)); assertFalse(mUsageStatsManagerWrapper.isAppInactive(ENTITLEMENT_PACKAGE_NAME)); assertFalse(mWrapper.isAppInactive(ENTITLEMENT_PACKAGE_NAME)); // Non-system handler of the intent action should stay idle. assertTrue(mUsageStatsManagerWrapper.isAppInactive(FAKE_PACKAGE_NAME)); assertTrue(mWrapper.isAppInactive(FAKE_PACKAGE_NAME)); } public void testScheduleRechecks() { Loading Loading @@ -418,11 +418,11 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> { } } private static class FakeUsageStatsManagerWrapper extends TetherService.UsageStatsManagerWrapper { private static class MockTetherServiceWrapper extends TetherService.TetherServiceWrapper { private final Set<String> mActivePackages; FakeUsageStatsManagerWrapper(Context context) { MockTetherServiceWrapper(Context context) { super(context); mActivePackages = new HashSet<>(); } Loading @@ -439,5 +439,10 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> { boolean isAppInactive(String packageName) { return !mActivePackages.contains(packageName); } @Override int getDefaultDataSubscriptionId() { return INVALID_SUBSCRIPTION_ID; } } } Loading
AndroidManifest.xml +1 −1 Original line number Diff line number Diff line Loading @@ -436,7 +436,7 @@ android:exported="true" android:permission="android.permission.TETHER_PRIVILEGED" /> <activity android:name="TetherProvisioningActivity" <activity android:name="network.TetherProvisioningActivity" android:exported="true" android:permission="android.permission.TETHER_PRIVILEGED" android:excludeFromRecents="true" Loading
src/com/android/settings/Utils.java +10 −0 Original line number Diff line number Diff line Loading @@ -74,6 +74,7 @@ import android.provider.Settings; import androidx.annotation.StringRes; import androidx.preference.Preference; import androidx.preference.PreferenceGroup; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.Spannable; import android.text.SpannableString; Loading Loading @@ -966,4 +967,13 @@ public final class Utils extends com.android.settingslib.Utils { return packageManager.getDefaultActivityIcon(); } } /** Get {@link Resources} by subscription id if subscription id is valid. */ public static Resources getResourcesForSubId(Context context, int subId) { if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { return SubscriptionManager.getResourcesForSubId(context, subId); } else { return context.getResources(); } } }
src/com/android/settings/TetherProvisioningActivity.java→src/com/android/settings/network/TetherProvisioningActivity.java +8 −2 Original line number Diff line number Diff line Loading @@ -14,17 +14,21 @@ * limitations under the License. */ package com.android.settings; package com.android.settings.network; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; import android.net.ConnectivityManager; import android.os.Bundle; import android.os.ResultReceiver; import android.os.UserHandle; import android.telephony.SubscriptionManager; import android.util.Log; import com.android.settings.Utils; /** * Activity which acts as a proxy to the tether provisioning app for sanity checks and permission * restrictions. Specifically, the provisioning apps require Loading @@ -47,7 +51,9 @@ public class TetherProvisioningActivity extends Activity { int tetherType = getIntent().getIntExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, ConnectivityManager.TETHERING_INVALID); String[] provisionApp = getResources().getStringArray( final int subId = SubscriptionManager.getDefaultDataSubscriptionId(); final Resources res = Utils.getResourcesForSubId(this, subId); final String[] provisionApp = res.getStringArray( com.android.internal.R.array.config_mobile_hotspot_provision_app); Intent intent = new Intent(Intent.ACTION_MAIN); Loading
src/com/android/settings/wifi/tether/TetherService.java +34 −15 Original line number Diff line number Diff line Loading @@ -32,16 +32,20 @@ import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.net.ConnectivityManager; import android.os.IBinder; import android.os.ResultReceiver; import android.os.SystemClock; import android.telephony.SubscriptionManager; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.Utils; import java.util.ArrayList; import java.util.List; Loading @@ -65,7 +69,7 @@ public class TetherService extends Service { private int mCurrentTypeIndex; private boolean mInProvisionCheck; private UsageStatsManagerWrapper mUsageManagerWrapper; private TetherServiceWrapper mWrapper; private ArrayList<Integer> mCurrentTethers; private ArrayMap<Integer, List<ResultReceiver>> mPendingCallbacks; private HotspotOffReceiver mHotspotReceiver; Loading @@ -79,7 +83,7 @@ public class TetherService extends Service { public void onCreate() { super.onCreate(); if (DEBUG) Log.d(TAG, "Creating TetherService"); String provisionResponse = getResources().getString( String provisionResponse = getResourceForDefaultDataSubId().getString( com.android.internal.R.string.config_mobile_hotspot_provision_response); registerReceiver(mReceiver, new IntentFilter(provisionResponse), android.Manifest.permission.CONNECTIVITY_INTERNAL, null); Loading @@ -91,9 +95,6 @@ public class TetherService extends Service { mPendingCallbacks.put(ConnectivityManager.TETHERING_USB, new ArrayList<ResultReceiver>()); mPendingCallbacks.put( ConnectivityManager.TETHERING_BLUETOOTH, new ArrayList<ResultReceiver>()); if (mUsageManagerWrapper == null) { mUsageManagerWrapper = new UsageStatsManagerWrapper(this); } mHotspotReceiver = new HotspotOffReceiver(this); } Loading Loading @@ -258,7 +259,7 @@ public class TetherService extends Service { } private Intent getProvisionBroadcastIntent(int index) { String provisionAction = getResources().getString( String provisionAction = getResourceForDefaultDataSubId().getString( com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui); Intent intent = new Intent(provisionAction); int type = mCurrentTethers.get(index); Loading @@ -282,7 +283,7 @@ public class TetherService extends Service { for (ResolveInfo resolver : resolvers) { if (resolver.activityInfo.applicationInfo.isSystemApp()) { String packageName = resolver.activityInfo.packageName; mUsageManagerWrapper.setAppInactive(packageName, false); getTetherServiceWrapper().setAppInactive(packageName, false); } } } Loading @@ -294,7 +295,7 @@ public class TetherService extends Service { PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0); AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); int period = getResources().getInteger( int period = getResourceForDefaultDataSubId().getInteger( com.android.internal.R.integer.config_mobile_hotspot_provision_check_period); long periodMs = period * MS_PER_HOUR; long firstTime = SystemClock.elapsedRealtime() + periodMs; Loading Loading @@ -347,7 +348,7 @@ public class TetherService extends Service { @Override public void onReceive(Context context, Intent intent) { if (DEBUG) Log.d(TAG, "Got provision result " + intent); String provisionResponse = getResources().getString( String provisionResponse = getResourceForDefaultDataSubId().getString( com.android.internal.R.string.config_mobile_hotspot_provision_response); if (provisionResponse.equals(intent.getAction())) { Loading Loading @@ -385,19 +386,27 @@ public class TetherService extends Service { }; @VisibleForTesting void setUsageStatsManagerWrapper(UsageStatsManagerWrapper wrapper) { mUsageManagerWrapper = wrapper; void setTetherServiceWrapper(TetherServiceWrapper wrapper) { mWrapper = wrapper; } private TetherServiceWrapper getTetherServiceWrapper() { if (mWrapper == null) { mWrapper = new TetherServiceWrapper(this); } return mWrapper; } /** * A static helper class used for tests. UsageStatsManager cannot be mocked out becasue * it's marked final. This class can be mocked out instead. * A static helper class used for tests. UsageStatsManager cannot be mocked out because * it's marked final. Static method SubscriptionManager#getResourcesForSubId also cannot * be mocked. This class can be mocked out instead. */ @VisibleForTesting public static class UsageStatsManagerWrapper { public static class TetherServiceWrapper { private final UsageStatsManager mUsageStatsManager; UsageStatsManagerWrapper(Context context) { TetherServiceWrapper(Context context) { mUsageStatsManager = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE); } Loading @@ -405,5 +414,15 @@ public class TetherService extends Service { void setAppInactive(String packageName, boolean isInactive) { mUsageStatsManager.setAppInactive(packageName, isInactive); } int getDefaultDataSubscriptionId() { return SubscriptionManager.getDefaultDataSubscriptionId(); } } @VisibleForTesting Resources getResourceForDefaultDataSubId() { final int subId = getTetherServiceWrapper().getDefaultDataSubscriptionId(); return Utils.getResourcesForSubId(this, subId); } }
tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java +15 −10 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import static android.net.ConnectivityManager.TETHERING_USB; import static android.net.ConnectivityManager.TETHERING_WIFI; import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR; import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import android.app.Activity; import android.app.AlarmManager; Loading Loading @@ -82,7 +83,7 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> { private TetherService mService; private MockResources mResources; private FakeUsageStatsManagerWrapper mUsageStatsManagerWrapper; private MockTetherServiceWrapper mWrapper; int mLastReceiverResultCode = BOGUS_RECEIVER_RESULT; private int mLastTetherRequestType = TETHERING_INVALID; private int mProvisionResponse = BOGUS_RECEIVER_RESULT; Loading Loading @@ -124,7 +125,7 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> { when(mPrefs.edit()).thenReturn(mPrefEditor); when(mPrefEditor.putString(eq(CURRENT_TYPES), mStoredTypes.capture())).thenReturn( mPrefEditor); mUsageStatsManagerWrapper = new FakeUsageStatsManagerWrapper(mContext); mWrapper = new MockTetherServiceWrapper(mContext); ResolveInfo systemAppResolveInfo = new ResolveInfo(); ActivityInfo systemActivityInfo = new ActivityInfo(); Loading @@ -145,6 +146,8 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> { resolvers.add(systemAppResolveInfo); when(mPackageManager.queryBroadcastReceivers( any(Intent.class), eq(PackageManager.MATCH_ALL))).thenReturn(resolvers); setupService(); getService().setTetherServiceWrapper(mWrapper); } @Override Loading @@ -170,16 +173,13 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> { } public void testStartKeepsProvisionAppActive() { setupService(); getService().setUsageStatsManagerWrapper(mUsageStatsManagerWrapper); runProvisioningForType(TETHERING_WIFI); assertTrue(waitForProvisionRequest(TETHERING_WIFI)); assertTrue(waitForProvisionResponse(TETHER_ERROR_NO_ERROR)); assertFalse(mUsageStatsManagerWrapper.isAppInactive(ENTITLEMENT_PACKAGE_NAME)); assertFalse(mWrapper.isAppInactive(ENTITLEMENT_PACKAGE_NAME)); // Non-system handler of the intent action should stay idle. assertTrue(mUsageStatsManagerWrapper.isAppInactive(FAKE_PACKAGE_NAME)); assertTrue(mWrapper.isAppInactive(FAKE_PACKAGE_NAME)); } public void testScheduleRechecks() { Loading Loading @@ -418,11 +418,11 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> { } } private static class FakeUsageStatsManagerWrapper extends TetherService.UsageStatsManagerWrapper { private static class MockTetherServiceWrapper extends TetherService.TetherServiceWrapper { private final Set<String> mActivePackages; FakeUsageStatsManagerWrapper(Context context) { MockTetherServiceWrapper(Context context) { super(context); mActivePackages = new HashSet<>(); } Loading @@ -439,5 +439,10 @@ public class TetherServiceTest extends ServiceTestCase<TetherService> { boolean isAppInactive(String packageName) { return !mActivePackages.contains(packageName); } @Override int getDefaultDataSubscriptionId() { return INVALID_SUBSCRIPTION_ID; } } }