|
42 | 42 | import android.content.pm.PackageManager; |
43 | 43 | import android.content.pm.PackageManager.NameNotFoundException; |
44 | 44 | import android.content.pm.UserInfo; |
| 45 | +import android.database.ContentObserver; |
45 | 46 | import android.net.Uri; |
46 | 47 | import android.os.Binder; |
47 | 48 | import android.os.Handler; |
@@ -180,6 +181,12 @@ public class ClipboardService extends SystemService { |
180 | 181 |
|
181 | 182 | private final SparseArray<PerUserClipboard> mClipboards = new SparseArray<>(); |
182 | 183 |
|
| 184 | + private SettingsObserver mSettingsObserver; |
| 185 | + private int mShouldToast; |
| 186 | + private Handler mHandler; |
| 187 | + private String mToastMessage; |
| 188 | + private Toast mToast; |
| 189 | + |
183 | 190 | /** |
184 | 191 | * Instantiates the clipboard. |
185 | 192 | */ |
@@ -215,6 +222,30 @@ public void onHostClipboardUpdated(String contents){ |
215 | 222 | mHostMonitorThread = new Thread(mHostClipboardMonitor); |
216 | 223 | mHostMonitorThread.start(); |
217 | 224 | } |
| 225 | + |
| 226 | + mHandler = new Handler(); |
| 227 | + |
| 228 | + mSettingsObserver = new SettingsObserver(); |
| 229 | + mSettingsObserver.update(); |
| 230 | + } |
| 231 | + |
| 232 | + private class SettingsObserver extends ContentObserver { |
| 233 | + SettingsObserver() { |
| 234 | + super(mHandler); |
| 235 | + getContext().getContentResolver().registerContentObserver(Settings.System.getUriFor( |
| 236 | + Settings.System.CLIPBOARD_TOAST_INFO), |
| 237 | + false, this, UserHandle.USER_ALL); |
| 238 | + } |
| 239 | + |
| 240 | + @Override |
| 241 | + public void onChange(boolean selfChange) { |
| 242 | + update(); |
| 243 | + } |
| 244 | + |
| 245 | + public void update() { |
| 246 | + mShouldToast = Settings.System.getIntForUser(getContext().getContentResolver(), |
| 247 | + Settings.System.CLIPBOARD_TOAST_INFO, 0, UserHandle.USER_CURRENT); |
| 248 | + } |
218 | 249 | } |
219 | 250 |
|
220 | 251 | @Override |
@@ -743,43 +774,70 @@ private final void revokeUris(PerUserClipboard clipboard) { |
743 | 774 | } |
744 | 775 | } |
745 | 776 |
|
| 777 | + private Runnable mRunnable = new Runnable() { |
| 778 | + @Override |
| 779 | + public void run() { |
| 780 | + String msg = mToastMessage; |
| 781 | + |
| 782 | + if (msg.isEmpty()) |
| 783 | + return; |
| 784 | + |
| 785 | + if (mToast != null) { |
| 786 | + mToast.cancel(); |
| 787 | + mToast = null; |
| 788 | + } |
| 789 | + mToast = Toast.makeText(getContext(), msg, Toast.LENGTH_SHORT); |
| 790 | + mToast.show(); |
| 791 | + } |
| 792 | + }; |
| 793 | + |
746 | 794 | private boolean clipboardAccessAllowed(int op, String callingPackage, int uid, |
747 | 795 | @UserIdInt int userId) { |
748 | | - final String prefName = "show_clipboard_toast"; |
749 | | - boolean shouldToast = Settings.System.getInt(getContext().getContentResolver(), prefName, 0) == 1; |
750 | | - if (shouldToast) { |
751 | | - // create toast that app has tried to access clipboard |
752 | | - final PackageManager pm = getContext().getPackageManager(); |
753 | | - ApplicationInfo ai; |
| 796 | + Context context = getContext(); |
| 797 | + String applicationName = "(unknown)"; |
| 798 | + mToastMessage = ""; |
| 799 | + |
| 800 | + if (mShouldToast > 0) { |
| 801 | + final PackageManager pm = context.getPackageManager(); |
| 802 | + ApplicationInfo ai = null; |
754 | 803 | try { |
755 | 804 | ai = pm.getApplicationInfo(callingPackage, 0); |
| 805 | + if (ai != null) applicationName = pm.getApplicationLabel(ai).toString(); |
756 | 806 | } catch (final NameNotFoundException e) { |
757 | | - ai = null; |
| 807 | + // Do nothing |
758 | 808 | } |
759 | | - final String applicationName = (String) (ai != null ? pm.getApplicationLabel(ai) : "(unknown)"); |
760 | | - Handler handler = new Handler(Looper.getMainLooper()); |
761 | | - handler.post(new Runnable() { |
762 | | - @Override |
763 | | - public void run() { |
764 | | - Toast.makeText(getContext(), applicationName + " tried to access the clipboard", Toast.LENGTH_SHORT).show(); |
765 | | - } |
766 | | - }); |
767 | 809 | } |
| 810 | + |
768 | 811 | // Check the AppOp. |
769 | 812 | if (mAppOps.noteOp(op, uid, callingPackage) != AppOpsManager.MODE_ALLOWED) { |
| 813 | + if (mShouldToast > 0) { |
| 814 | + mToastMessage = String.format(context.getResources().getString(com.android.internal.R.string.app_clipboard_access_denied), |
| 815 | + applicationName); |
| 816 | + mHandler.post(mRunnable); |
| 817 | + } |
770 | 818 | return false; |
771 | 819 | } |
772 | 820 | // Shell can access the clipboard for testing purposes. |
773 | 821 | if (mPm.checkPermission(android.Manifest.permission.READ_CLIPBOARD_IN_BACKGROUND, |
774 | 822 | callingPackage) == PackageManager.PERMISSION_GRANTED) { |
| 823 | + if (mShouldToast > 1) { |
| 824 | + mToastMessage = String.format(context.getResources().getString(com.android.internal.R.string.app_clipboard_access_granted), |
| 825 | + applicationName); |
| 826 | + mHandler.post(mRunnable); |
| 827 | + } |
775 | 828 | return true; |
776 | 829 | } |
777 | 830 | // The default IME is always allowed to access the clipboard. |
778 | | - String defaultIme = Settings.Secure.getStringForUser(getContext().getContentResolver(), |
| 831 | + String defaultIme = Settings.Secure.getStringForUser(context.getContentResolver(), |
779 | 832 | Settings.Secure.DEFAULT_INPUT_METHOD, userId); |
780 | 833 | if (!TextUtils.isEmpty(defaultIme)) { |
781 | 834 | final String imePkg = ComponentName.unflattenFromString(defaultIme).getPackageName(); |
782 | 835 | if (imePkg.equals(callingPackage)) { |
| 836 | + if (mShouldToast > 1) { |
| 837 | + mToastMessage = String.format(context.getResources().getString(com.android.internal.R.string.app_clipboard_access_granted), |
| 838 | + applicationName); |
| 839 | + mHandler.post(mRunnable); |
| 840 | + } |
783 | 841 | return true; |
784 | 842 | } |
785 | 843 | } |
@@ -816,9 +874,23 @@ public void run() { |
816 | 874 | + ", application is not in focus neither is a system service for " |
817 | 875 | + "user " + userId); |
818 | 876 | } |
| 877 | + if (mShouldToast > 0 && allowed) { |
| 878 | + mToastMessage = String.format(context.getResources().getString(com.android.internal.R.string.app_clipboard_access_granted), |
| 879 | + applicationName); |
| 880 | + mHandler.post(mRunnable); |
| 881 | + } else if (mShouldToast > 0 && !allowed) { |
| 882 | + mToastMessage = String.format(context.getResources().getString(com.android.internal.R.string.app_clipboard_access_denied), |
| 883 | + applicationName); |
| 884 | + mHandler.post(mRunnable); |
| 885 | + } |
819 | 886 | return allowed; |
820 | 887 | case AppOpsManager.OP_WRITE_CLIPBOARD: |
821 | 888 | // Writing is allowed without focus. |
| 889 | + if (mShouldToast > 0) { |
| 890 | + mToastMessage = String.format(context.getResources().getString(com.android.internal.R.string.app_clipboard_access_granted), |
| 891 | + applicationName); |
| 892 | + mHandler.post(mRunnable); |
| 893 | + } |
822 | 894 | return true; |
823 | 895 | default: |
824 | 896 | throw new IllegalArgumentException("Unknown clipboard appop " + op); |
|
0 commit comments