/* * Copyright (C) 2020 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.keyguard; import android.util.Log; import android.view.LayoutInflater; import androidx.annotation.Nullable; import androidx.asynclayoutinflater.view.AsyncLayoutInflater; import com.android.internal.annotations.VisibleForTesting; import com.android.keyguard.KeyguardInputViewController.Factory; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.keyguard.dagger.KeyguardBouncerScope; import com.android.systemui.R; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.util.ViewController; import java.util.ArrayList; import java.util.List; import javax.inject.Inject; /** * Controller for a {@link KeyguardSecurityViewFlipper}. */ @KeyguardBouncerScope public class KeyguardSecurityViewFlipperController extends ViewController { private static final boolean DEBUG = KeyguardConstants.DEBUG; private static final String TAG = "KeyguardSecurityView"; private final List> mChildren = new ArrayList<>(); private final LayoutInflater mLayoutInflater; private final AsyncLayoutInflater mAsyncLayoutInflater; private final EmergencyButtonController.Factory mEmergencyButtonControllerFactory; private final Factory mKeyguardSecurityViewControllerFactory; private final FeatureFlags mFeatureFlags; @Inject protected KeyguardSecurityViewFlipperController(KeyguardSecurityViewFlipper view, LayoutInflater layoutInflater, AsyncLayoutInflater asyncLayoutInflater, KeyguardInputViewController.Factory keyguardSecurityViewControllerFactory, EmergencyButtonController.Factory emergencyButtonControllerFactory, FeatureFlags featureFlags) { super(view); mKeyguardSecurityViewControllerFactory = keyguardSecurityViewControllerFactory; mLayoutInflater = layoutInflater; mEmergencyButtonControllerFactory = emergencyButtonControllerFactory; mAsyncLayoutInflater = asyncLayoutInflater; mFeatureFlags = featureFlags; } @Override protected void onViewAttached() { } @Override protected void onViewDetached() { } public void reset() { for (KeyguardInputViewController child : mChildren) { child.reset(); } } /** Handles density or font scale changes. */ public void clearViews() { mView.removeAllViews(); mChildren.clear(); } @VisibleForTesting void getSecurityView(SecurityMode securityMode, KeyguardSecurityCallback keyguardSecurityCallback, OnViewInflatedCallback onViewInflatedCallback) { for (KeyguardInputViewController child : mChildren) { if (child.getSecurityMode() == securityMode) { onViewInflatedCallback.onViewInflated(child); return; } } asynchronouslyInflateView(securityMode, keyguardSecurityCallback, onViewInflatedCallback); } /** * Asynchronously inflate view and then add it to view flipper on the main thread when complete. * * OnInflateFinishedListener will be called on the main thread. * * @param securityMode * @param keyguardSecurityCallback */ public void asynchronouslyInflateView(SecurityMode securityMode, KeyguardSecurityCallback keyguardSecurityCallback, @Nullable OnViewInflatedCallback onViewInflatedListener) { int layoutId = getLayoutIdFor(securityMode); int viewID = getKeyguardInputViewId(securityMode); if (layoutId != 0 && viewID != 0) { if (DEBUG) { Log.v(TAG, "inflating on bg thread id = " + layoutId + " . viewID = " + viewID); } mAsyncLayoutInflater.inflate(layoutId, mView, (view, resId, parent) -> { mView.addView(view); KeyguardInputViewController childController = mKeyguardSecurityViewControllerFactory.create( (KeyguardInputView) view.findViewById(viewID), securityMode, keyguardSecurityCallback); childController.init(); mChildren.add(childController); if (onViewInflatedListener != null) { onViewInflatedListener.onViewInflated(childController); } }); } } private int getLayoutIdFor(SecurityMode securityMode) { switch (securityMode) { case Pattern: return R.layout.keyguard_pattern_view; case PIN: return R.layout.keyguard_pin_view; case Password: return R.layout.keyguard_password_view; case SimPin: return R.layout.keyguard_sim_pin_view; case SimPuk: return R.layout.keyguard_sim_puk_view; default: return 0; } } private int getKeyguardInputViewId(SecurityMode securityMode) { //Keyguard Input View is not the root view of the layout, use these IDs for lookup. switch (securityMode) { case Pattern: return R.id.keyguard_pattern_view; case PIN: return R.id.keyguard_pin_view; case Password: return R.id.keyguard_password_view; case SimPin: return R.id.keyguard_sim_pin_view; case SimPuk: return R.id.keyguard_sim_puk_view; default: return 0; } } /** Makes the supplied child visible if it is contained win this view, */ public void show(KeyguardInputViewController childController) { int index = childController.getIndexIn(mView); if (index != -1) { mView.setDisplayedChild(index); } } /** Listener to when view has finished inflation. */ public interface OnViewInflatedCallback { /** Notifies that view has been inflated */ void onViewInflated(KeyguardInputViewController controller); } }