Introduce device owner API to disable the status bar

Let the device owner disable the status bar to achieve multi-app single purpose
mode. When the status bar is disabled, quick settings, notifications and the
assist gesture are blocked.

Bug: 19533026
Change-Id: I72830798135136e5edc53e5e2221aebb9a7c7d57
This commit is contained in:
Benjamin Franz
2015-03-16 17:18:09 +00:00
parent de77be6311
commit ea2ec97f37
7 changed files with 91 additions and 8 deletions

View File

@@ -5737,6 +5737,7 @@ package android.app.admin {
method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public void setStatusBarEnabledState(android.content.ComponentName, boolean);
method public int setStorageEncryption(android.content.ComponentName, boolean);
method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);

View File

@@ -5841,6 +5841,7 @@ package android.app.admin {
method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public void setStatusBarEnabledState(android.content.ComponentName, boolean);
method public int setStorageEncryption(android.content.ComponentName, boolean);
method public void setTrustAgentConfiguration(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle);
method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);

View File

@@ -4210,4 +4210,20 @@ public class DevicePolicyManager {
return false;
}
}
/**
* Called by device owner to set the enabled state of the status bar. Disabling the status
* bar blocks notifications, quick settings and other screen overlays that allow escaping from
* a single use device.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param enabled New state of the status bar.
*/
public void setStatusBarEnabledState(ComponentName admin, boolean enabled) {
try {
mService.setStatusBarEnabledState(admin, enabled);
} catch (RemoteException re) {
Log.w(TAG, "Failed talking with device policy service", re);
}
}
}

View File

@@ -223,4 +223,5 @@ interface IDevicePolicyManager {
PersistableBundle getOtaPolicy();
boolean setKeyguardEnabledState(in ComponentName admin, boolean enabled);
void setStatusBarEnabledState(in ComponentName who, boolean enabled);
}

View File

@@ -27,6 +27,7 @@ interface IStatusBarService
void expandNotificationsPanel();
void collapsePanels();
void disable(int what, IBinder token, String pkg);
void disableForUser(int what, IBinder token, String pkg, int userId);
void setIcon(String slot, String iconPackage, int iconId, int iconLevel, String contentDescription);
void setIconVisibility(String slot, boolean visible);
void removeIcon(String slot);

View File

@@ -79,7 +79,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
public void binderDied() {
Slog.i(TAG, "binder died for pkg=" + pkg);
disableInternal(userId, 0, token, pkg);
disableForUser(0, token, pkg, userId);
token.unlinkToDeath(this, 0);
}
}
@@ -194,10 +194,11 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
@Override
public void disable(int what, IBinder token, String pkg) {
disableInternal(mCurrentUserId, what, token, pkg);
disableForUser(what, token, pkg, mCurrentUserId);
}
private void disableInternal(int userId, int what, IBinder token, String pkg) {
@Override
public void disableForUser(int what, IBinder token, String pkg, int userId) {
enforceStatusBar();
synchronized (mLock) {

View File

@@ -32,6 +32,7 @@ import android.app.IActivityManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.StatusBarManager;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyManager;
@@ -102,6 +103,7 @@ import android.view.IWindowManager;
import com.android.internal.R;
import com.android.internal.os.storage.ExternalStorageFormatter;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.Preconditions;
@@ -152,7 +154,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private static final String DEVICE_POLICIES_XML = "device_policies.xml";
private static final String LOCK_TASK_COMPONENTS_XML = "lock-task-component";
private static final String TAG_LOCK_TASK_COMPONENTS = "lock-task-component";
private static final String TAG_STATUS_BAR = "statusbar";
private static final String ATTR_ENABLED = "enabled";
private static final int REQUEST_EXPIRE_PASSWORD = 5571;
@@ -172,6 +178,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private static final String ATTR_DELEGATED_CERT_INSTALLER = "delegated-cert-installer";
private static final int STATUS_BAR_DISABLE_MASK =
StatusBarManager.DISABLE_EXPAND |
StatusBarManager.DISABLE_NOTIFICATION_ICONS |
StatusBarManager.DISABLE_NOTIFICATION_ALERTS |
StatusBarManager.DISABLE_SEARCH;
private static final Set<String> DEVICE_OWNER_USER_RESTRICTIONS;
static {
DEVICE_OWNER_USER_RESTRICTIONS = new HashSet();
@@ -237,6 +249,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Stores and loads state on device and profile owners.
private DeviceOwner mDeviceOwner;
private final Binder mToken = new Binder();
/**
* Whether or not device admin feature is supported. If it isn't return defaults for all
* public methods.
@@ -287,6 +301,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// This is the list of component allowed to start lock task mode.
final List<String> mLockTaskPackages = new ArrayList<>();
boolean mStatusBarEnabledState = true;
ComponentName mRestrictionsProvider;
String mDelegatedCertInstallerPackage;
@@ -1429,9 +1445,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
for (int i=0; i<policy.mLockTaskPackages.size(); i++) {
String component = policy.mLockTaskPackages.get(i);
out.startTag(null, LOCK_TASK_COMPONENTS_XML);
out.startTag(null, TAG_LOCK_TASK_COMPONENTS);
out.attribute(null, "name", component);
out.endTag(null, LOCK_TASK_COMPONENTS_XML);
out.endTag(null, TAG_LOCK_TASK_COMPONENTS);
}
if (!policy.mStatusBarEnabledState) {
out.startTag(null, TAG_STATUS_BAR);
out.attribute(null, ATTR_ENABLED, Boolean.toString(policy.mStatusBarEnabledState));
out.endTag(null, TAG_STATUS_BAR);
}
out.endTag(null, "policies");
@@ -1552,9 +1574,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
policy.mActivePasswordNonLetter = Integer.parseInt(
parser.getAttributeValue(null, "nonletter"));
XmlUtils.skipCurrentTag(parser);
} else if (LOCK_TASK_COMPONENTS_XML.equals(tag)) {
} else if (TAG_LOCK_TASK_COMPONENTS.equals(tag)) {
policy.mLockTaskPackages.add(parser.getAttributeValue(null, "name"));
XmlUtils.skipCurrentTag(parser);
} else if (TAG_STATUS_BAR.equals(tag)) {
policy.mStatusBarEnabledState = Boolean.parseBoolean(
parser.getAttributeValue(null, ATTR_ENABLED));
XmlUtils.skipCurrentTag(parser);
} else {
Slog.w(LOG_TAG, "Unknown tag: " + tag);
XmlUtils.skipCurrentTag(parser);
@@ -1679,7 +1705,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (!mHasFeature) {
return;
}
getUserData(UserHandle.USER_OWNER);
DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
loadDeviceOwner();
cleanUpOldUsers();
// Register an observer for watching for user setup complete.
@@ -1696,6 +1722,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
getScreenCaptureDisabled(null, userHandle));
}
if (mDeviceOwner != null && mDeviceOwner.hasDeviceOwner()
&& !policy.mStatusBarEnabledState) {
setStatusBarEnabledStateInternal(STATUS_BAR_DISABLE_MASK, UserHandle.USER_OWNER);
}
}
private void cleanUpOldUsers() {
@@ -5830,6 +5860,38 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return true;
}
@Override
public void setStatusBarEnabledState(ComponentName who, boolean enabled) {
int userId = UserHandle.getCallingUserId();
synchronized (this) {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
DevicePolicyData policy = getUserData(userId);
if (policy.mStatusBarEnabledState != enabled) {
policy.mStatusBarEnabledState = enabled;
setStatusBarEnabledStateInternal(
enabled ? StatusBarManager.DISABLE_NONE : STATUS_BAR_DISABLE_MASK,
userId);
saveSettingsLocked(userId);
}
}
}
private void setStatusBarEnabledStateInternal(int flags, int userId) {
long ident = Binder.clearCallingIdentity();
try {
IStatusBarService statusBarService = IStatusBarService.Stub.asInterface(
ServiceManager.checkService(Context.STATUS_BAR_SERVICE));
if (statusBarService != null) {
statusBarService.disableForUser(flags, mToken,
mDeviceOwner.getDeviceOwnerPackageName(), userId);
}
} catch (RemoteException e) {
Slog.e(LOG_TAG, "Failed to disable the status bar", e);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
/**
* We need to update the internal state of whether a user has completed setup once. After
* that, we ignore any changes that reset the Settings.Secure.USER_SETUP_COMPLETE changes