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

Commit cb2f6469 authored by Selim Cinek's avatar Selim Cinek Committed by android-build-merger
Browse files

Merge "Implemented dynamic privacy for redacted lockscreens" into qt-dev

am: 07e64c8b

Change-Id: I93a79abae7a5477c3a95cd6cab2230adeb674ca9
parents dd42aaa3 07e64c8b
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -33,6 +33,14 @@ public interface NotificationLockscreenUserManager {
     */
    boolean isLockscreenPublicMode(int userId);

    /**
     * Does a user require a separate work challenge? If so, the unlock mechanism is decoupled from
     * the current user and has to be solved separately.
     */
    default boolean needsSeparateWorkChallenge(int userId) {
        return false;
    }

    void setUpWithPresenter(NotificationPresenter presenter);

    int getCurrentUserId();
+11 −2
Original line number Diff line number Diff line
@@ -77,6 +77,7 @@ public class NotificationLockscreenUserManagerImpl implements

    private final DevicePolicyManager mDevicePolicyManager;
    private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray();
    private final SparseBooleanArray mUsersWithSeperateWorkChallenge = new SparseBooleanArray();
    private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
    private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
    private final UserManager mUserManager;
@@ -394,6 +395,11 @@ public class NotificationLockscreenUserManagerImpl implements
        return mLockscreenPublicMode.get(userId, false);
    }

    @Override
    public boolean needsSeparateWorkChallenge(int userId) {
        return mUsersWithSeperateWorkChallenge.get(userId, false);
    }

    /**
     * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
     * "public" (secure & locked) mode?
@@ -493,20 +499,23 @@ public class NotificationLockscreenUserManagerImpl implements
        //   - device keyguard is shown in secure mode;
        //   - profile is locked with a work challenge.
        SparseArray<UserInfo> currentProfiles = getCurrentProfiles();
        mUsersWithSeperateWorkChallenge.clear();
        for (int i = currentProfiles.size() - 1; i >= 0; i--) {
            final int userId = currentProfiles.valueAt(i).id;
            boolean isProfilePublic = devicePublic;
            boolean needsSeparateChallenge = mLockPatternUtils.isSeparateProfileChallengeEnabled(
                    userId);
            if (!devicePublic && userId != getCurrentUserId()) {
                // We can't rely on KeyguardManager#isDeviceLocked() for unified profile challenge
                // due to a race condition where this code could be called before
                // TrustManagerService updates its internal records, resulting in an incorrect
                // state being cached in mLockscreenPublicMode. (b/35951989)
                if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
                        && isSecure(userId)) {
                if (needsSeparateChallenge && isSecure(userId)) {
                    isProfilePublic = mKeyguardManager.isDeviceLocked(userId);
                }
            }
            setLockscreenPublicMode(isProfilePublic, userId);
            mUsersWithSeperateWorkChallenge.put(userId, needsSeparateChallenge);
        }
    }

+22 −6
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar;
import android.content.Context;
import android.content.res.Resources;
import android.os.Trace;
import android.os.UserHandle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
@@ -26,6 +27,7 @@ import android.view.ViewGroup;
import com.android.systemui.R;
import com.android.systemui.bubbles.BubbleData;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -33,6 +35,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.UnlockMethodCache;

import java.util.ArrayList;
import java.util.HashMap;
@@ -52,7 +55,7 @@ import dagger.Lazy;
 * notifications that might affect their display.
 */
@Singleton
public class NotificationViewHierarchyManager {
public class NotificationViewHierarchyManager implements DynamicPrivacyController.Listener {
    private static final String TAG = "NotificationViewHierarchyManager";

    //TODO: change this top <Entry, List<Entry>>?
@@ -76,6 +79,7 @@ public class NotificationViewHierarchyManager {
     */
    private final boolean mAlwaysExpandNonGroupedNotification;
    private final BubbleData mBubbleData;
    private final DynamicPrivacyController mDynamicPrivacyController;

    private NotificationPresenter mPresenter;
    private NotificationListContainer mListContainer;
@@ -88,7 +92,8 @@ public class NotificationViewHierarchyManager {
            StatusBarStateController statusBarStateController,
            NotificationEntryManager notificationEntryManager,
            Lazy<ShadeController> shadeController,
            BubbleData bubbleData) {
            BubbleData bubbleData,
            DynamicPrivacyController privacyController) {
        mLockscreenUserManager = notificationLockscreenUserManager;
        mGroupManager = groupManager;
        mVisualStabilityManager = visualStabilityManager;
@@ -99,6 +104,8 @@ public class NotificationViewHierarchyManager {
        mAlwaysExpandNonGroupedNotification =
                res.getBoolean(R.bool.config_alwaysExpandNonGroupedNotifications);
        mBubbleData = bubbleData;
        mDynamicPrivacyController = privacyController;
        privacyController.addListener(this);
    }

    public void setUpWithPresenter(NotificationPresenter presenter,
@@ -130,15 +137,20 @@ public class NotificationViewHierarchyManager {
            // Display public version of the notification if we need to redact.
            // TODO: This area uses a lot of calls into NotificationLockscreenUserManager.
            // We can probably move some of this code there.
            boolean devicePublic = mLockscreenUserManager.isLockscreenPublicMode(
                    mLockscreenUserManager.getCurrentUserId());
            int currentUserId = mLockscreenUserManager.getCurrentUserId();
            boolean devicePublic = mLockscreenUserManager.isLockscreenPublicMode(currentUserId);
            boolean userPublic = devicePublic
                    || mLockscreenUserManager.isLockscreenPublicMode(userId);
            if (userPublic && mDynamicPrivacyController.isDynamicallyUnlocked()
                    && (userId == currentUserId || userId == UserHandle.USER_ALL
                    || !mLockscreenUserManager.needsSeparateWorkChallenge(userId))) {
                userPublic = false;
            }
            boolean needsRedaction = mLockscreenUserManager.needsRedaction(ent);
            boolean sensitive = userPublic && needsRedaction;
            boolean deviceSensitive = devicePublic
                    && !mLockscreenUserManager.userAllowsPrivateNotificationsInPublic(
                    mLockscreenUserManager.getCurrentUserId());
                    currentUserId);
            ent.getRow().setSensitive(sensitive, deviceSensitive);
            ent.getRow().setNeedsRedaction(needsRedaction);
            if (mGroupManager.isChildInGroupWithSummary(ent.notification)) {
@@ -153,7 +165,6 @@ public class NotificationViewHierarchyManager {
            } else {
                toShow.add(ent.getRow());
            }

        }

        ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>();
@@ -406,4 +417,9 @@ public class NotificationViewHierarchyManager {
        Trace.endSection();
        Trace.endSection();
    }

    @Override
    public void onDynamicPrivacyChanged() {
        updateNotificationViews();
    }
}
+90 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.systemui.statusbar.notification;

import android.content.Context;
import android.util.ArraySet;

import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.phone.UnlockMethodCache;

import javax.inject.Inject;
import javax.inject.Singleton;

/**
 * A controller which dynamically controls the visibility of Notification content
 */
@Singleton
public class DynamicPrivacyController implements UnlockMethodCache.OnUnlockMethodChangedListener {

    private final UnlockMethodCache mUnlockMethodCache;
    private final NotificationLockscreenUserManager mLockscreenUserManager;
    private ArraySet<Listener> mListeners = new ArraySet<>();

    private boolean mLastDynamicUnlocked;
    private boolean mCacheInvalid;

    @Inject
    DynamicPrivacyController(Context context,
            NotificationLockscreenUserManager notificationLockscreenUserManager) {
        this(notificationLockscreenUserManager, UnlockMethodCache.getInstance(context));
    }

    @VisibleForTesting
    DynamicPrivacyController(NotificationLockscreenUserManager notificationLockscreenUserManager,
            UnlockMethodCache unlockMethodCache) {
        mLockscreenUserManager = notificationLockscreenUserManager;
        mUnlockMethodCache = unlockMethodCache;
        mUnlockMethodCache.addListener(this);
        mLastDynamicUnlocked = isDynamicallyUnlocked();
    }

    @Override
    public void onUnlockMethodStateChanged() {
        if (isDynamicPrivacyEnabled()) {
            // We only want to notify our listeners if dynamic privacy is actually active
            boolean dynamicallyUnlocked = isDynamicallyUnlocked();
            if (dynamicallyUnlocked != mLastDynamicUnlocked || mCacheInvalid) {
                mLastDynamicUnlocked = dynamicallyUnlocked;
                for (Listener listener : mListeners) {
                    listener.onDynamicPrivacyChanged();
                }
            }
            mCacheInvalid = false;
        } else {
            mCacheInvalid = true;
        }
    }

    private boolean isDynamicPrivacyEnabled() {
        return !mLockscreenUserManager.shouldHideNotifications(
                mLockscreenUserManager.getCurrentUserId());
    }

    public boolean isDynamicallyUnlocked() {
        return mUnlockMethodCache.canSkipBouncer() && isDynamicPrivacyEnabled();
    }

    public void addListener(Listener listener) {
        mListeners.add(listener);
    }

    public interface Listener {
        void onDynamicPrivacyChanged();
    }
}
 No newline at end of file
+17 −3
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -153,7 +154,8 @@ import javax.inject.Named;
 * A layout which handles a dynamic amount of notifications and presents them in a scrollable stack.
 */
public class NotificationStackScrollLayout extends ViewGroup implements ScrollAdapter,
        NotificationListContainer, ConfigurationListener, Dumpable {
        NotificationListContainer, ConfigurationListener, Dumpable,
        DynamicPrivacyController.Listener {

    public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
    private static final String TAG = "StackScroller";
@@ -498,6 +500,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
     * If the {@link NotificationShelf} should be visible when dark.
     */
    private boolean mShowDarkShelf;
    private boolean mAnimateBottomOnLayout;

    @Inject
    public NotificationStackScrollLayout(
@@ -505,7 +508,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
            AttributeSet attrs,
            @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
            NotificationRoundnessManager notificationRoundnessManager,
            AmbientPulseManager ambientPulseManager) {
            AmbientPulseManager ambientPulseManager,
            DynamicPrivacyController dynamicPrivacyController) {
        super(context, attrs, 0, 0);
        Resources res = getResources();

@@ -576,6 +580,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
                }
            }
        });
        dynamicPrivacyController.addListener(this);
    }

    private void updateDismissRtlSetting(boolean dismissRtl) {
@@ -3165,7 +3170,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd

        if (mAnimationsEnabled && mIsExpanded) {
            mAnimateNextBackgroundTop = firstChild != previousFirstChild;
            mAnimateNextBackgroundBottom = lastChild != previousLastChild;
            mAnimateNextBackgroundBottom = lastChild != previousLastChild || mAnimateBottomOnLayout;
            mAnimateNextSectionBoundsChange = sectionViewsChanged;
        } else {
            mAnimateNextBackgroundTop = false;
@@ -3174,6 +3179,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
        }
        mAmbientState.setLastVisibleBackgroundChild(lastChild);
        mRoundnessManager.updateRoundedChildren(mSections);
        mAnimateBottomOnLayout = false;
        invalidate();
    }

@@ -5714,6 +5720,14 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
        }
    }

    @Override
    public void onDynamicPrivacyChanged() {
        if (mIsExpanded) {
            // The bottom might change because we're using the final actual height of the view
            mAnimateBottomOnLayout = true;
        }
    }

    /**
     * A listener that is notified when the empty space below the notifications is clicked on
     */
Loading