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

Commit 001aae8d authored by Derek Jedral's avatar Derek Jedral Committed by Android (Google) Code Review
Browse files

Merge changes from topic "au-initial-commit-master"

* changes:
  Update text when Active Unlock is enabled.
  Update tile summary from ContentProvider.
  Add Active Unlock tile under face & fingerprint
  Add ActiveUnlock check when picking preference
parents 664ffc63 9134f24f
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -6802,6 +6802,9 @@
    <!-- Search keyword for biometric settings. [CHAR_LIMIT=NONE]-->
    <!-- Search keyword for biometric settings. [CHAR_LIMIT=NONE]-->
    <string name="keywords_biometric_settings">face, fingerprint, add fingerprint</string>
    <string name="keywords_biometric_settings">face, fingerprint, add fingerprint</string>
    <!-- Search keyword for active unlock settings. [CHAR_LIMIT=NONE]-->
    <string name="keywords_active_unlock_settings">watch unlock, add watch unlock</string>
    <!-- Search keywords for adaptive brightness setting [CHAR LIMIT=NONE]-->
    <!-- Search keywords for adaptive brightness setting [CHAR LIMIT=NONE]-->
    <string name="keywords_display_auto_brightness">dim screen, touchscreen, battery, smart brightness, dynamic brightness, Auto brightness</string>
    <string name="keywords_display_auto_brightness">dim screen, touchscreen, battery, smart brightness, dynamic brightness, Auto brightness</string>
+8 −1
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@
    android:title="@string/security_settings_biometric_preference_title">
    android:title="@string/security_settings_biometric_preference_title">


    <com.android.settingslib.widget.TopIntroPreference
    <com.android.settingslib.widget.TopIntroPreference
        android:key="biometric_intro"
        android:title="@string/biometric_settings_intro" />
        android:title="@string/biometric_settings_intro" />


    <PreferenceCategory
    <PreferenceCategory
@@ -40,6 +41,12 @@
            settings:keywords="@string/keywords_fingerprint_settings"
            settings:keywords="@string/keywords_fingerprint_settings"
            settings:controller="com.android.settings.biometrics.combination.BiometricFingerprintStatusPreferenceController" />
            settings:controller="com.android.settings.biometrics.combination.BiometricFingerprintStatusPreferenceController" />


        <com.android.settingslib.RestrictedPreference
            android:key="biometric_active_unlock_settings"
            android:title="@string/security_settings_activeunlock_preference_title"
            android:summary="@string/summary_placeholder"
            settings:keywords="@string/keywords_active_unlock_settings"
            settings:controller="com.android.settings.biometrics.activeunlock.ActiveUnlockStatusPreferenceController" />
    </PreferenceCategory>
    </PreferenceCategory>


    <PreferenceCategory
    <PreferenceCategory
+38 −1
Original line number Original line Diff line number Diff line
@@ -25,6 +25,7 @@ import androidx.preference.Preference;


import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.Utils;
import com.android.settings.Utils;
import com.android.settings.biometrics.activeunlock.ActiveUnlockStatusUtils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.overlay.FeatureFactory;


@@ -37,12 +38,18 @@ public abstract class BiometricStatusPreferenceController extends BasePreference
    protected final int mProfileChallengeUserId;
    protected final int mProfileChallengeUserId;


    private final BiometricNavigationUtils mBiometricNavigationUtils;
    private final BiometricNavigationUtils mBiometricNavigationUtils;
    private final ActiveUnlockStatusUtils mActiveUnlockStatusUtils;


    /**
    /**
     * @return true if the manager is not null and the hardware is detected.
     * @return true if the controller should be shown exclusively.
     */
     */
    protected abstract boolean isDeviceSupported();
    protected abstract boolean isDeviceSupported();


    /**
     * @return true if the manager is not null and the hardware is detected.
     */
    protected abstract boolean isHardwareSupported();

    /**
    /**
     * @return the summary text.
     * @return the summary text.
     */
     */
@@ -61,13 +68,21 @@ public abstract class BiometricStatusPreferenceController extends BasePreference
                .getLockPatternUtils(context);
                .getLockPatternUtils(context);
        mProfileChallengeUserId = Utils.getManagedProfileId(mUm, mUserId);
        mProfileChallengeUserId = Utils.getManagedProfileId(mUm, mUserId);
        mBiometricNavigationUtils = new BiometricNavigationUtils(getUserId());
        mBiometricNavigationUtils = new BiometricNavigationUtils(getUserId());
        mActiveUnlockStatusUtils = new ActiveUnlockStatusUtils(context);
    }
    }


    @Override
    @Override
    public int getAvailabilityStatus() {
    public int getAvailabilityStatus() {
        if (mActiveUnlockStatusUtils.isAvailable()) {
            return getAvailabilityStatusWithWorkProfileCheck();
        }
        if (!isDeviceSupported()) {
        if (!isDeviceSupported()) {
            return UNSUPPORTED_ON_DEVICE;
            return UNSUPPORTED_ON_DEVICE;
        }
        }
        return getAvailabilityFromUserSupported();
    }

    private int getAvailabilityFromUserSupported() {
        if (isUserSupported()) {
        if (isUserSupported()) {
            return AVAILABLE;
            return AVAILABLE;
        } else {
        } else {
@@ -75,6 +90,21 @@ public abstract class BiometricStatusPreferenceController extends BasePreference
        }
        }
    }
    }


    // Since this code is flag guarded by mActiveUnlockStatusUtils.isAvailable(), we don't need to
    // do another check here.
    private int getAvailabilityStatusWithWorkProfileCheck() {
        if (!isHardwareSupported()) {
            // no hardware, never show
            return UNSUPPORTED_ON_DEVICE;
        }
        if (!isDeviceSupported() && isWorkProfileController()) {
            // hardware supported but work profile, don't show
            return UNSUPPORTED_ON_DEVICE;
        }
        // hardware supported, not work profile, active unlock enabled
        return getAvailabilityFromUserSupported();
    }

    @Override
    @Override
    public void updateState(Preference preference) {
    public void updateState(Preference preference) {
        if (!isAvailable()) {
        if (!isAvailable()) {
@@ -105,4 +135,11 @@ public abstract class BiometricStatusPreferenceController extends BasePreference
    protected boolean isUserSupported() {
    protected boolean isUserSupported() {
        return true;
        return true;
    }
    }

    /**
     * Returns true if the controller controls is used for work profile.
     */
    protected boolean isWorkProfileController() {
        return false;
    }
}
}
+145 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2023 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.biometrics.activeunlock;

import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.Nullable;

import com.android.settingslib.utils.ThreadUtils;

/** Listens to updates from the content provider and fetches the latest value. */
public class ActiveUnlockContentListener {

    /** Callback interface for updates to values from the ContentProvider. */
    public interface OnContentChangedListener {
        /**
         * Called when the content observer has updated.
         *
         * @param newValue the new value retrieved from the ContentProvider.
         **/
        void onContentChanged(@Nullable String newValue);
    }

    private static final String CONTENT_PROVIDER_PATH = "getSummary";

    private final Context mContext;
    private final OnContentChangedListener mContentChangedListener;
    @Nullable private final Uri mUri;
    private final String mLogTag;
    private final String mMethodName;
    private final String mContentKey;
    @Nullable private String mContent;
    private boolean mSubscribed = false;
    private ContentObserver mContentObserver =
            new ContentObserver(new Handler(Looper.getMainLooper())) {
                @Override
                public void onChange(boolean selfChange) {
                    getContentFromUri();
                }
            };

    ActiveUnlockContentListener(
            Context context,
            OnContentChangedListener listener,
            String logTag,
            String methodName,
            String contentKey) {
        mContext = context;
        mContentChangedListener = listener;
        mLogTag = logTag;
        mMethodName = methodName;
        mContentKey = contentKey;
        String authority = new ActiveUnlockStatusUtils(mContext).getAuthority();
        if (authority != null) {
            mUri = new Uri.Builder()
                    .scheme(ContentResolver.SCHEME_CONTENT)
                    .authority(authority)
                    .appendPath(CONTENT_PROVIDER_PATH)
                    .build();
        } else {
            mUri = null;
        }

    }

    /** Starts listening for updates from the ContentProvider, and fetches the current value. */
    public synchronized void subscribe() {
        if (mSubscribed && mUri != null) {
            return;
        }
        mSubscribed = true;
        mContext.getContentResolver().registerContentObserver(
                mUri, true /* notifyForDescendants */, mContentObserver);
        ThreadUtils.postOnBackgroundThread(
                () -> {
                    getContentFromUri();
                });
    }

    /** Stops listening for updates from the ContentProvider. */
    public synchronized void unsubscribe() {
        if (!mSubscribed && mUri != null) {
            return;
        }
        mSubscribed = false;
        mContext.getContentResolver().unregisterContentObserver(mContentObserver);
    }

    /** Retrieves the most recently fetched value from the ContentProvider. */
    @Nullable
    public String getContent() {
        return mContent;
    }

    private void getContentFromUri() {
        if (mUri == null) {
            Log.e(mLogTag, "Uri null when trying to fetch content");
            return;
        }
        ContentResolver contentResolver = mContext.getContentResolver();
        ContentProviderClient client = contentResolver.acquireContentProviderClient(mUri);
        Bundle bundle;
        try {
            bundle = client.call(mMethodName, null /* arg */, null /* extras */);
        } catch (RemoteException e) {
            Log.e(mLogTag, "Failed to call contentProvider", e);
            return;
        } finally {
            client.close();
        }
        if (bundle == null) {
            Log.e(mLogTag, "Null bundle returned from contentProvider");
            return;
        }
        String newValue = bundle.getString(mContentKey);
        if (!TextUtils.equals(mContent, newValue)) {
            mContent = newValue;
            mContentChangedListener.onContentChanged(mContent);
        }
    }
}
+48 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2023 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.biometrics.activeunlock;

import android.content.Context;

/** Listens to device name updates from the content provider and fetches the latest value. */
public class ActiveUnlockDeviceNameListener  {
    private static final String TAG = "ActiveUnlockDeviceNameListener";
    private static final String METHOD_NAME = "getDeviceName";
    private static final String DEVICE_NAME_KEY = "com.android.settings.active_unlock.device_name";

    private final ActiveUnlockContentListener mActiveUnlockContentListener;
    public ActiveUnlockDeviceNameListener(
            Context context, ActiveUnlockContentListener.OnContentChangedListener listener) {
        mActiveUnlockContentListener = new ActiveUnlockContentListener(
            context, listener, TAG, METHOD_NAME, DEVICE_NAME_KEY);
    }

    /** Returns whether a device is enrolled in Active Unlock. */
    public boolean hasEnrolled() {
        return mActiveUnlockContentListener.getContent() != null;
    }

    /** Subscribes to device name updates. */
    public void subscribe() {
        mActiveUnlockContentListener.subscribe();
    }

    /** Unsubscribes from device name updates. */
    public void unsubscribe() {
        mActiveUnlockContentListener.unsubscribe();
    }
}
Loading