Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e53d1cae authored by Svet Ganov's avatar Svet Ganov
Browse files

Use new no overlay flag instead app ops

Test: updated DrawOverlayDetailsTest passes

bug:66936547

Change-Id: I7c17c95a2b44fd2ffd593a6eb03a16be034e9192
parent 17acd3d1
Loading
Loading
Loading
Loading
+10 −22
Original line number Diff line number Diff line
@@ -29,12 +29,13 @@ import android.support.v7.preference.Preference.OnPreferenceChangeListener;
import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.util.Log;

import android.view.Window;
import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
import com.android.settings.applications.AppStateOverlayBridge.OverlayState;
import com.android.settings.core.TouchOverlayManager;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.applications.ApplicationsState.AppEntry;

@@ -60,8 +61,6 @@ public class DrawOverlayDetails extends AppInfoWithHeader implements OnPreferenc
    private Intent mSettingsIntent;
    private OverlayState mOverlayState;

    private TouchOverlayManager mTouchOverlayManager;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
@@ -69,7 +68,6 @@ public class DrawOverlayDetails extends AppInfoWithHeader implements OnPreferenc
        Context context = getActivity();
        mOverlayBridge = new AppStateOverlayBridge(context, mState, null);
        mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
        mTouchOverlayManager = new TouchOverlayManager(context);

        // find preferences
        addPreferencesFromResource(R.xml.app_ops_permissions_details);
@@ -92,17 +90,17 @@ public class DrawOverlayDetails extends AppInfoWithHeader implements OnPreferenc
    }

    @Override
    public void onStart() {
        super.onStart();

        mTouchOverlayManager.setOverlayAllowed(false);
    public void onResume() {
        super.onResume();
        getActivity().getWindow().addFlags(
                WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
    }

    @Override
    public void onStop() {
        super.onStop();

        mTouchOverlayManager.setOverlayAllowed(true);
    public void onPause() {
        getActivity().getWindow().clearFlags(
                WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
        super.onPause();
    }

    @Override
@@ -153,16 +151,6 @@ public class DrawOverlayDetails extends AppInfoWithHeader implements OnPreferenc
                .getMetricsFeatureProvider().action(getContext(), logCategory, packageName);
    }

    private boolean canDrawOverlay(String pkgName) {
        int result = mAppOpsManager.noteOpNoThrow(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
                mPackageInfo.applicationInfo.uid, pkgName);
        if (result == AppOpsManager.MODE_ALLOWED) {
            return true;
        }

        return false;
    }

    @Override
    protected boolean refreshUi() {
        mOverlayState = mOverlayBridge.getOverlayInfo(mPackageName,
+0 −40
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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
 */

package com.android.settings.core;

import android.app.AppOpsManager;
import android.content.Context;
import android.os.Binder;
import android.os.IBinder;

public class TouchOverlayManager {

    private final Context mContext;
    private final IBinder mToken = new Binder();

    public TouchOverlayManager(Context context) {
        mContext = context;
    }

    public void setOverlayAllowed(boolean allowed) {
        final AppOpsManager aom = mContext.getSystemService(AppOpsManager.class);
        if (aom != null) {
            aom.setUserRestriction(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, !allowed, mToken);
            aom.setUserRestriction(AppOpsManager.OP_TOAST_WINDOW, !allowed, mToken);
        }
    }
}
+15 −17
Original line number Diff line number Diff line
@@ -35,15 +35,13 @@ import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.os.Bundle;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.SettingsStringUtil;
import android.util.Slog;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;

import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
import com.android.settings.R;
import com.android.settings.core.TouchOverlayManager;

/** @hide */
public class NotificationAccessConfirmationActivity extends Activity
@@ -54,14 +52,12 @@ public class NotificationAccessConfirmationActivity extends Activity

    private int mUserId;
    private ComponentName mComponentName;
    private TouchOverlayManager mTouchOverlayManager;
    private NotificationManager mNm;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mTouchOverlayManager = new TouchOverlayManager(this);
        mNm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        mComponentName = getIntent().getParcelableExtra(EXTRA_COMPONENT_NAME);
@@ -84,6 +80,20 @@ public class NotificationAccessConfirmationActivity extends Activity
                .installContent(p);
    }

    @Override
    public void onResume() {
        super.onResume();
        getWindow().addFlags(
                WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
    }

    @Override
    public void onPause() {
        getWindow().clearFlags(
                WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
        super.onPause();
    }

    private void onAllow() {
        String requiredPermission = Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
        try {
@@ -121,16 +131,4 @@ public class NotificationAccessConfirmationActivity extends Activity
            finish();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        mTouchOverlayManager.setOverlayAllowed(false);
    }

    @Override
    protected void onPause() {
        super.onPause();
        mTouchOverlayManager.setOverlayAllowed(true);
    }
}
+31 −23
Original line number Diff line number Diff line
@@ -19,52 +19,59 @@ package com.android.settings.applications;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.nullable;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;

import android.app.Activity;
import android.content.Context;

import android.view.Window;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settings.core.TouchOverlayManager;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowPreferenceFragment;

import com.android.settings.testutils.shadow.ShadowAppInfoBase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.util.ReflectionHelpers;

@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class DrawOverlayDetailsTest {

    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
    private Context mContext;
    private Activity mActivity;

    @Mock
    private Window mWindow;

    private FakeFeatureFactory mFeatureFactory;
    private DrawOverlayDetails mFragment;

    @Mock
    private TouchOverlayManager mTouchOverlayManager;
    @Spy
    private DrawOverlayDetails mFragment;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        FakeFeatureFactory.setupForTest(mContext);
        mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);

        mFragment = new DrawOverlayDetails();
        ReflectionHelpers.setField(mFragment, "mTouchOverlayManager", mTouchOverlayManager);
        FakeFeatureFactory.setupForTest(mActivity);
        mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mActivity);
    }

    @Test
    public void logSpecialPermissionChange() {
        mFragment.onAttach(ShadowApplication.getInstance().getApplicationContext());
        when(mFragment.getContext()).thenReturn(
                ShadowApplication.getInstance().getApplicationContext());

        mFragment.logSpecialPermissionChange(true, "app");
        verify(mFeatureFactory.metricsFeatureProvider).action(nullable(Context.class),
                eq(MetricsProto.MetricsEvent.APP_SPECIAL_PERMISSION_APPDRAW_ALLOW), eq("app"));
@@ -75,16 +82,17 @@ public class DrawOverlayDetailsTest {
    }

    @Test
    @Config(shadows = ShadowPreferenceFragment.class)
    public void onStart_disableOverlay() {
        mFragment.onStart();
        verify(mTouchOverlayManager).setOverlayAllowed(false);
    }
    @Config(shadows = {ShadowAppInfoBase.class})
    public void hideNonSystemOverlaysWhenResumed() {
        when(mFragment.getActivity()).thenReturn(mActivity);
        when(mActivity.getWindow()).thenReturn(mWindow);

    @Test
    @Config(shadows = ShadowPreferenceFragment.class)
    public void onStop_enableOverlay() {
        mFragment.onStop();
        verify(mTouchOverlayManager).setOverlayAllowed(true);
        mFragment.onResume();
        mFragment.onPause();

        InOrder inOrder = Mockito.inOrder(mWindow);
        inOrder.verify(mWindow).addFlags(PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
        inOrder.verify(mWindow).clearFlags(PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
        inOrder.verifyNoMoreInteractions();
    }
}
+5 −5
Original line number Diff line number Diff line
@@ -16,20 +16,20 @@

package com.android.settings.testutils.shadow;

import android.support.v14.preference.PreferenceFragment;
import com.android.settings.applications.AppInfoBase;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;

@Implements(PreferenceFragment.class)
public class ShadowPreferenceFragment {
@Implements(AppInfoBase.class)
public class ShadowAppInfoBase {

    @Implementation
    public void onStart() {
    public void onResume() {
        // No-op.
    }

    @Implementation
    public void onStop() {
    public void onPause() {
        // No-op.
    }
}