• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.car.settings.common;
18 
19 import android.car.drivingstate.CarUxRestrictions;
20 import android.car.drivingstate.CarUxRestrictionsManager.OnUxRestrictionsChangedListener;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentSender;
24 import android.os.Bundle;
25 import android.view.View;
26 import android.view.inputmethod.InputMethodManager;
27 import android.widget.Toast;
28 
29 import androidx.annotation.Nullable;
30 import androidx.fragment.app.DialogFragment;
31 import androidx.fragment.app.Fragment;
32 import androidx.fragment.app.FragmentActivity;
33 import androidx.fragment.app.FragmentManager.OnBackStackChangedListener;
34 import androidx.preference.Preference;
35 import androidx.preference.PreferenceFragmentCompat;
36 
37 import com.android.car.apps.common.util.Themes;
38 import com.android.car.settings.R;
39 
40 /**
41  * Base activity class for car settings, provides a action bar with a back button that goes to
42  * previous activity.
43  */
44 public abstract class BaseCarSettingsActivity extends FragmentActivity implements
45         FragmentController, OnUxRestrictionsChangedListener, UxRestrictionsProvider,
46         OnBackStackChangedListener, PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
47     private static final Logger LOG = new Logger(BaseCarSettingsActivity.class);
48 
49     private CarUxRestrictionsHelper mUxRestrictionsHelper;
50     private View mRestrictedMessage;
51     // Default to minimum restriction.
52     private CarUxRestrictions mCarUxRestrictions = new CarUxRestrictions.Builder(
53             /* reqOpt= */ true,
54             CarUxRestrictions.UX_RESTRICTIONS_BASELINE,
55             /* timestamp= */ 0
56     ).build();
57 
58     @Override
onCreate(Bundle savedInstanceState)59     protected void onCreate(Bundle savedInstanceState) {
60         super.onCreate(savedInstanceState);
61         setContentView(R.layout.car_setting_activity);
62         if (mUxRestrictionsHelper == null) {
63             mUxRestrictionsHelper = new CarUxRestrictionsHelper(/* context= */ this, /* listener= */
64                     this);
65         }
66         mUxRestrictionsHelper.start();
67         getSupportFragmentManager().addOnBackStackChangedListener(this);
68         mRestrictedMessage = findViewById(R.id.restricted_message);
69 
70         launchIfDifferent(getInitialFragment());
71     }
72 
73     @Override
onDestroy()74     public void onDestroy() {
75         super.onDestroy();
76         mUxRestrictionsHelper.stop();
77         mUxRestrictionsHelper = null;
78     }
79 
80     @Override
onBackPressed()81     public void onBackPressed() {
82         super.onBackPressed();
83         hideKeyboard();
84         // If the backstack is empty, finish the activity.
85         if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
86             finish();
87         }
88     }
89 
90     @Override
launchFragment(Fragment fragment)91     public void launchFragment(Fragment fragment) {
92         if (fragment instanceof DialogFragment) {
93             throw new IllegalArgumentException(
94                     "cannot launch dialogs with launchFragment() - use showDialog() instead");
95         }
96 
97         getSupportFragmentManager()
98                 .beginTransaction()
99                 .setCustomAnimations(
100                         Themes.getAttrResourceId(/* context= */ this,
101                                 android.R.attr.fragmentOpenEnterAnimation),
102                         Themes.getAttrResourceId(/* context= */ this,
103                                 android.R.attr.fragmentOpenExitAnimation),
104                         Themes.getAttrResourceId(/* context= */ this,
105                                 android.R.attr.fragmentCloseEnterAnimation),
106                         Themes.getAttrResourceId(/* context= */ this,
107                                 android.R.attr.fragmentCloseExitAnimation))
108                 .replace(R.id.fragment_container, fragment,
109                         Integer.toString(getSupportFragmentManager().getBackStackEntryCount()))
110                 .addToBackStack(null)
111                 .commit();
112     }
113 
114     @Override
goBack()115     public void goBack() {
116         onBackPressed();
117     }
118 
119     @Override
showBlockingMessage()120     public void showBlockingMessage() {
121         Toast.makeText(this, R.string.restricted_while_driving, Toast.LENGTH_SHORT).show();
122     }
123 
124     @Override
showDialog(DialogFragment dialogFragment, @Nullable String tag)125     public void showDialog(DialogFragment dialogFragment, @Nullable String tag) {
126         dialogFragment.show(getSupportFragmentManager(), tag);
127     }
128 
129     @Override
130     @Nullable
findDialogByTag(String tag)131     public DialogFragment findDialogByTag(String tag) {
132         Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
133         if (fragment instanceof DialogFragment) {
134             return (DialogFragment) fragment;
135         }
136         return null;
137     }
138 
139     @Override
startActivityForResult(Intent intent, int requestCode, ActivityResultCallback callback)140     public void startActivityForResult(Intent intent, int requestCode,
141             ActivityResultCallback callback) {
142         throw new UnsupportedOperationException(
143                 "Unimplemented for activities that implement FragmentController");
144     }
145 
146     @Override
startIntentSenderForResult(IntentSender intent, int requestCode, @Nullable Intent fillInIntent, int flagsMask, int flagsValues, Bundle options, ActivityResultCallback callback)147     public void startIntentSenderForResult(IntentSender intent, int requestCode,
148             @Nullable Intent fillInIntent, int flagsMask, int flagsValues, Bundle options,
149             ActivityResultCallback callback) {
150         throw new UnsupportedOperationException(
151                 "Unimplemented for activities that implement FragmentController");
152     }
153 
154     @Override
onUxRestrictionsChanged(CarUxRestrictions restrictionInfo)155     public void onUxRestrictionsChanged(CarUxRestrictions restrictionInfo) {
156         mCarUxRestrictions = restrictionInfo;
157         Fragment currentFragment = getCurrentFragment();
158         if (currentFragment instanceof OnUxRestrictionsChangedListener) {
159             ((OnUxRestrictionsChangedListener) currentFragment)
160                     .onUxRestrictionsChanged(restrictionInfo);
161         }
162         updateBlockingView(currentFragment);
163     }
164 
165     @Override
getCarUxRestrictions()166     public CarUxRestrictions getCarUxRestrictions() {
167         return mCarUxRestrictions;
168     }
169 
170     @Override
onBackStackChanged()171     public void onBackStackChanged() {
172         onUxRestrictionsChanged(getCarUxRestrictions());
173     }
174 
175     @Override
onPreferenceStartFragment(PreferenceFragmentCompat caller, Preference pref)176     public boolean onPreferenceStartFragment(PreferenceFragmentCompat caller, Preference pref) {
177         if (pref.getFragment() != null) {
178             Fragment fragment = Fragment.instantiate(/* context= */ this, pref.getFragment(),
179                     pref.getExtras());
180             launchFragment(fragment);
181             return true;
182         }
183         return false;
184     }
185 
186     /**
187      * Gets the fragment to show onCreate. If null, the activity will not perform an initial
188      * fragment transaction.
189      */
190     @Nullable
getInitialFragment()191     protected abstract Fragment getInitialFragment();
192 
launchIfDifferent(Fragment newFragment)193     protected void launchIfDifferent(Fragment newFragment) {
194         Fragment currentFragment = getCurrentFragment();
195         if ((newFragment != null) && differentFragment(newFragment, currentFragment)) {
196             LOG.d("launchIfDifferent: " + newFragment + " replacing " + currentFragment);
197             launchFragment(newFragment);
198         }
199     }
200 
getCurrentFragment()201     protected Fragment getCurrentFragment() {
202         return getSupportFragmentManager().findFragmentById(R.id.fragment_container);
203     }
204 
205     /**
206      * Returns {code true} if newFragment is different from current fragment.
207      */
differentFragment(Fragment newFragment, Fragment currentFragment)208     private boolean differentFragment(Fragment newFragment, Fragment currentFragment) {
209         return (currentFragment == null)
210                 || (!currentFragment.getClass().equals(newFragment.getClass()));
211     }
212 
hideKeyboard()213     private void hideKeyboard() {
214         InputMethodManager imm = (InputMethodManager) this.getSystemService(
215                 Context.INPUT_METHOD_SERVICE);
216         imm.hideSoftInputFromWindow(getWindow().getDecorView().getWindowToken(), 0);
217     }
218 
updateBlockingView(@ullable Fragment currentFragment)219     private void updateBlockingView(@Nullable Fragment currentFragment) {
220         if (currentFragment instanceof BaseFragment) {
221             boolean canBeShown = ((BaseFragment) currentFragment).canBeShown(mCarUxRestrictions);
222             mRestrictedMessage.setVisibility(canBeShown ? View.GONE : View.VISIBLE);
223         }
224     }
225 }
226