1 /* 2 * Copyright (C) 2018 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; 18 19 import static android.car.CarOccupantZoneManager.DISPLAY_TYPE_MAIN; 20 21 import android.annotation.Nullable; 22 import android.app.Application; 23 import android.car.Car; 24 import android.car.Car.CarServiceLifecycleListener; 25 import android.car.CarOccupantZoneManager; 26 import android.car.CarOccupantZoneManager.OccupantZoneConfigChangeListener; 27 import android.car.CarOccupantZoneManager.OccupantZoneInfo; 28 import android.car.media.CarAudioManager; 29 import android.car.wifi.CarWifiManager; 30 import android.content.BroadcastReceiver; 31 import android.content.ComponentName; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.content.IntentFilter; 35 import android.content.pm.PackageManager; 36 import android.os.UserManager; 37 import android.view.Display; 38 39 import androidx.annotation.GuardedBy; 40 import androidx.annotation.VisibleForTesting; 41 42 import com.android.car.settings.activityembedding.ActivityEmbeddingRulesController; 43 import com.android.car.settings.activityembedding.ActivityEmbeddingUtils; 44 import com.android.car.settings.common.Logger; 45 import com.android.car.settings.deeplink.DeepLinkHomepageActivity; 46 47 /** 48 * Application class for CarSettings. 49 */ 50 public class CarSettingsApplication extends Application { 51 52 public static final String CAR_SETTINGS_PACKAGE_NAME = "com.android.car.settings"; 53 private static final Logger LOG = new Logger(CarSettingsApplication.class); 54 private CarOccupantZoneManager mCarOccupantZoneManager; 55 56 private final Object mInfoLock = new Object(); 57 private final Object mCarAudioManagerLock = new Object(); 58 private final Object mCarWifiManagerLock = new Object(); 59 60 @GuardedBy("mInfoLock") 61 private int mOccupantZoneDisplayId = Display.DEFAULT_DISPLAY; 62 @GuardedBy("mInfoLock") 63 private int mAudioZoneId = CarAudioManager.INVALID_AUDIO_ZONE; 64 @GuardedBy("mInfoLock") 65 private int mOccupantZoneType = CarOccupantZoneManager.OCCUPANT_TYPE_INVALID; 66 @GuardedBy("mCarAudioManagerLock") 67 private CarAudioManager mCarAudioManager = null; 68 @GuardedBy("mCarWifiManagerLock") 69 private CarWifiManager mCarWifiManager = null; 70 71 /** 72 * Listener to monitor any Occupant Zone configuration change. 73 */ 74 private final OccupantZoneConfigChangeListener mConfigChangeListener = flags -> { 75 synchronized (mInfoLock) { 76 updateZoneInfoLocked(); 77 } 78 }; 79 80 /** 81 * Listener to monitor the Lifecycle of car service. 82 */ 83 private final CarServiceLifecycleListener mCarServiceLifecycleListener = (car, ready) -> { 84 if (!ready) { 85 mCarOccupantZoneManager = null; 86 synchronized (mCarAudioManagerLock) { 87 mCarAudioManager = null; 88 } 89 synchronized (mCarWifiManagerLock) { 90 mCarWifiManager = null; 91 } 92 return; 93 } 94 mCarOccupantZoneManager = (CarOccupantZoneManager) car.getCarManager( 95 Car.CAR_OCCUPANT_ZONE_SERVICE); 96 if (mCarOccupantZoneManager != null) { 97 mCarOccupantZoneManager.registerOccupantZoneConfigChangeListener( 98 mConfigChangeListener); 99 } 100 synchronized (mCarAudioManagerLock) { 101 mCarAudioManager = (CarAudioManager) car.getCarManager(Car.AUDIO_SERVICE); 102 } 103 synchronized (mCarWifiManagerLock) { 104 mCarWifiManager = (CarWifiManager) car.getCarManager(Car.CAR_WIFI_SERVICE); 105 } 106 synchronized (mInfoLock) { 107 updateZoneInfoLocked(); 108 } 109 }; 110 111 @Override onCreate()112 public void onCreate() { 113 super.onCreate(); 114 registerCarServiceLifecycleListener(); 115 // Register activity embedding only when user is unlocked, which happens after boot has been 116 // completed. This is so that RRO values may be read properly for device configurations that 117 // uses RROs for embedding related configs, which are not available before boot completion. 118 ActivityEmbeddingRulesController controller = new ActivityEmbeddingRulesController(this); 119 if (getApplicationContext().getSystemService(UserManager.class).isUserUnlocked()) { 120 controller.initActivityEmbeddingRules(); 121 } else { 122 IntentFilter filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED); 123 getApplicationContext().registerReceiver(new BroadcastReceiver() { 124 @Override 125 public void onReceive(Context context, Intent intent) { 126 controller.initActivityEmbeddingRules(); 127 } 128 }, filter, 0); 129 } 130 updateDeepLinkHomepageActivityEnabledState(); 131 } 132 133 @VisibleForTesting registerCarServiceLifecycleListener()134 void registerCarServiceLifecycleListener() { 135 Car.createCar(this, /* handler= */ null , Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, 136 mCarServiceLifecycleListener); 137 } 138 139 /** 140 * Returns zone type assigned for the current user. 141 * The zone type is used to determine whether the settings preferences 142 * should be available or not. 143 */ getMyOccupantZoneType()144 public final int getMyOccupantZoneType() { 145 synchronized (mInfoLock) { 146 return mOccupantZoneType; 147 } 148 } 149 150 /** 151 * Returns displayId assigned for the current user. 152 */ getMyOccupantZoneDisplayId()153 public final int getMyOccupantZoneDisplayId() { 154 synchronized (mInfoLock) { 155 return mOccupantZoneDisplayId; 156 } 157 } 158 159 /** 160 * Returns audio zone id assigned for the current user. 161 */ getMyAudioZoneId()162 public final int getMyAudioZoneId() { 163 synchronized (mInfoLock) { 164 return mAudioZoneId; 165 } 166 } 167 168 /** 169 * Returns CarAudioManager instance. 170 */ 171 @Nullable getCarAudioManager()172 public final CarAudioManager getCarAudioManager() { 173 synchronized (mCarAudioManagerLock) { 174 return mCarAudioManager; 175 } 176 } 177 178 /** 179 * Returns CarAudioManager instance. 180 */ 181 @Nullable getCarWifiManager()182 public final CarWifiManager getCarWifiManager() { 183 synchronized (mCarWifiManagerLock) { 184 return mCarWifiManager; 185 } 186 } 187 188 @GuardedBy("mInfoLock") updateZoneInfoLocked()189 private void updateZoneInfoLocked() { 190 if (mCarOccupantZoneManager == null) { 191 return; 192 } 193 OccupantZoneInfo info = mCarOccupantZoneManager.getMyOccupantZone(); 194 if (info != null) { 195 mOccupantZoneType = info.occupantType; 196 mAudioZoneId = mCarOccupantZoneManager.getAudioZoneIdForOccupant(info); 197 Display display = mCarOccupantZoneManager 198 .getDisplayForOccupant(info, DISPLAY_TYPE_MAIN); 199 if (display != null) { 200 mOccupantZoneDisplayId = display.getDisplayId(); 201 } 202 } 203 } 204 205 /** 206 * Disable {@link DeepLinkHomepageActivity} if ActivityEmbedding is not enabled. 207 */ updateDeepLinkHomepageActivityEnabledState()208 private void updateDeepLinkHomepageActivityEnabledState() { 209 int componentEnabledState = ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this) 210 ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED 211 : PackageManager.COMPONENT_ENABLED_STATE_DISABLED; 212 try { 213 getPackageManager().setComponentEnabledSetting( 214 /* ComponentName */ new ComponentName(this, DeepLinkHomepageActivity.class), 215 /* newState */ componentEnabledState, 216 /* flags */ PackageManager.DONT_KILL_APP); 217 } catch (IllegalArgumentException exception) { 218 LOG.e("Unable to update enabled state for DeepLinkHomepageActivity: " + exception); 219 } 220 } 221 } 222