1 /* 2 * Copyright (C) 2016 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.tv.settings; 18 19 import static com.android.tv.settings.overlay.FlavorUtils.ALL_FLAVORS_MASK; 20 21 import android.content.Intent; 22 import android.os.Bundle; 23 import android.transition.Scene; 24 import android.transition.Slide; 25 import android.transition.Transition; 26 import android.transition.TransitionManager; 27 import android.util.Log; 28 import android.view.Gravity; 29 import android.view.ViewGroup; 30 import android.view.ViewTreeObserver; 31 32 import androidx.annotation.Nullable; 33 import androidx.fragment.app.Fragment; 34 import androidx.fragment.app.FragmentActivity; 35 36 import com.android.tv.settings.overlay.FlavorUtils; 37 38 public abstract class TvSettingsActivity extends FragmentActivity { 39 private static final String TAG = "TvSettingsActivity"; 40 41 private static final String SETTINGS_FRAGMENT_TAG = 42 "com.android.tv.settings.MainSettings.SETTINGS_FRAGMENT"; 43 44 private static final int REQUEST_CODE_STARTUP_VERIFICATION = 1; 45 46 @Override onCreate(@ullable Bundle savedInstanceState)47 protected void onCreate(@Nullable Bundle savedInstanceState) { 48 super.onCreate(savedInstanceState); 49 if ((FlavorUtils.getFlavor(this) & getAvailableFlavors()) == 0) { 50 Log.w(TAG, "Activity is not supported in current flavor"); 51 finish(); 52 } 53 if (savedInstanceState == null) { 54 55 final Fragment fragment = createSettingsFragment(); 56 if (fragment == null) { 57 return; 58 } 59 if (isStartupVerificationRequired()) { 60 if (FlavorUtils.getFeatureFactory(this) 61 .getStartupVerificationFeatureProvider() 62 .startStartupVerificationActivityForResult( 63 this, REQUEST_CODE_STARTUP_VERIFICATION)) { 64 return; 65 } 66 } 67 if (FlavorUtils.isTwoPanel(this)) { 68 getSupportFragmentManager().beginTransaction() 69 .setCustomAnimations(android.R.animator.fade_in, 70 android.R.animator.fade_out) 71 .add(android.R.id.content, fragment, SETTINGS_FRAGMENT_TAG) 72 .commitNow(); 73 return; 74 } 75 76 final ViewGroup root = findViewById(android.R.id.content); 77 root.getViewTreeObserver().addOnPreDrawListener( 78 new ViewTreeObserver.OnPreDrawListener() { 79 @Override 80 public boolean onPreDraw() { 81 root.getViewTreeObserver().removeOnPreDrawListener(this); 82 final Scene scene = new Scene(root); 83 scene.setEnterAction(() -> { 84 if (getFragmentManager().isStateSaved() 85 || getFragmentManager().isDestroyed()) { 86 Log.d(TAG, "Got torn down before adding fragment"); 87 return; 88 } 89 getSupportFragmentManager().beginTransaction() 90 .add(android.R.id.content, fragment, 91 SETTINGS_FRAGMENT_TAG) 92 .commitNow(); 93 }); 94 95 final Slide slide = new Slide(Gravity.END); 96 slide.setSlideFraction( 97 getResources().getDimension(R.dimen.lb_settings_pane_width) 98 / root.getWidth()); 99 TransitionManager.go(scene, slide); 100 101 // Skip the current draw, there's nothing in it 102 return false; 103 } 104 }); 105 } 106 } 107 108 @Override finish()109 public void finish() { 110 final Fragment fragment = getSupportFragmentManager().findFragmentByTag(SETTINGS_FRAGMENT_TAG); 111 if (FlavorUtils.isTwoPanel(this)) { 112 super.finish(); 113 return; 114 } 115 116 if (isResumed() && fragment != null) { 117 final ViewGroup root = findViewById(android.R.id.content); 118 final Scene scene = new Scene(root); 119 scene.setEnterAction(() -> getSupportFragmentManager().beginTransaction() 120 .remove(fragment) 121 .commitNow()); 122 final Slide slide = new Slide(Gravity.END); 123 slide.setSlideFraction( 124 getResources().getDimension(R.dimen.lb_settings_pane_width) / root.getWidth()); 125 slide.addListener(new Transition.TransitionListener() { 126 @Override 127 public void onTransitionStart(Transition transition) { 128 getWindow().setDimAmount(0); 129 } 130 131 @Override 132 public void onTransitionEnd(Transition transition) { 133 transition.removeListener(this); 134 TvSettingsActivity.super.finish(); 135 } 136 137 @Override 138 public void onTransitionCancel(Transition transition) { 139 } 140 141 @Override 142 public void onTransitionPause(Transition transition) { 143 } 144 145 @Override 146 public void onTransitionResume(Transition transition) { 147 } 148 }); 149 TransitionManager.go(scene, slide); 150 } else { 151 super.finish(); 152 } 153 } 154 createSettingsFragment()155 protected abstract Fragment createSettingsFragment(); 156 157 /** 158 * Subclass may override this to return true to indicate that the Activity may only be started 159 * after some verification. Example: in special mode, we need to challenge the user with re-auth 160 * before launching account settings. 161 * 162 * This only works in certain flavors as we do not have features requiring the startup 163 * verification in classic flavor or ordinary two panel flavor. 164 */ isStartupVerificationRequired()165 protected boolean isStartupVerificationRequired() { 166 return false; 167 } 168 169 /** Subclass may override this to specify the flavor, in which the activity is available. */ getAvailableFlavors()170 protected int getAvailableFlavors() { 171 return ALL_FLAVORS_MASK; 172 } 173 174 @Override onActivityResult(int requestCode, int resultCode, Intent data)175 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 176 super.onActivityResult(requestCode, resultCode, data); 177 if (requestCode == REQUEST_CODE_STARTUP_VERIFICATION) { 178 if (resultCode == RESULT_OK) { 179 Log.v(TAG, "Startup verification succeeded."); 180 if (FlavorUtils.getFlavor(this) == FlavorUtils.FLAVOR_X 181 || FlavorUtils.getFlavor(this) == FlavorUtils.FLAVOR_VENDOR) { 182 if (createSettingsFragment() == null) { 183 Log.e(TAG, "Fragment is null."); 184 finish(); 185 return; 186 } 187 getSupportFragmentManager().beginTransaction() 188 .setCustomAnimations( 189 android.R.animator.fade_in, android.R.animator.fade_out) 190 .add( 191 android.R.id.content, 192 createSettingsFragment(), 193 SETTINGS_FRAGMENT_TAG) 194 .commitNow(); 195 } 196 } else { 197 Log.v(TAG, "Startup verification cancelled or failed."); 198 finish(); 199 } 200 } 201 } 202 } 203