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