Home | History | Annotate | Download | only in sensor
      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.google.android.car.kitchensink.sensor;
     18 
     19 import static java.lang.Integer.toHexString;
     20 
     21 import android.Manifest;
     22 import android.annotation.Nullable;
     23 import android.car.Car;
     24 import android.car.CarNotConnectedException;
     25 import android.car.hardware.CarSensorConfig;
     26 import android.car.hardware.CarSensorEvent;
     27 import android.car.hardware.CarSensorManager;
     28 import android.content.pm.PackageManager;
     29 import android.os.Bundle;
     30 import android.os.Handler;
     31 import android.support.v4.app.Fragment;
     32 import android.text.TextUtils;
     33 import android.util.Log;
     34 import android.view.LayoutInflater;
     35 import android.view.View;
     36 import android.view.ViewGroup;
     37 import android.widget.TextView;
     38 
     39 import com.google.android.car.kitchensink.KitchenSinkActivity;
     40 import com.google.android.car.kitchensink.R;
     41 
     42 import java.text.DateFormat;
     43 import java.text.SimpleDateFormat;
     44 import java.util.ArrayList;
     45 import java.util.Date;
     46 import java.util.HashSet;
     47 import java.util.List;
     48 import java.util.Map;
     49 import java.util.Set;
     50 import java.util.concurrent.ConcurrentHashMap;
     51 
     52 public class SensorsTestFragment extends Fragment {
     53     private static final String TAG = "CAR.SENSOR.KS";
     54     private static final boolean DBG = true;
     55     private static final boolean DBG_VERBOSE = true;
     56     private static final int KS_PERMISSIONS_REQUEST = 1;
     57 
     58     private final static String[] REQUIRED_PERMISSIONS = new String[]{
     59         Manifest.permission.ACCESS_FINE_LOCATION,
     60         Manifest.permission.ACCESS_COARSE_LOCATION,
     61         Car.PERMISSION_MILEAGE,
     62         Car.PERMISSION_ENERGY,
     63         Car.PERMISSION_SPEED,
     64         Car.PERMISSION_CAR_DYNAMICS_STATE
     65     };
     66 
     67     private final CarSensorManager.OnSensorChangedListener mOnSensorChangedListener =
     68             new CarSensorManager.OnSensorChangedListener() {
     69                 @Override
     70                 public void onSensorChanged(CarSensorEvent event) {
     71                     if (DBG_VERBOSE) {
     72                         Log.v(TAG, "New car sensor event: " + event);
     73                     }
     74                     synchronized (SensorsTestFragment.this) {
     75                         mEventMap.put(event.sensorType, event);
     76                     }
     77                     refreshUi();
     78                 }
     79             };
     80     private final Handler mHandler = new Handler();
     81     private final Map<Integer, CarSensorEvent> mEventMap = new ConcurrentHashMap<>();
     82     private final DateFormat mDateFormat = SimpleDateFormat.getDateTimeInstance();
     83 
     84     private KitchenSinkActivity mActivity;
     85     private TextView mSensorInfo;
     86     private Car mCar;
     87     private CarSensorManager mSensorManager;
     88     private String mNaString;
     89     private int[] supportedSensors = new int[0];
     90     private Set<String> mActivePermissions = new HashSet<String>();
     91 
     92     @Nullable
     93     @Override
     94     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
     95                              @Nullable Bundle savedInstanceState) {
     96         if (DBG) {
     97             Log.i(TAG, "onCreateView");
     98         }
     99 
    100         View view = inflater.inflate(R.layout.sensors, container, false);
    101         mActivity = (KitchenSinkActivity) getHost();
    102 
    103         mSensorInfo = (TextView) view.findViewById(R.id.sensor_info);
    104         mNaString = getContext().getString(R.string.sensor_na);
    105 
    106         return view;
    107     }
    108 
    109     @Override
    110     public void onResume() {
    111         super.onResume();
    112         initPermissions();
    113     }
    114 
    115     @Override
    116     public void onPause() {
    117         super.onPause();
    118         if (mSensorManager != null) {
    119             mSensorManager.unregisterListener(mOnSensorChangedListener);
    120         }
    121     }
    122 
    123     private void initSensors() {
    124         try {
    125             mSensorManager =
    126                 (CarSensorManager) ((KitchenSinkActivity) getActivity()).getSensorManager();
    127             supportedSensors = mSensorManager.getSupportedSensors();
    128             for (Integer sensor : supportedSensors) {
    129                 mSensorManager.registerListener(mOnSensorChangedListener, sensor,
    130                         CarSensorManager.SENSOR_RATE_NORMAL);
    131             }
    132         } catch (CarNotConnectedException e) {
    133             Log.e(TAG, "Car not connected or not supported", e);
    134         } catch (Exception e) {
    135             Log.e(TAG, "initSensors() exception caught: ", e);
    136         }
    137     }
    138 
    139     private void initPermissions() {
    140         Set<String> missingPermissions = checkExistingPermissions();
    141         if (!missingPermissions.isEmpty()) {
    142             requestPermissions(missingPermissions);
    143         } else {
    144             initSensors();
    145         }
    146     }
    147 
    148     private Set<String> checkExistingPermissions() {
    149         Set<String> missingPermissions = new HashSet<String>();
    150         for (String permission : REQUIRED_PERMISSIONS) {
    151             if (mActivity.checkSelfPermission(permission)
    152                 == PackageManager.PERMISSION_GRANTED) {
    153                 mActivePermissions.add(permission);
    154             } else {
    155                 missingPermissions.add(permission);
    156             }
    157         }
    158         return missingPermissions;
    159     }
    160 
    161     private void requestPermissions(Set<String> permissions) {
    162         Log.d(TAG, "requesting additional permissions=" + permissions);
    163 
    164         requestPermissions(permissions.toArray(new String[permissions.size()]),
    165                 KS_PERMISSIONS_REQUEST);
    166     }
    167 
    168     @Override
    169     public void onRequestPermissionsResult(int requestCode, String[] permissions,
    170             int[] grantResults) {
    171         Log.d(TAG, "onRequestPermissionsResult reqCode=" + requestCode);
    172         if (KS_PERMISSIONS_REQUEST == requestCode) {
    173             for (int i=0; i<permissions.length; i++) {
    174                 if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
    175                     mActivePermissions.add(permissions[i]);
    176                 }
    177             }
    178             initSensors();
    179         }
    180     }
    181 
    182     private void refreshUi() {
    183         String summaryString;
    184         synchronized (this) {
    185             List<String> summary = new ArrayList<>();
    186             for (Integer i : supportedSensors) {
    187                 CarSensorEvent event = mEventMap.get(i);
    188                 switch (i) {
    189                     case CarSensorManager.SENSOR_TYPE_CAR_SPEED:
    190                         summary.add(getContext().getString(R.string.sensor_speed,
    191                                 getTimestamp(event),
    192                                 event == null ? mNaString : event.getCarSpeedData(null).carSpeed));
    193                         break;
    194                     case CarSensorManager.SENSOR_TYPE_RPM:
    195                         summary.add(getContext().getString(R.string.sensor_rpm,
    196                                 getTimestamp(event),
    197                                 event == null ? mNaString : event.getRpmData(null).rpm));
    198                         break;
    199                     case CarSensorManager.SENSOR_TYPE_ODOMETER:
    200                         summary.add(getContext().getString(R.string.sensor_odometer,
    201                                 getTimestamp(event),
    202                                 event == null ? mNaString : event.getOdometerData(null).kms));
    203                         break;
    204                     case CarSensorManager.SENSOR_TYPE_FUEL_LEVEL:
    205                         summary.add(getFuelLevel(event));
    206                         break;
    207                     case CarSensorManager.SENSOR_TYPE_FUEL_DOOR_OPEN:
    208                         summary.add(getFuelDoorOpen(event));
    209                         break;
    210                     case CarSensorManager.SENSOR_TYPE_PARKING_BRAKE:
    211                         summary.add(getContext().getString(R.string.sensor_parking_brake,
    212                                 getTimestamp(event),
    213                                 event == null ? mNaString :
    214                                 event.getParkingBrakeData(null).isEngaged));
    215                         break;
    216                     case CarSensorManager.SENSOR_TYPE_GEAR:
    217                         summary.add(getContext().getString(R.string.sensor_gear,
    218                                 getTimestamp(event),
    219                                 event == null ? mNaString : event.getGearData(null).gear));
    220                         break;
    221                     case CarSensorManager.SENSOR_TYPE_NIGHT:
    222                         summary.add(getContext().getString(R.string.sensor_night,
    223                                 getTimestamp(event),
    224                                 event == null ? mNaString : event.getNightData(null).isNightMode));
    225                         break;
    226                     case CarSensorManager.SENSOR_TYPE_ENVIRONMENT:
    227                         String temperature = mNaString;
    228                         String pressure = mNaString;
    229                         if (event != null) {
    230                             CarSensorEvent.EnvironmentData env = event.getEnvironmentData(null);
    231                             temperature = Float.isNaN(env.temperature) ? temperature :
    232                                     String.valueOf(env.temperature);
    233                             pressure = Float.isNaN(env.pressure) ? pressure :
    234                                     String.valueOf(env.pressure);
    235                         }
    236                         summary.add(getContext().getString(R.string.sensor_environment,
    237                                 getTimestamp(event), temperature, pressure));
    238                         break;
    239                     case CarSensorManager.SENSOR_TYPE_WHEEL_TICK_DISTANCE:
    240                         if(event != null) {
    241                             CarSensorEvent.CarWheelTickDistanceData d =
    242                                     event.getCarWheelTickDistanceData(null);
    243                             summary.add(getContext().getString(R.string.sensor_wheel_ticks,
    244                                 getTimestamp(event), d.sensorResetCount, d.frontLeftWheelDistanceMm,
    245                                 d.frontRightWheelDistanceMm, d.rearLeftWheelDistanceMm,
    246                                 d.rearRightWheelDistanceMm));
    247                         } else {
    248                             summary.add(getContext().getString(R.string.sensor_wheel_ticks,
    249                                 getTimestamp(event), mNaString, mNaString, mNaString, mNaString,
    250                                 mNaString));
    251                         }
    252                         // Get the config data
    253                         try {
    254                             CarSensorConfig c = mSensorManager.getSensorConfig(
    255                                 CarSensorManager.SENSOR_TYPE_WHEEL_TICK_DISTANCE);
    256                             summary.add(getContext().getString(R.string.sensor_wheel_ticks_cfg,
    257                                 c.getInt(CarSensorConfig.WHEEL_TICK_DISTANCE_SUPPORTED_WHEELS),
    258                                 c.getInt(CarSensorConfig.WHEEL_TICK_DISTANCE_FRONT_LEFT_UM_PER_TICK),
    259                                 c.getInt(CarSensorConfig.WHEEL_TICK_DISTANCE_FRONT_RIGHT_UM_PER_TICK),
    260                                 c.getInt(CarSensorConfig.WHEEL_TICK_DISTANCE_REAR_LEFT_UM_PER_TICK),
    261                                 c.getInt(CarSensorConfig.WHEEL_TICK_DISTANCE_REAR_RIGHT_UM_PER_TICK)));
    262                         } catch (CarNotConnectedException e) {
    263                             Log.e(TAG, "Car not connected or not supported", e);
    264                         }
    265                         break;
    266                     case CarSensorManager.SENSOR_TYPE_ABS_ACTIVE:
    267                         summary.add(getContext().getString(R.string.sensor_abs_is_active,
    268                             getTimestamp(event), event == null ? mNaString :
    269                                     event.getCarAbsActiveData(null).absIsActive));
    270                         break;
    271 
    272                     case CarSensorManager.SENSOR_TYPE_TRACTION_CONTROL_ACTIVE:
    273                         summary.add(
    274                             getContext().getString(R.string.sensor_traction_control_is_active,
    275                             getTimestamp(event), event == null ? mNaString :
    276                                     event.getCarTractionControlActiveData(null)
    277                                     .tractionControlIsActive));
    278                         break;
    279                     case CarSensorManager.SENSOR_TYPE_EV_BATTERY_LEVEL:
    280                         summary.add(getEvBatteryLevel(event));
    281                         break;
    282                     case CarSensorManager.SENSOR_TYPE_EV_CHARGE_PORT_OPEN:
    283                         summary.add(getEvChargePortOpen(event));
    284                         break;
    285                     case CarSensorManager.SENSOR_TYPE_EV_CHARGE_PORT_CONNECTED:
    286                         summary.add(getEvChargePortConnected(event));
    287                         break;
    288                     case CarSensorManager.SENSOR_TYPE_EV_BATTERY_CHARGE_RATE:
    289                         summary.add(getEvChargeRate(event));
    290                         break;
    291                     default:
    292                         // Should never happen.
    293                         Log.w(TAG, "Unrecognized event type: " + toHexString(i));
    294                 }
    295             }
    296             summaryString = TextUtils.join("\n", summary);
    297         }
    298         mHandler.post(new Runnable() {
    299             @Override
    300             public void run() {
    301                 mSensorInfo.setText(summaryString);
    302             }
    303         });
    304     }
    305 
    306     private String getTimestamp(CarSensorEvent event) {
    307         if (event == null) {
    308             return mNaString;
    309         }
    310         return mDateFormat.format(new Date(event.timestamp / (1000L * 1000L)));
    311     }
    312 
    313     private String getFuelLevel(CarSensorEvent event) {
    314         String fuelLevel = mNaString;
    315         if(event != null) {
    316             fuelLevel = String.valueOf(event.getFuelLevelData(null).level);
    317         }
    318         return getContext().getString(R.string.sensor_fuel_level, getTimestamp(event), fuelLevel);
    319     }
    320 
    321     private String getFuelDoorOpen(CarSensorEvent event) {
    322         String fuelDoorOpen = mNaString;
    323         if(event != null) {
    324             fuelDoorOpen = String.valueOf(event.getCarFuelDoorOpenData(null).fuelDoorIsOpen);
    325         }
    326         return getContext().getString(R.string.sensor_fuel_door_open, getTimestamp(event),
    327             fuelDoorOpen);
    328     }
    329 
    330     private String getEvBatteryLevel(CarSensorEvent event) {
    331         String evBatteryLevel = mNaString;
    332         if(event != null) {
    333             evBatteryLevel = String.valueOf(event.getCarEvBatteryLevelData(null).evBatteryLevel);
    334         }
    335         return getContext().getString(R.string.sensor_ev_battery_level, getTimestamp(event),
    336             evBatteryLevel);
    337     }
    338 
    339     private String getEvChargePortOpen(CarSensorEvent event) {
    340         String evChargePortOpen = mNaString;
    341         if(event != null) {
    342             evChargePortOpen = String.valueOf(
    343                 event.getCarEvChargePortOpenData(null).evChargePortIsOpen);
    344         }
    345         return getContext().getString(R.string.sensor_ev_charge_port_is_open, getTimestamp(event),
    346             evChargePortOpen);
    347     }
    348 
    349     private String getEvChargePortConnected(CarSensorEvent event) {
    350         String evChargePortConnected = mNaString;
    351         if(event != null) {
    352             evChargePortConnected = String.valueOf(
    353                 event.getCarEvChargePortConnectedData(null).evChargePortIsConnected);
    354         }
    355         return getContext().getString(R.string.sensor_ev_charge_port_is_connected,
    356             getTimestamp(event), evChargePortConnected);
    357     }
    358 
    359     private String getEvChargeRate(CarSensorEvent event) {
    360         String evChargeRate = mNaString;
    361         if(event != null) {
    362             evChargeRate = String.valueOf(event.getCarEvBatteryChargeRateData(null).evChargeRate);
    363         }
    364         return getContext().getString(R.string.sensor_ev_charge_rate, getTimestamp(event),
    365             evChargeRate);
    366     }
    367 }
    368