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 package com.google.android.car.kitchensink.cluster; 17 18 import android.app.AlertDialog; 19 import android.car.cluster.CarInstrumentClusterManager; 20 import android.content.Intent; 21 import android.content.pm.PackageManager; 22 import android.os.Bundle; 23 import android.support.annotation.Nullable; 24 import android.support.car.Car; 25 import android.support.car.CarAppFocusManager; 26 import android.support.car.CarConnectionCallback; 27 import android.support.car.CarNotConnectedException; 28 import android.support.car.navigation.CarNavigationStatusManager; 29 import android.support.v4.app.Fragment; 30 import android.util.Log; 31 import android.view.LayoutInflater; 32 import android.view.View; 33 import android.view.ViewGroup; 34 import android.widget.Toast; 35 36 import com.google.android.car.kitchensink.R; 37 38 /** 39 * Contains functions to test instrument cluster API. 40 */ 41 public class InstrumentClusterFragment extends Fragment { 42 private static final String TAG = InstrumentClusterFragment.class.getSimpleName(); 43 44 private static final int DISPLAY_IN_CLUSTER_PERMISSION_REQUEST = 1; 45 46 private CarNavigationStatusManager mCarNavigationStatusManager; 47 private CarAppFocusManager mCarAppFocusManager; 48 private Car mCarApi; 49 50 private final CarConnectionCallback mCarConnectionCallback = new CarConnectionCallback() { 51 @Override 52 public void onConnected(Car car) { 53 Log.d(TAG, "Connected to Car Service"); 54 try { 55 mCarNavigationStatusManager = 56 mCarApi.getCarManager(CarNavigationStatusManager.class); 57 mCarAppFocusManager = mCarApi.getCarManager(CarAppFocusManager.class); 58 } catch (CarNotConnectedException e) { 59 Log.e(TAG, "Car is not connected!", e); 60 } 61 } 62 63 @Override 64 public void onDisconnected(Car car) { 65 Log.d(TAG, "Disconnect from Car Service"); 66 } 67 }; 68 69 private void initCarApi() { 70 if (mCarApi != null && mCarApi.isConnected()) { 71 mCarApi.disconnect(); 72 mCarApi = null; 73 } 74 75 mCarApi = Car.createCar(getContext(), mCarConnectionCallback); 76 mCarApi.connect(); 77 } 78 79 @Nullable 80 @Override 81 public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, 82 @Nullable Bundle savedInstanceState) { 83 View view = inflater.inflate(R.layout.instrument_cluster, container, false); 84 85 view.findViewById(R.id.cluster_start_button).setOnClickListener(v -> initCluster()); 86 view.findViewById(R.id.cluster_turn_left_button).setOnClickListener(v -> turnLeft()); 87 view.findViewById(R.id.cluster_start_activity).setOnClickListener(v -> startNavActivity()); 88 89 return view; 90 } 91 92 @Override 93 public void onCreate(@Nullable Bundle savedInstanceState) { 94 initCarApi(); 95 96 super.onCreate(savedInstanceState); 97 } 98 99 private void startNavActivity() { 100 CarInstrumentClusterManager clusterManager; 101 try { 102 clusterManager = (CarInstrumentClusterManager) mCarApi.getCarManager( 103 android.car.Car.CAR_INSTRUMENT_CLUSTER_SERVICE); 104 } catch (CarNotConnectedException e) { 105 Log.e(TAG, "Failed to get CarInstrumentClusterManager", e); 106 Toast.makeText(getContext(), "Failed to get CarInstrumentClusterManager", 107 Toast.LENGTH_LONG).show(); 108 return; 109 } 110 111 // Implicit intent 112 Intent intent = new Intent(Intent.ACTION_MAIN); 113 intent.addCategory(CarInstrumentClusterManager.CATEGORY_NAVIGATION); 114 try { 115 clusterManager.startActivity(intent); 116 } catch (android.car.CarNotConnectedException e) { 117 Log.e(TAG, "Failed to startActivity in cluster", e); 118 Toast.makeText(getContext(), "Failed to start activity in cluster", 119 Toast.LENGTH_LONG).show(); 120 return; 121 } 122 } 123 124 private void turnLeft() { 125 try { 126 mCarNavigationStatusManager 127 .sendNavigationTurnEvent(CarNavigationStatusManager.TURN_TURN, "Huff Ave", 90, 128 -1, null, CarNavigationStatusManager.TURN_SIDE_LEFT); 129 mCarNavigationStatusManager.sendNavigationTurnDistanceEvent(500, 10, 500, 130 CarNavigationStatusManager.DISTANCE_METERS); 131 } catch (CarNotConnectedException e) { 132 e.printStackTrace(); 133 } 134 } 135 136 private void initCluster() { 137 try { 138 mCarAppFocusManager 139 .addFocusListener(new CarAppFocusManager.OnAppFocusChangedListener() { 140 @Override 141 public void onAppFocusChanged(CarAppFocusManager manager, int appType, 142 boolean active) { 143 Log.d(TAG, "onAppFocusChanged, appType: " + appType + " active: " 144 + active); 145 } 146 }, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION); 147 } catch (CarNotConnectedException e) { 148 Log.e(TAG, "Failed to register focus listener", e); 149 } 150 151 CarAppFocusManager.OnAppFocusOwnershipCallback 152 focusCallback = new CarAppFocusManager.OnAppFocusOwnershipCallback() { 153 @Override 154 public void onAppFocusOwnershipLost(CarAppFocusManager manager, int focus) { 155 Log.w(TAG, "onAppFocusOwnershipLost, focus: " + focus); 156 new AlertDialog.Builder(getContext()) 157 .setTitle(getContext().getApplicationInfo().name) 158 .setMessage(R.string.cluster_nav_app_context_loss) 159 .show(); 160 } 161 162 @Override 163 public void onAppFocusOwnershipGranted(CarAppFocusManager manager, int focus) { 164 Log.w(TAG, "onAppFocusOwnershipGranted, focus: " + focus); 165 } 166 167 }; 168 try { 169 mCarAppFocusManager.requestAppFocus(CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, 170 focusCallback); 171 } catch (CarNotConnectedException e) { 172 Log.e(TAG, "Failed to set active focus", e); 173 } 174 175 try { 176 boolean ownsFocus = mCarAppFocusManager.isOwningFocus( 177 CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION, focusCallback); 178 Log.d(TAG, "Owns APP_FOCUS_TYPE_NAVIGATION: " + ownsFocus); 179 if (!ownsFocus) { 180 throw new RuntimeException("Focus was not acquired."); 181 } 182 } catch (CarNotConnectedException e) { 183 Log.e(TAG, "Failed to get owned focus", e); 184 } 185 186 try { 187 mCarNavigationStatusManager 188 .sendNavigationStatus(CarNavigationStatusManager.STATUS_ACTIVE); 189 } catch (CarNotConnectedException e) { 190 Log.e(TAG, "Failed to set navigation status, reconnecting to the car", e); 191 } 192 } 193 194 @Override 195 public void onResume() { 196 super.onResume(); 197 Log.i(TAG, "onResume!"); 198 if (getActivity().checkSelfPermission(android.car.Car.PERMISSION_CAR_DISPLAY_IN_CLUSTER) 199 != PackageManager.PERMISSION_GRANTED) { 200 Log.i(TAG, "Requesting: " + android.car.Car.PERMISSION_CAR_DISPLAY_IN_CLUSTER); 201 202 requestPermissions(new String[] {android.car.Car.PERMISSION_CAR_DISPLAY_IN_CLUSTER}, 203 DISPLAY_IN_CLUSTER_PERMISSION_REQUEST); 204 } else { 205 Log.i(TAG, "All required permissions granted"); 206 } 207 } 208 209 @Override 210 public void onRequestPermissionsResult(int requestCode, String[] permissions, 211 int[] grantResults) { 212 if (DISPLAY_IN_CLUSTER_PERMISSION_REQUEST == requestCode) { 213 for (int i = 0; i < permissions.length; i++) { 214 boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED; 215 Log.i(TAG, "onRequestPermissionsResult, requestCode: " + requestCode 216 + ", permission: " + permissions[i] + ", granted: " + granted); 217 } 218 } 219 } 220 } 221