1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.pip.phone; 18 19 import static android.app.AppOpsManager.MODE_ALLOWED; 20 import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE; 21 22 import android.app.AppOpsManager; 23 import android.app.AppOpsManager.OnOpChangedListener; 24 import android.app.IActivityManager; 25 import android.content.ComponentName; 26 import android.content.Context; 27 import android.content.pm.ApplicationInfo; 28 import android.content.pm.PackageManager.NameNotFoundException; 29 import android.os.Handler; 30 import android.util.Pair; 31 32 public class PipAppOpsListener { 33 private static final String TAG = PipAppOpsListener.class.getSimpleName(); 34 35 private Context mContext; 36 private Handler mHandler; 37 private IActivityManager mActivityManager; 38 private AppOpsManager mAppOpsManager; 39 40 private PipMotionHelper mMotionHelper; 41 42 private AppOpsManager.OnOpChangedListener mAppOpsChangedListener = new OnOpChangedListener() { 43 @Override 44 public void onOpChanged(String op, String packageName) { 45 try { 46 // Dismiss the PiP once the user disables the app ops setting for that package 47 final Pair<ComponentName, Integer> topPipActivityInfo = 48 PipUtils.getTopPinnedActivity(mContext, mActivityManager); 49 if (topPipActivityInfo.first != null) { 50 final ApplicationInfo appInfo = mContext.getPackageManager() 51 .getApplicationInfoAsUser(packageName, 0, topPipActivityInfo.second); 52 if (appInfo.packageName.equals(topPipActivityInfo.first.getPackageName()) && 53 mAppOpsManager.checkOpNoThrow(OP_PICTURE_IN_PICTURE, appInfo.uid, 54 packageName) != MODE_ALLOWED) { 55 mHandler.post(() -> mMotionHelper.dismissPip()); 56 } 57 } 58 } catch (NameNotFoundException e) { 59 // Unregister the listener if the package can't be found 60 unregisterAppOpsListener(); 61 } 62 } 63 }; 64 65 public PipAppOpsListener(Context context, IActivityManager activityManager, 66 PipMotionHelper motionHelper) { 67 mContext = context; 68 mHandler = new Handler(mContext.getMainLooper()); 69 mActivityManager = activityManager; 70 mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); 71 mMotionHelper = motionHelper; 72 } 73 74 public void onActivityPinned(String packageName) { 75 // Register for changes to the app ops setting for this package while it is in PiP 76 registerAppOpsListener(packageName); 77 } 78 79 public void onActivityUnpinned() { 80 // Unregister for changes to the previously PiP'ed package 81 unregisterAppOpsListener(); 82 } 83 84 private void registerAppOpsListener(String packageName) { 85 mAppOpsManager.startWatchingMode(OP_PICTURE_IN_PICTURE, packageName, 86 mAppOpsChangedListener); 87 } 88 89 private void unregisterAppOpsListener() { 90 mAppOpsManager.stopWatchingMode(mAppOpsChangedListener); 91 } 92 }