| /* |
| * 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.cts.managedprofile; |
| |
| import static android.os.Process.BLUETOOTH_UID; |
| |
| import android.app.UiAutomation; |
| import android.bluetooth.BluetoothAdapter; |
| import android.content.ComponentName; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.pm.ComponentInfo; |
| import android.content.pm.PackageManager; |
| import android.content.pm.ResolveInfo; |
| import android.net.Uri; |
| import android.os.SystemClock; |
| import android.os.SystemProperties; |
| import android.os.UserManager; |
| |
| import androidx.test.InstrumentationRegistry; |
| |
| import com.android.internal.util.ArrayUtils; |
| |
| import junit.framework.TestCase; |
| |
| import java.util.List; |
| |
| /** |
| * Test {@link UserManager#DISALLOW_BLUETOOTH_SHARING} in profile owner. |
| * |
| * Shamelessly copied from BluetoothRestrictionTest, would be nice to extract common stuff to a lib. |
| */ |
| public class BluetoothSharingRestrictionTest extends BaseManagedProfileTest { |
| /** How long should we wait for the component state to change. */ |
| private static final int COMPONENT_STATE_TIMEOUT_MS = 5000; |
| /** How often to check component state. */ |
| private static final int POLL_TIME_MS = 400; |
| /** Activity that handles Bluetooth sharing. */ |
| private static final String OPP_LAUNCHER_CLASS = |
| "com.android.bluetooth.opp.BluetoothOppLauncherActivity"; |
| private static final String INTERACT_ACROSS_USERS_PERMISSION = |
| "android.permission.INTERACT_ACROSS_USERS"; |
| private static final UiAutomation sUiAutomation = |
| InstrumentationRegistry.getInstrumentation().getUiAutomation(); |
| |
| /** |
| * Tests that Bluetooth sharing activity gets disabled when the restriction is enforced. |
| */ |
| public void testOppDisabledWhenRestrictionSet() throws Exception { |
| if (BluetoothAdapter.getDefaultAdapter() == null) { |
| // No Bluetooth - nothing to test. |
| return; |
| } |
| |
| // The restriction is active by default for managed profiles. |
| assertBluetoothSharingAvailable(mContext, false); |
| |
| // Remove the user restriction. |
| mDevicePolicyManager.clearUserRestriction( |
| ADMIN_RECEIVER_COMPONENT, UserManager.DISALLOW_BLUETOOTH_SHARING); |
| // Bluetooth sharing should become available. |
| assertBluetoothSharingAvailable(mContext, true); |
| |
| // Add the user restriction back (which is the default state). |
| mDevicePolicyManager.addUserRestriction( |
| ADMIN_RECEIVER_COMPONENT, UserManager.DISALLOW_BLUETOOTH_SHARING); |
| // Bluetooth sharing should be disabled once again. |
| assertBluetoothSharingAvailable(mContext, false); |
| } |
| |
| /** Verifies restriction enforcement. */ |
| private static void assertRestrictionEnforced(Context context, boolean enforced) { |
| final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); |
| assertEquals("Invalid restriction enforcement status", enforced, |
| um.getUserRestrictions().getBoolean(UserManager.DISALLOW_BLUETOOTH_SHARING, false)); |
| } |
| |
| /** |
| * Builds an intent to share an image file. If Bluetooth sharing is allowed, it should be |
| * handled by {@link #OPP_LAUNCHER_CLASS}. |
| */ |
| private static Intent fileSharingIntent() { |
| final Intent result = new Intent(Intent.ACTION_SEND); |
| final Uri uri = Uri.parse("content://foo/bar"); |
| result.setDataAndType(uri, "image/*"); |
| return result; |
| } |
| |
| /** |
| * Verifies bluetooth sharing availability. |
| */ |
| static void assertBluetoothSharingAvailable(Context context, boolean available) |
| throws Exception { |
| // Check restriction. |
| assertRestrictionEnforced(context, !available); |
| // Check component status. |
| final int[] componentEnabledState = available |
| ? new int[] {PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, |
| PackageManager.COMPONENT_ENABLED_STATE_ENABLED} |
| : new int[] {PackageManager.COMPONENT_ENABLED_STATE_DISABLED}; |
| |
| sUiAutomation.adoptShellPermissionIdentity(INTERACT_ACROSS_USERS_PERMISSION); |
| String bluetoothPackageName = context.getPackageManager() |
| .getPackagesForUid(BLUETOOTH_UID)[0]; |
| sUiAutomation.dropShellPermissionIdentity(); |
| |
| ComponentName oppLauncherComponent = new ComponentName( |
| bluetoothPackageName, OPP_LAUNCHER_CLASS); |
| |
| assertComponentStateAfterTimeout(context, oppLauncherComponent, componentEnabledState); |
| // Do not perform the handler check if the profile is disabled on the device. |
| if (SystemProperties.getBoolean("bluetooth.profile.opp.enabled", false)) { |
| // Check whether sharing activity is offered. |
| assertHandlerAvailable(context, fileSharingIntent(), oppLauncherComponent, available); |
| } |
| } |
| |
| /** Waits for package state to change to a desired one or fails. */ |
| private static void assertComponentStateAfterTimeout(Context context, ComponentName component, |
| int[] expectedState) |
| throws Exception { |
| final long timeout = SystemClock.elapsedRealtime() + COMPONENT_STATE_TIMEOUT_MS; |
| int state = -1; |
| while (SystemClock.elapsedRealtime() < timeout) { |
| state = context.getPackageManager().getComponentEnabledSetting(component); |
| if (ArrayUtils.contains(expectedState, state)) { |
| // Success |
| return; |
| } |
| Thread.sleep(POLL_TIME_MS); |
| } |
| TestCase.fail("The state of " + component + " should have been " |
| + ArrayUtils.deepToString(expectedState) |
| + ", but was " + state + " after timeout."); |
| } |
| |
| /** Verifies that {@code component} is offered when handling {@code intent}. */ |
| private static void assertHandlerAvailable(Context context, Intent intent, |
| ComponentName component, |
| boolean shouldResolve) { |
| final List<ResolveInfo> infos = |
| context.getPackageManager().queryIntentActivities(intent, 0); |
| for (final ResolveInfo info : infos) { |
| final ComponentInfo componentInfo = |
| info.activityInfo != null ? info.activityInfo : |
| info.serviceInfo != null ? info.serviceInfo : |
| info.providerInfo; |
| final ComponentName resolvedComponent = |
| new ComponentName(componentInfo.packageName, componentInfo.name); |
| if (resolvedComponent.equals(component)) { |
| if (shouldResolve) { |
| // Found it, assertion passed. |
| return; |
| } else { |
| TestCase.fail(component + " is available as a handler for " + intent); |
| } |
| } |
| } |
| // If we get to this point, there was no match. |
| if (shouldResolve) { |
| TestCase.fail(component + " isn't available as a handler for " + intent); |
| } |
| } |
| } |