diff options
9 files changed, 183 insertions, 1 deletions
diff --git a/api/current.txt b/api/current.txt index 3d08dd8..934452f 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5355,6 +5355,7 @@ package android.app.admin { method public int getPasswordMinimumSymbols(android.content.ComponentName); method public int getPasswordMinimumUpperCase(android.content.ComponentName); method public int getPasswordQuality(android.content.ComponentName); + method public boolean getScreenCaptureDisabled(android.content.ComponentName); method public boolean getStorageEncryption(android.content.ComponentName); method public int getStorageEncryptionStatus(); method public boolean hasAnyCaCertsInstalled(); @@ -5399,6 +5400,7 @@ package android.app.admin { method public void setProfileName(android.content.ComponentName, java.lang.String); method public void setRecommendedGlobalProxy(android.content.ComponentName, android.net.ProxyInfo); 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 int setStorageEncryption(android.content.ComponentName, boolean); method public boolean switchUser(android.content.ComponentName, android.os.UserHandle); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index efeded5..a193a34 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1775,6 +1775,46 @@ public class DevicePolicyManager { } /** + * Called by a device/profile owner to set whether the screen capture is disabled. + * + * <p>The calling device admin must be a device or profile owner. If it is not, a + * security exception will be thrown. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + */ + public void setScreenCaptureDisabled(ComponentName admin, boolean disabled) { + if (mService != null) { + try { + mService.setScreenCaptureDisabled(admin, UserHandle.myUserId(), disabled); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + } + + /** + * Determine whether or not screen capture has been disabled by the current + * admin, if specified, or all admins. + * @param admin The name of the admin component to check, or null to check if any admins + * have disabled screen capture. + */ + public boolean getScreenCaptureDisabled(ComponentName admin) { + return getScreenCaptureDisabled(admin, UserHandle.myUserId()); + } + + /** @hide per-user version */ + public boolean getScreenCaptureDisabled(ComponentName admin, int userHandle) { + if (mService != null) { + try { + return mService.getScreenCaptureDisabled(admin, userHandle); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + } + return false; + } + + /** * Called by an application that is administering the device to disable keyguard customizations, * such as widgets. After setting this, keyguard features will be disabled according to the * provided feature list. diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 5fc8c5f..6499ae4 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -88,6 +88,9 @@ interface IDevicePolicyManager { void setCameraDisabled(in ComponentName who, boolean disabled, int userHandle); boolean getCameraDisabled(in ComponentName who, int userHandle); + void setScreenCaptureDisabled(in ComponentName who, int userHandle, boolean disabled); + boolean getScreenCaptureDisabled(in ComponentName who, int userHandle); + void setKeyguardDisabledFeatures(in ComponentName who, int which, int userHandle); int getKeyguardDisabledFeatures(in ComponentName who, int userHandle); diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index a61d771..5157c41 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -149,6 +149,12 @@ interface IWindowManager // boolean string as parsed by SystemProperties.getBoolean(). void setStrictModeVisualIndicatorPreference(String enabled); + /** + * Update the windowmanagers cached value of + * {@link android.app.admin.DevicePolicyManager#getScreenCaptureDisabled(null, userId)} + */ + void updateScreenCaptureDisabled(int userId); + // These can only be called with the SET_ORIENTATION permission. /** * Update the current screen rotation based on the current state of diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index cf2f5d3..416cd54 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -191,7 +191,7 @@ <!-- Notification title displayed when we fail to take a screenshot. [CHAR LIMIT=50] --> <string name="screenshot_failed_title">Couldn\'t capture screenshot.</string> <!-- Notification text displayed when we fail to take a screenshot. [CHAR LIMIT=100] --> - <string name="screenshot_failed_text">Couldn\'t save screenshot. Storage may be in use.</string> + <string name="screenshot_failed_text">Can\'t take screenshot due to limited storage space, or it isn\'t allowed by the app or your organization.</string> <!-- Title for the USB function chooser in UsbPreferenceActivity. [CHAR LIMIT=30] --> <string name="usb_preference_title">USB file transfer options</string> diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index aae2bb8..eac2819 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.*; import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; +import android.app.admin.DevicePolicyManager; import android.app.AppOpsManager; import android.util.ArraySet; import android.util.TimeUtils; @@ -425,6 +426,13 @@ public class WindowManagerService extends IWindowManager.Stub */ WindowState[] mRebuildTmp = new WindowState[20]; + /** + * Stores for each user whether screencapture is disabled + * This array is essentially a cache for all userId for + * {@link android.app.admin.DevicePolicyManager#getScreenCaptureDisabled(null, userId)} + */ + SparseArray<Boolean> mScreenCaptureDisabled = new SparseArray<Boolean>(); + IInputMethodManager mInputMethodManager; AccessibilityController mAccessibilityController; @@ -2439,6 +2447,45 @@ public class WindowManagerService extends IWindowManager.Stub return res; } + /** + * Returns whether screen capture is disabled for all windows of a specific user. + */ + boolean isScreenCaptureDisabledLocked(int userId) { + Boolean disabled = mScreenCaptureDisabled.get(userId); + if (disabled != null) { + return disabled; + } + + // mScreenCaptureDisabled not set yet, try to update it. + updateScreenCaptureDisabledLocked(userId); + disabled = mScreenCaptureDisabled.get(userId); + if (disabled == null) { + // Not able to update, return false by default. + return false; + } else { + return disabled; + } + } + + /** + * Update mScreenCaptureDisabled for specific user according to the device policy manager. + */ + @Override + public void updateScreenCaptureDisabled(int userId) { + mH.sendMessage(mH.obtainMessage(H.UPDATE_SCRN_CAP, userId, 0 /* unused argument */)); + } + + void updateScreenCaptureDisabledLocked(int userId) { + DevicePolicyManager dpm = (DevicePolicyManager) mContext + .getSystemService(Context.DEVICE_POLICY_SERVICE); + if (dpm != null) { + boolean disabled = dpm.getScreenCaptureDisabled(null, userId); + mScreenCaptureDisabled.put(userId, disabled); + } else { + Slog.e(TAG, "Could not get DevicePolicyManager."); + } + } + public void removeWindow(Session session, IWindow client) { synchronized(mWindowMap) { WindowState win = windowForClientLocked(session, client, false); @@ -7203,6 +7250,8 @@ public class WindowManagerService extends IWindowManager.Stub public static final int NEW_ANIMATOR_SCALE = 34; + public static final int UPDATE_SCRN_CAP = 35; + @Override public void handleMessage(Message msg) { if (DEBUG_WINDOW_TRACE) { @@ -7677,6 +7726,13 @@ public class WindowManagerService extends IWindowManager.Stub } } break; + + case UPDATE_SCRN_CAP: { + synchronized (mWindowMap) { + updateScreenCaptureDisabledLocked(msg.arg1); + } + } + break; } if (DEBUG_WINDOW_TRACE) { Slog.v(TAG, "handleMessage: exit"); diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 49d4ae9..f3afe82 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -39,6 +39,7 @@ import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.os.Debug; +import android.os.UserHandle; import android.util.Slog; import android.view.Display; import android.view.DisplayInfo; @@ -690,6 +691,10 @@ class WindowStateAnimator { flags |= SurfaceControl.SECURE; } + if (mService.isScreenCaptureDisabledLocked(UserHandle.getUserId(mWin.mOwnerUid))) { + flags |= SurfaceControl.SECURE; + } + int width; int height; if ((attrs.flags & LayoutParams.FLAG_SCALED) != 0) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 5c661af..e0612eb 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -258,6 +258,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features"; private static final String TAG_DISABLE_CAMERA = "disable-camera"; private static final String TAG_DISABLE_CALLER_ID = "disable-caller-id"; + private static final String TAG_DISABLE_SCREEN_CAPTURE = "disable-screen-capture"; private static final String TAG_DISABLE_ACCOUNT_MANAGEMENT = "disable-account-management"; private static final String TAG_ACCOUNT_TYPE = "account-type"; private static final String TAG_ENCRYPTION_REQUESTED = "encryption-requested"; @@ -326,6 +327,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { boolean encryptionRequested = false; boolean disableCamera = false; boolean disableCallerId = false; + boolean disableScreenCapture = false; // Can only be set by a device/profile owner. + Set<String> accountTypesWithManagementDisabled = new HashSet<String>(); // TODO: review implementation decisions with frameworks team @@ -443,6 +446,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.attribute(null, ATTR_VALUE, Boolean.toString(disableCallerId)); out.endTag(null, TAG_DISABLE_CALLER_ID); } + if (disableScreenCapture) { + out.startTag(null, TAG_DISABLE_SCREEN_CAPTURE); + out.attribute(null, ATTR_VALUE, Boolean.toString(disableScreenCapture)); + out.endTag(null, TAG_DISABLE_SCREEN_CAPTURE); + } if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) { out.startTag(null, TAG_DISABLE_KEYGUARD_FEATURES); out.attribute(null, ATTR_VALUE, Integer.toString(disabledKeyguardFeatures)); @@ -528,6 +536,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } else if (TAG_DISABLE_CALLER_ID.equals(tag)) { disableCallerId = Boolean.parseBoolean( parser.getAttributeValue(null, ATTR_VALUE)); + } else if (TAG_DISABLE_SCREEN_CAPTURE.equals(tag)) { + disableScreenCapture = Boolean.parseBoolean( + parser.getAttributeValue(null, ATTR_VALUE)); } else if (TAG_DISABLE_KEYGUARD_FEATURES.equals(tag)) { disabledKeyguardFeatures = Integer.parseInt( parser.getAttributeValue(null, ATTR_VALUE)); @@ -606,6 +617,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { pw.println(disableCamera); pw.print(prefix); pw.print("disableCallerId="); pw.println(disableCallerId); + pw.print(prefix); pw.print("disableScreenCapture="); + pw.println(disableScreenCapture); pw.print(prefix); pw.print("disabledKeyguardFeatures="); pw.println(disabledKeyguardFeatures); } @@ -2977,6 +2990,58 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private void setEncryptionRequested(boolean encrypt) { } + + /** + * Set whether the screen capture is disabled for the user managed by the specified admin. + */ + public void setScreenCaptureDisabled(ComponentName who, int userHandle, boolean disabled) { + if (!mHasFeature) { + return; + } + synchronized (this) { + if (who == null) { + throw new NullPointerException("ComponentName is null"); + } + ActiveAdmin ap = getActiveAdminForCallerLocked(who, + DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + if (ap.disableScreenCapture != disabled) { + ap.disableScreenCapture = disabled; + saveSettingsLocked(userHandle); + try { + getWindowManager().updateScreenCaptureDisabled(userHandle); + } catch (RemoteException e) { + Log.w(LOG_TAG, "Unable to notify WindowManager.", e); + } + } + } + } + + /** + * Returns whether or not screen capture is disabled for a given admin, or disabled for any + * active admin (if given admin is null). + */ + public boolean getScreenCaptureDisabled(ComponentName who, int userHandle) { + if (!mHasFeature) { + return false; + } + synchronized (this) { + if (who != null) { + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + return (admin != null) ? admin.disableScreenCapture : false; + } + + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (admin.disableScreenCapture) { + return true; + } + } + return false; + } + } + /** * The system property used to share the state of the camera. The native camera service * is expected to read this property and act accordingly. diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java index 6927b26..2ffe4a2 100644 --- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java +++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java @@ -360,6 +360,11 @@ public class IWindowManagerImpl implements IWindowManager { } @Override + public void updateScreenCaptureDisabled(int userId) { + // TODO Auto-generated method stub + } + + @Override public void updateRotation(boolean arg0, boolean arg1) throws RemoteException { // TODO Auto-generated method stub } |