diff options
| author | 2018-01-13 00:34:42 +0000 | |
|---|---|---|
| committer | 2018-01-13 00:34:42 +0000 | |
| commit | 2d38a44938d9c2bf0635921dbe9f6cc16c1c9221 (patch) | |
| tree | e1f9a06d3dd810f9ebd81437f9bc8755f5f4836e | |
| parent | 2c941f8460314dfafa2b4e52886352b6d69bc5b4 (diff) | |
| parent | a2cd19e3d1c0ec0ad0932bb033a53b9e7e009537 (diff) | |
Merge "Screenshot global actions item."
| -rw-r--r-- | core/java/com/android/internal/util/ScreenshotHelper.java | 128 | ||||
| -rw-r--r-- | core/res/res/drawable/ic_screenshot.xml | 33 | ||||
| -rw-r--r-- | core/res/res/values/config.xml | 1 | ||||
| -rw-r--r-- | core/res/res/values/strings.xml | 6 | ||||
| -rw-r--r-- | core/res/res/values/symbols.xml | 4 | ||||
| -rw-r--r-- | packages/SystemUI/res/values/strings.xml | 16 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java | 42 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java | 2 | ||||
| -rw-r--r-- | proto/src/metrics_constants.proto | 6 | ||||
| -rw-r--r-- | services/core/java/com/android/server/policy/PhoneWindowManager.java | 101 |
10 files changed, 234 insertions, 105 deletions
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java new file mode 100644 index 000000000000..f7ea7875c8df --- /dev/null +++ b/core/java/com/android/internal/util/ScreenshotHelper.java @@ -0,0 +1,128 @@ +package com.android.internal.util; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.Log; + +public class ScreenshotHelper { + private static final String TAG = "ScreenshotHelper"; + + private static final String SYSUI_PACKAGE = "com.android.systemui"; + private static final String SYSUI_SCREENSHOT_SERVICE = + "com.android.systemui.screenshot.TakeScreenshotService"; + private static final String SYSUI_SCREENSHOT_ERROR_RECEIVER = + "com.android.systemui.screenshot.ScreenshotServiceErrorReceiver"; + + // Time until we give up on the screenshot & show an error instead. + private final int SCREENSHOT_TIMEOUT_MS = 10000; + + private final Object mScreenshotLock = new Object(); + private ServiceConnection mScreenshotConnection = null; + private final Context mContext; + + public ScreenshotHelper(Context context) { + mContext = context; + } + + public void takeScreenshot(final int screenshotType, final boolean hasStatus, + final boolean hasNav, Handler handler) { + synchronized (mScreenshotLock) { + if (mScreenshotConnection != null) { + return; + } + final ComponentName serviceComponent = new ComponentName(SYSUI_PACKAGE, + SYSUI_SCREENSHOT_SERVICE); + final Intent serviceIntent = new Intent(); + + final Runnable mScreenshotTimeout = new Runnable() { + @Override public void run() { + synchronized (mScreenshotLock) { + if (mScreenshotConnection != null) { + mContext.unbindService(mScreenshotConnection); + mScreenshotConnection = null; + notifyScreenshotError(); + } + } + } + }; + + serviceIntent.setComponent(serviceComponent); + ServiceConnection conn = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + synchronized (mScreenshotLock) { + if (mScreenshotConnection != this) { + return; + } + Messenger messenger = new Messenger(service); + Message msg = Message.obtain(null, screenshotType); + final ServiceConnection myConn = this; + Handler h = new Handler(handler.getLooper()) { + @Override + public void handleMessage(Message msg) { + synchronized (mScreenshotLock) { + if (mScreenshotConnection == myConn) { + mContext.unbindService(mScreenshotConnection); + mScreenshotConnection = null; + handler.removeCallbacks(mScreenshotTimeout); + } + } + } + }; + msg.replyTo = new Messenger(h); + msg.arg1 = hasStatus ? 1: 0; + msg.arg2 = hasNav ? 1: 0; + try { + messenger.send(msg); + } catch (RemoteException e) { + Log.e(TAG, "Couldn't take screenshot: " + e); + } + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + synchronized (mScreenshotLock) { + if (mScreenshotConnection != null) { + mContext.unbindService(mScreenshotConnection); + mScreenshotConnection = null; + handler.removeCallbacks(mScreenshotTimeout); + notifyScreenshotError(); + } + } + } + }; + if (mContext.bindServiceAsUser(serviceIntent, conn, + Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE, + UserHandle.CURRENT)) { + mScreenshotConnection = conn; + handler.postDelayed(mScreenshotTimeout, SCREENSHOT_TIMEOUT_MS); + } + } + } + + /** + * Notifies the screenshot service to show an error. + */ + private void notifyScreenshotError() { + // If the service process is killed, then ask it to clean up after itself + final ComponentName errorComponent = new ComponentName(SYSUI_PACKAGE, + SYSUI_SCREENSHOT_ERROR_RECEIVER); + // Broadcast needs to have a valid action. We'll just pick + // a generic one, since the receiver here doesn't care. + Intent errorIntent = new Intent(Intent.ACTION_USER_PRESENT); + errorIntent.setComponent(errorComponent); + errorIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | + Intent.FLAG_RECEIVER_FOREGROUND); + mContext.sendBroadcastAsUser(errorIntent, UserHandle.CURRENT); + } + +} diff --git a/core/res/res/drawable/ic_screenshot.xml b/core/res/res/drawable/ic_screenshot.xml new file mode 100644 index 000000000000..3074b28497cf --- /dev/null +++ b/core/res/res/drawable/ic_screenshot.xml @@ -0,0 +1,33 @@ +<!-- +Copyright (C) 2018 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24.0dp" + android:height="24.0dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:pathData="M0,0h24v24H0V0z" + android:fillColor="#00000000"/> + <path + android:fillColor="#FF000000" + android:pathData="M17.0,1.0L7.0,1.0C5.9,1.0 5.0,1.9 5.0,3.0l0.0,18.0c0.0,1.1 0.9,2.0 2.0,2.0l10.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L19.0,3.0C19.0,1.9 18.1,1.0 17.0,1.0zM17.0,20.0L7.0,20.0L7.0,4.0l10.0,0.0L17.0,20.0z"/> + <path + android:fillColor="#FF000000" + android:pathData="M13.0,6.0l-4.0,0.0 0.0,4.0 1.5,0.0 0.0,-2.5 2.5,0.0z"/> + <path + android:fillColor="#FF000000" + android:pathData="M11.0,18.0l4.0,0.0 0.0,-4.0 -1.5,0.0 0.0,2.5 -2.5,0.0z"/> +</vector> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index f1e9662a5458..ed94f8471130 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2481,6 +2481,7 @@ <string-array translatable="false" name="config_globalActionsList"> <item>power</item> <item>restart</item> + <item>screenshot</item> <item>logout</item> <item>bugreport</item> <item>users</item> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index f671b6b8382f..b2fa294f77be 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -484,6 +484,9 @@ <!-- label for item that logouts the current user --> <string name="global_action_logout">End session</string> + <!-- label for screenshot item in power menu --> + <string name="global_action_screenshot">Screenshot</string> + <!-- Take bug report menu title [CHAR LIMIT=NONE] --> <string name="bugreport_title">Take bug report</string> <!-- Message in bugreport dialog describing what it does [CHAR LIMIT=NONE] --> @@ -4800,13 +4803,10 @@ <!--Battery saver warning. STOPSHIP: Remove it eventually. --> <string name="battery_saver_warning_title" translatable="false">Extreme battery saver</string> - <!-- Label for the uninstall button on the harmful app warning dialog. --> <string name="harmful_app_warning_uninstall">Uninstall</string> <!-- Label for the launch anyway button on the harmful app warning dialog. --> <string name="harmful_app_warning_launch_anyway">Launch anyway</string> <!-- Title for the harmful app warning dialog. --> <string name="harmful_app_warning_title">Uninstall harmful app?</string> - - </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 0dad20bbce58..1251c11c4daa 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1722,6 +1722,7 @@ <java-symbol type="string" name="global_action_lockdown" /> <java-symbol type="string" name="global_action_voice_assist" /> <java-symbol type="string" name="global_action_assist" /> + <java-symbol type="string" name="global_action_screenshot" /> <java-symbol type="string" name="invalidPuk" /> <java-symbol type="string" name="lockscreen_carrier_default" /> <java-symbol type="style" name="Animation.LockScreen" /> @@ -2889,8 +2890,9 @@ <java-symbol type="bool" name="config_permissionReviewRequired" /> - + <!-- Global actions icons --> <java-symbol type="drawable" name="ic_restart" /> + <java-symbol type="drawable" name="ic_screenshot" /> <java-symbol type="drawable" name="emergency_icon" /> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index a19917d91667..6ff239ebd2ee 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -173,22 +173,25 @@ [CHAR LIMIT=25] --> <string name="compat_mode_off">Stretch to fill screen</string> + <!-- Power menu item for taking a screenshot [CHAR LIMIT=20]--> + <string name="global_action_screenshot">Screenshot</string> + <!-- Notification ticker displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=30] --> <string name="screenshot_saving_ticker">Saving screenshot\u2026</string> <!-- Notification title displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=50] --> <string name="screenshot_saving_title">Saving screenshot\u2026</string> <!-- Notification text displayed when a screenshot is being saved to the Gallery. [CHAR LIMIT=100] --> - <string name="screenshot_saving_text">Screenshot is being saved.</string> + <string name="screenshot_saving_text">Screenshot is being saved</string> <!-- Notification title displayed when a screenshot is saved to the Gallery. [CHAR LIMIT=50] --> - <string name="screenshot_saved_title">Screenshot captured.</string> + <string name="screenshot_saved_title">Screenshot saved</string> <!-- Notification text displayed when a screenshot is saved to the Gallery. [CHAR LIMIT=100] --> - <string name="screenshot_saved_text">Tap to view your screenshot.</string> + <string name="screenshot_saved_text">Tap to view your screenshot</string> <!-- Notification title displayed when we fail to take a screenshot. [CHAR LIMIT=50] --> - <string name="screenshot_failed_title">Couldn\'t capture screenshot.</string> + <string name="screenshot_failed_title">Couldn\'t capture screenshot</string> <!-- Notification text displayed when we fail to save a screenshot for unknown reasons. [CHAR LIMIT=100] --> - <string name="screenshot_failed_to_save_unknown_text">Problem encountered while saving screenshot.</string> + <string name="screenshot_failed_to_save_unknown_text">Problem encountered while saving screenshot</string> <!-- Notification text displayed when we fail to save a screenshot. [CHAR LIMIT=100] --> - <string name="screenshot_failed_to_save_text">Can\'t save screenshot due to limited storage space.</string> + <string name="screenshot_failed_to_save_text">Can\'t save screenshot due to limited storage space</string> <!-- Notification text displayed when we fail to take a screenshot. [CHAR LIMIT=100] --> <string name="screenshot_failed_to_capture_text">Taking screenshots isn\'t allowed by the app or your organization</string> @@ -2038,4 +2041,5 @@ <string name="touch_filtered_warning">Because an app is obscuring a permission request, Settings can’t verify your response.</string> + </resources> diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index e008148a25de..0f34513bc40f 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -24,10 +24,12 @@ import android.app.KeyguardManager; import android.app.WallpaperManager; import android.app.admin.DevicePolicyManager; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; +import android.content.ServiceConnection; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.graphics.Point; @@ -36,7 +38,9 @@ import android.media.AudioManager; import android.net.ConnectivityManager; import android.os.Build; import android.os.Handler; +import android.os.IBinder; import android.os.Message; +import android.os.Messenger; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; @@ -77,6 +81,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyProperties; import com.android.internal.util.EmergencyAffordanceManager; +import com.android.internal.util.ScreenshotHelper; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.Dependency; import com.android.systemui.HardwareUiLayout; @@ -117,6 +122,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, private static final String GLOBAL_ACTION_KEY_ASSIST = "assist"; private static final String GLOBAL_ACTION_KEY_RESTART = "restart"; private static final String GLOBAL_ACTION_KEY_LOGOUT = "logout"; + private static final String GLOBAL_ACTION_KEY_SCREENSHOT = "screenshot"; private final Context mContext; private final GlobalActionsManager mWindowManagerFuncs; @@ -143,6 +149,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, private boolean mHasLogoutButton; private final boolean mShowSilentToggle; private final EmergencyAffordanceManager mEmergencyAffordanceManager; + private final ScreenshotHelper mScreenshotHelper; /** * @param context everything needs a context :( @@ -183,6 +190,7 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, R.bool.config_useFixedVolume); mEmergencyAffordanceManager = new EmergencyAffordanceManager(context); + mScreenshotHelper = new ScreenshotHelper(context); } /** @@ -340,6 +348,8 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, mItems.add(getAssistAction()); } else if (GLOBAL_ACTION_KEY_RESTART.equals(actionKey)) { mItems.add(new RestartAction()); + } else if (GLOBAL_ACTION_KEY_SCREENSHOT.equals(actionKey)) { + mItems.add(new ScreenshotAction()); } else if (GLOBAL_ACTION_KEY_LOGOUT.equals(actionKey)) { if (mDevicePolicyManager.isLogoutEnabled() && getCurrentUser().id != UserHandle.USER_SYSTEM) { @@ -458,6 +468,38 @@ class GlobalActionsDialog implements DialogInterface.OnDismissListener, } + private class ScreenshotAction extends SinglePressAction { + public ScreenshotAction() { + super(R.drawable.ic_screenshot, R.string.global_action_screenshot); + } + + @Override + public void onPress() { + // Add a little delay before executing, to give the + // dialog a chance to go away before it takes a + // screenshot. + // TODO: instead, omit global action dialog layer + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + mScreenshotHelper.takeScreenshot(1, true, true, mHandler); + MetricsLogger.action(mContext, + MetricsEvent.ACTION_SCREENSHOT_POWER_MENU); + } + }, 500); + } + + @Override + public boolean showDuringKeyguard() { + return true; + } + + @Override + public boolean showBeforeProvisioning() { + return false; + } + } + private class BugReportAction extends SinglePressAction implements LongPressAction { public BugReportAction() { diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java index f3bae20e544a..34b8bfe59e7e 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java @@ -67,6 +67,8 @@ public class TakeScreenshotService extends Service { case WindowManager.TAKE_SCREENSHOT_SELECTED_REGION: mScreenshot.takeScreenshotPartial(finisher, msg.arg1 > 0, msg.arg2 > 0); break; + default: + Log.d(TAG, "Invalid screenshot option: " + msg.what); } } }; diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 4f04d36ba2fc..10a809aaae08 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -5129,6 +5129,12 @@ message MetricsEvent { // OS: P FUELGAUGE_SMART_BATTERY = 1281; + // ACTION: User tapped Screenshot in the power menu. + // CATEGORY: GLOBAL_SYSTEM_UI + // OS: P + ACTION_SCREENSHOT_POWER_MENU = 1282; + + // ---- End P Constants, all P constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index a1852fe501e3..31dd67311aab 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -269,6 +269,7 @@ import com.android.internal.policy.IShortcutService; import com.android.internal.policy.PhoneWindow; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.ScreenshotHelper; import com.android.internal.util.ScreenShapeHelper; import com.android.internal.widget.PointerLocationView; import com.android.server.GestureLauncherService; @@ -460,6 +461,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { AccessibilityManager mAccessibilityManager; BurnInProtectionHelper mBurnInProtectionHelper; AppOpsManager mAppOpsManager; + private ScreenshotHelper mScreenshotHelper; private boolean mHasFeatureWatch; private boolean mHasFeatureLeanback; @@ -1713,7 +1715,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public void run() { - takeScreenshot(mScreenshotType); + mScreenshotHelper.takeScreenshot(mScreenshotType, + mStatusBar != null && mStatusBar.isVisibleLw(), + mNavigationBar != null && mNavigationBar.isVisibleLw(), mHandler); } } @@ -2191,6 +2195,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { mWindowManagerFuncs.notifyKeyguardTrustedChanged(); } }); + mScreenshotHelper = new ScreenshotHelper(mContext); } /** @@ -5766,100 +5771,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { setHdmiPlugged(!mHdmiPlugged); } - final Object mScreenshotLock = new Object(); - ServiceConnection mScreenshotConnection = null; - - final Runnable mScreenshotTimeout = new Runnable() { - @Override public void run() { - synchronized (mScreenshotLock) { - if (mScreenshotConnection != null) { - mContext.unbindService(mScreenshotConnection); - mScreenshotConnection = null; - notifyScreenshotError(); - } - } - } - }; - - // Assume this is called from the Handler thread. - private void takeScreenshot(final int screenshotType) { - synchronized (mScreenshotLock) { - if (mScreenshotConnection != null) { - return; - } - final ComponentName serviceComponent = new ComponentName(SYSUI_PACKAGE, - SYSUI_SCREENSHOT_SERVICE); - final Intent serviceIntent = new Intent(); - serviceIntent.setComponent(serviceComponent); - ServiceConnection conn = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - synchronized (mScreenshotLock) { - if (mScreenshotConnection != this) { - return; - } - Messenger messenger = new Messenger(service); - Message msg = Message.obtain(null, screenshotType); - final ServiceConnection myConn = this; - Handler h = new Handler(mHandler.getLooper()) { - @Override - public void handleMessage(Message msg) { - synchronized (mScreenshotLock) { - if (mScreenshotConnection == myConn) { - mContext.unbindService(mScreenshotConnection); - mScreenshotConnection = null; - mHandler.removeCallbacks(mScreenshotTimeout); - } - } - } - }; - msg.replyTo = new Messenger(h); - msg.arg1 = msg.arg2 = 0; - if (mStatusBar != null && mStatusBar.isVisibleLw()) - msg.arg1 = 1; - if (mNavigationBar != null && mNavigationBar.isVisibleLw()) - msg.arg2 = 1; - try { - messenger.send(msg); - } catch (RemoteException e) { - } - } - } - - @Override - public void onServiceDisconnected(ComponentName name) { - synchronized (mScreenshotLock) { - if (mScreenshotConnection != null) { - mContext.unbindService(mScreenshotConnection); - mScreenshotConnection = null; - mHandler.removeCallbacks(mScreenshotTimeout); - notifyScreenshotError(); - } - } - } - }; - if (mContext.bindServiceAsUser(serviceIntent, conn, - Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE, - UserHandle.CURRENT)) { - mScreenshotConnection = conn; - mHandler.postDelayed(mScreenshotTimeout, 10000); - } - } - } - - /** - * Notifies the screenshot service to show an error. - */ - private void notifyScreenshotError() { - // If the service process is killed, then ask it to clean up after itself - final ComponentName errorComponent = new ComponentName(SYSUI_PACKAGE, - SYSUI_SCREENSHOT_ERROR_RECEIVER); - Intent errorIntent = new Intent(Intent.ACTION_USER_PRESENT); - errorIntent.setComponent(errorComponent); - errorIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | - Intent.FLAG_RECEIVER_FOREGROUND); - mContext.sendBroadcastAsUser(errorIntent, UserHandle.CURRENT); - } /** {@inheritDoc} */ @Override |