1 /* 2 * Copyright (C) 2015 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.google.android.car.kitchensink; 18 19 import android.car.hardware.hvac.CarHvacManager; 20 import android.content.Intent; 21 import android.content.pm.PackageManager; 22 import android.os.Bundle; 23 import android.support.car.Car; 24 import android.support.car.CarAppFocusManager; 25 import android.support.car.CarConnectionCallback; 26 import android.support.car.CarNotConnectedException; 27 import android.support.car.hardware.CarSensorManager; 28 import android.support.v4.app.Fragment; 29 import android.util.Log; 30 import android.view.HapticFeedbackConstants; 31 import android.view.View; 32 import android.widget.ImageView; 33 import android.widget.Toast; 34 35 import com.android.car.app.CarDrawerActivity; 36 import com.android.car.app.CarDrawerAdapter; 37 import com.android.car.app.DrawerItemViewHolder; 38 import com.google.android.car.kitchensink.assistant.CarAssistantFragment; 39 import com.google.android.car.kitchensink.audio.AudioTestFragment; 40 import com.google.android.car.kitchensink.bluetooth.BluetoothHeadsetFragment; 41 import com.google.android.car.kitchensink.bluetooth.MapMceTestFragment; 42 import com.google.android.car.kitchensink.cluster.InstrumentClusterFragment; 43 import com.google.android.car.kitchensink.cube.CubesTestFragment; 44 import com.google.android.car.kitchensink.diagnostic.DiagnosticTestFragment; 45 import com.google.android.car.kitchensink.hvac.HvacTestFragment; 46 import com.google.android.car.kitchensink.input.InputTestFragment; 47 import com.google.android.car.kitchensink.job.JobSchedulerFragment; 48 import com.google.android.car.kitchensink.orientation.OrientationTestFragment; 49 import com.google.android.car.kitchensink.radio.RadioTestFragment; 50 import com.google.android.car.kitchensink.sensor.SensorsTestFragment; 51 import com.google.android.car.kitchensink.setting.CarServiceSettingsActivity; 52 import com.google.android.car.kitchensink.touch.TouchTestFragment; 53 import com.google.android.car.kitchensink.volume.VolumeTestFragment; 54 import java.util.ArrayList; 55 import java.util.List; 56 57 public class KitchenSinkActivity extends CarDrawerActivity { 58 private static final String TAG = "KitchenSinkActivity"; 59 60 private interface ClickHandler { 61 void onClick(); 62 } 63 64 private static abstract class MenuEntry implements ClickHandler { 65 abstract String getText(); 66 } 67 68 private final class OnClickMenuEntry extends MenuEntry { 69 private final String mText; 70 private final ClickHandler mClickHandler; 71 72 OnClickMenuEntry(String text, ClickHandler clickHandler) { 73 mText = text; 74 mClickHandler = clickHandler; 75 } 76 77 @Override 78 String getText() { 79 return mText; 80 } 81 82 @Override 83 public void onClick() { 84 mClickHandler.onClick(); 85 } 86 } 87 88 private final class FragmentMenuEntry<T extends Fragment> extends MenuEntry { 89 private final class FragmentClassOrInstance<T extends Fragment> { 90 final Class<T> mClazz; 91 T mFragment = null; 92 93 FragmentClassOrInstance(Class<T> clazz) { 94 mClazz = clazz; 95 } 96 97 T getFragment() { 98 if (mFragment == null) { 99 try { 100 mFragment = mClazz.newInstance(); 101 } catch (InstantiationException | IllegalAccessException e) { 102 Log.e(TAG, "unable to create fragment", e); 103 } 104 } 105 return mFragment; 106 } 107 } 108 109 private final String mText; 110 private final FragmentClassOrInstance<T> mFragment; 111 112 FragmentMenuEntry(String text, Class<T> clazz) { 113 mText = text; 114 mFragment = new FragmentClassOrInstance<>(clazz); 115 } 116 117 @Override 118 String getText() { 119 return mText; 120 } 121 122 @Override 123 public void onClick() { 124 Fragment fragment = mFragment.getFragment(); 125 if (fragment != null) { 126 KitchenSinkActivity.this.showFragment(fragment); 127 } else { 128 Log.e(TAG, "cannot show fragment for " + getText()); 129 } 130 } 131 } 132 133 private final List<MenuEntry> mMenuEntries = new ArrayList<MenuEntry>() { 134 { 135 add("audio", AudioTestFragment.class); 136 add("hvac", HvacTestFragment.class); 137 add("job scheduler", JobSchedulerFragment.class); 138 add("inst cluster", InstrumentClusterFragment.class); 139 add("input test", InputTestFragment.class); 140 add("radio", RadioTestFragment.class); 141 add("assistant", CarAssistantFragment.class); 142 add("sensors", SensorsTestFragment.class); 143 add("diagnostic", DiagnosticTestFragment.class); 144 add("volume test", VolumeTestFragment.class); 145 add("touch test", TouchTestFragment.class); 146 add("cubes test", CubesTestFragment.class); 147 add("orientation test", OrientationTestFragment.class); 148 add("bluetooth headset",BluetoothHeadsetFragment.class); 149 add("bluetooth messaging test", MapMceTestFragment.class); 150 add("car service settings", () -> { 151 Intent intent = new Intent(KitchenSinkActivity.this, 152 CarServiceSettingsActivity.class); 153 startActivity(intent); 154 }); 155 add("quit", KitchenSinkActivity.this::finish); 156 } 157 158 <T extends Fragment> void add(String text, Class<T> clazz) { 159 add(new FragmentMenuEntry(text, clazz)); 160 } 161 void add(String text, ClickHandler onClick) { 162 add(new OnClickMenuEntry(text, onClick)); 163 } 164 }; 165 private Car mCarApi; 166 private CarHvacManager mHvacManager; 167 private CarSensorManager mCarSensorManager; 168 private CarAppFocusManager mCarAppFocusManager; 169 170 private final CarSensorManager.OnSensorChangedListener mListener = (manager, event) -> { 171 switch (event.sensorType) { 172 case CarSensorManager.SENSOR_TYPE_DRIVING_STATUS: 173 Log.d(TAG, "driving status:" + event.intValues[0]); 174 break; 175 } 176 }; 177 178 public CarHvacManager getHvacManager() { 179 return mHvacManager; 180 } 181 182 @Override 183 protected CarDrawerAdapter getRootAdapter() { 184 return new DrawerAdapter(); 185 } 186 187 @Override 188 protected void onCreate(Bundle savedInstanceState) { 189 super.onCreate(savedInstanceState); 190 setMainContent(R.layout.kitchen_content); 191 // Connection to Car Service does not work for non-automotive yet. 192 if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) { 193 mCarApi = Car.createCar(this, mCarConnectionCallback); 194 mCarApi.connect(); 195 } 196 Log.i(TAG, "onCreate"); 197 } 198 199 @Override 200 protected void onStart() { 201 super.onStart(); 202 Log.i(TAG, "onStart"); 203 } 204 205 @Override 206 protected void onRestart() { 207 super.onRestart(); 208 Log.i(TAG, "onRestart"); 209 } 210 211 @Override 212 protected void onResume() { 213 super.onResume(); 214 Log.i(TAG, "onResume"); 215 } 216 217 @Override 218 protected void onPause() { 219 super.onPause(); 220 Log.i(TAG, "onPause"); 221 } 222 223 @Override 224 protected void onStop() { 225 super.onStop(); 226 Log.i(TAG, "onStop"); 227 } 228 229 @Override 230 protected void onDestroy() { 231 super.onDestroy(); 232 if (mCarSensorManager != null) { 233 mCarSensorManager.removeListener(mListener); 234 } 235 if (mCarApi != null) { 236 mCarApi.disconnect(); 237 } 238 Log.i(TAG, "onDestroy"); 239 } 240 241 private void showFragment(Fragment fragment) { 242 getSupportFragmentManager().beginTransaction() 243 .replace(R.id.kitchen_content, fragment) 244 .commit(); 245 } 246 247 private final CarConnectionCallback mCarConnectionCallback = 248 new CarConnectionCallback() { 249 @Override 250 public void onConnected(Car car) { 251 Log.d(TAG, "Connected to Car Service"); 252 try { 253 mHvacManager = (CarHvacManager) mCarApi.getCarManager(android.car.Car.HVAC_SERVICE); 254 mCarSensorManager = (CarSensorManager) mCarApi.getCarManager(Car.SENSOR_SERVICE); 255 mCarSensorManager.addListener(mListener, 256 CarSensorManager.SENSOR_TYPE_DRIVING_STATUS, 257 CarSensorManager.SENSOR_RATE_NORMAL); 258 mCarAppFocusManager = 259 (CarAppFocusManager) mCarApi.getCarManager(Car.APP_FOCUS_SERVICE); 260 } catch (CarNotConnectedException e) { 261 Log.e(TAG, "Car is not connected!", e); 262 } 263 } 264 265 @Override 266 public void onDisconnected(Car car) { 267 Log.d(TAG, "Disconnect from Car Service"); 268 } 269 }; 270 271 public Car getCar() { 272 return mCarApi; 273 } 274 275 private final class DrawerAdapter extends CarDrawerAdapter { 276 277 public DrawerAdapter() { 278 super(KitchenSinkActivity.this, true /* showDisabledOnListOnEmpty */); 279 setTitle(getString(R.string.app_title)); 280 } 281 282 @Override 283 protected int getActualItemCount() { 284 return mMenuEntries.size(); 285 } 286 287 @Override 288 protected void populateViewHolder(DrawerItemViewHolder holder, int position) { 289 holder.getTitle().setText(mMenuEntries.get(position).getText()); 290 } 291 292 @Override 293 public void onItemClick(int position) { 294 if ((position < 0) || (position >= mMenuEntries.size())) { 295 Log.wtf(TAG, "Unknown menu item: " + position); 296 return; 297 } 298 299 mMenuEntries.get(position).onClick(); 300 301 closeDrawer(); 302 } 303 } 304 } 305