1 /* 2 * Copyright (C) 2020 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.keyguard; 18 19 import android.util.Log; 20 import android.view.LayoutInflater; 21 22 import androidx.annotation.Nullable; 23 import androidx.asynclayoutinflater.view.AsyncLayoutInflater; 24 25 import com.android.internal.annotations.VisibleForTesting; 26 import com.android.keyguard.KeyguardInputViewController.Factory; 27 import com.android.keyguard.KeyguardSecurityModel.SecurityMode; 28 import com.android.keyguard.dagger.KeyguardBouncerScope; 29 import com.android.systemui.R; 30 import com.android.systemui.flags.FeatureFlags; 31 import com.android.systemui.flags.Flags; 32 import com.android.systemui.util.ViewController; 33 34 import java.util.ArrayList; 35 import java.util.List; 36 37 import javax.inject.Inject; 38 39 /** 40 * Controller for a {@link KeyguardSecurityViewFlipper}. 41 */ 42 @KeyguardBouncerScope 43 public class KeyguardSecurityViewFlipperController 44 extends ViewController<KeyguardSecurityViewFlipper> { 45 46 private static final boolean DEBUG = KeyguardConstants.DEBUG; 47 private static final String TAG = "KeyguardSecurityView"; 48 49 private final List<KeyguardInputViewController<KeyguardInputView>> mChildren = 50 new ArrayList<>(); 51 private final LayoutInflater mLayoutInflater; 52 private final AsyncLayoutInflater mAsyncLayoutInflater; 53 private final EmergencyButtonController.Factory mEmergencyButtonControllerFactory; 54 private final Factory mKeyguardSecurityViewControllerFactory; 55 private final FeatureFlags mFeatureFlags; 56 57 @Inject KeyguardSecurityViewFlipperController(KeyguardSecurityViewFlipper view, LayoutInflater layoutInflater, AsyncLayoutInflater asyncLayoutInflater, KeyguardInputViewController.Factory keyguardSecurityViewControllerFactory, EmergencyButtonController.Factory emergencyButtonControllerFactory, FeatureFlags featureFlags)58 protected KeyguardSecurityViewFlipperController(KeyguardSecurityViewFlipper view, 59 LayoutInflater layoutInflater, 60 AsyncLayoutInflater asyncLayoutInflater, 61 KeyguardInputViewController.Factory keyguardSecurityViewControllerFactory, 62 EmergencyButtonController.Factory emergencyButtonControllerFactory, 63 FeatureFlags featureFlags) { 64 super(view); 65 mKeyguardSecurityViewControllerFactory = keyguardSecurityViewControllerFactory; 66 mLayoutInflater = layoutInflater; 67 mEmergencyButtonControllerFactory = emergencyButtonControllerFactory; 68 mAsyncLayoutInflater = asyncLayoutInflater; 69 mFeatureFlags = featureFlags; 70 } 71 72 @Override onViewAttached()73 protected void onViewAttached() { 74 75 } 76 77 @Override onViewDetached()78 protected void onViewDetached() { 79 80 } 81 reset()82 public void reset() { 83 for (KeyguardInputViewController<KeyguardInputView> child : mChildren) { 84 child.reset(); 85 } 86 } 87 88 /** Handles density or font scale changes. */ clearViews()89 public void clearViews() { 90 mView.removeAllViews(); 91 mChildren.clear(); 92 } 93 94 95 @VisibleForTesting getSecurityView(SecurityMode securityMode, KeyguardSecurityCallback keyguardSecurityCallback)96 KeyguardInputViewController<KeyguardInputView> getSecurityView(SecurityMode securityMode, 97 KeyguardSecurityCallback keyguardSecurityCallback) { 98 KeyguardInputViewController<KeyguardInputView> childController = null; 99 for (KeyguardInputViewController<KeyguardInputView> child : mChildren) { 100 if (child.getSecurityMode() == securityMode) { 101 childController = child; 102 break; 103 } 104 } 105 106 if (!mFeatureFlags.isEnabled(Flags.ASYNC_INFLATE_BOUNCER) && childController == null 107 && securityMode != SecurityMode.None && securityMode != SecurityMode.Invalid) { 108 int layoutId = getLayoutIdFor(securityMode); 109 KeyguardInputView view = null; 110 if (layoutId != 0) { 111 if (DEBUG) Log.v(TAG, "inflating on main thread id = " + layoutId); 112 view = (KeyguardInputView) mLayoutInflater.inflate( 113 layoutId, mView, false); 114 mView.addView(view); 115 childController = mKeyguardSecurityViewControllerFactory.create( 116 view, securityMode, keyguardSecurityCallback); 117 childController.init(); 118 119 mChildren.add(childController); 120 } 121 } 122 123 if (childController == null) { 124 childController = new NullKeyguardInputViewController( 125 securityMode, keyguardSecurityCallback, 126 mEmergencyButtonControllerFactory.create(null)); 127 } 128 129 return childController; 130 } 131 132 /** 133 * Asynchronously inflate view and then add it to view flipper on the main thread when complete. 134 * 135 * OnInflateFinishedListener will be called on the main thread. 136 * 137 * @param securityMode 138 * @param keyguardSecurityCallback 139 */ asynchronouslyInflateView(SecurityMode securityMode, KeyguardSecurityCallback keyguardSecurityCallback, @Nullable OnViewInflatedListener onViewInflatedListener)140 public void asynchronouslyInflateView(SecurityMode securityMode, 141 KeyguardSecurityCallback keyguardSecurityCallback, 142 @Nullable OnViewInflatedListener onViewInflatedListener) { 143 int layoutId = getLayoutIdFor(securityMode); 144 if (layoutId != 0) { 145 if (DEBUG) Log.v(TAG, "inflating on bg thread id = " + layoutId); 146 mAsyncLayoutInflater.inflate(layoutId, mView, 147 (view, resId, parent) -> { 148 mView.addView(view); 149 KeyguardInputViewController<KeyguardInputView> childController = 150 mKeyguardSecurityViewControllerFactory.create( 151 (KeyguardInputView) view, securityMode, 152 keyguardSecurityCallback); 153 childController.init(); 154 mChildren.add(childController); 155 if (onViewInflatedListener != null) { 156 onViewInflatedListener.onViewInflated(); 157 } 158 }); 159 } 160 } 161 getLayoutIdFor(SecurityMode securityMode)162 private int getLayoutIdFor(SecurityMode securityMode) { 163 switch (securityMode) { 164 case Pattern: return R.layout.keyguard_pattern_view; 165 case PIN: return R.layout.keyguard_pin_view; 166 case Password: return R.layout.keyguard_password_view; 167 case SimPin: return R.layout.keyguard_sim_pin_view; 168 case SimPuk: return R.layout.keyguard_sim_puk_view; 169 default: 170 return 0; 171 } 172 } 173 174 /** Makes the supplied child visible if it is contained win this view, */ show(KeyguardInputViewController<KeyguardInputView> childController)175 public void show(KeyguardInputViewController<KeyguardInputView> childController) { 176 int index = childController.getIndexIn(mView); 177 if (index != -1) { 178 mView.setDisplayedChild(index); 179 } 180 } 181 182 private static class NullKeyguardInputViewController 183 extends KeyguardInputViewController<KeyguardInputView> { NullKeyguardInputViewController(SecurityMode securityMode, KeyguardSecurityCallback keyguardSecurityCallback, EmergencyButtonController emergencyButtonController)184 protected NullKeyguardInputViewController(SecurityMode securityMode, 185 KeyguardSecurityCallback keyguardSecurityCallback, 186 EmergencyButtonController emergencyButtonController) { 187 super(null, securityMode, keyguardSecurityCallback, emergencyButtonController, 188 null); 189 } 190 191 @Override needsInput()192 public boolean needsInput() { 193 return false; 194 } 195 196 @Override onStartingToHide()197 public void onStartingToHide() { 198 } 199 200 @Override getInitialMessageResId()201 protected int getInitialMessageResId() { 202 return 0; 203 } 204 } 205 206 /** Listener to when view has finished inflation. */ 207 public interface OnViewInflatedListener { 208 /** Notifies that view has been inflated */ onViewInflated()209 void onViewInflated(); 210 } 211 } 212