Home | History | Annotate | Download | only in diagnosticverifier
      1 /*
      2  * Copyright (C) 2017 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.diagnosticverifier;
     17 
     18 import android.app.Activity;
     19 import android.car.Car;
     20 import android.car.CarNotConnectedException;
     21 import android.car.diagnostic.CarDiagnosticEvent;
     22 import android.car.diagnostic.CarDiagnosticManager;
     23 import android.car.hardware.CarSensorManager;
     24 import android.content.BroadcastReceiver;
     25 import android.content.ComponentName;
     26 import android.content.Context;
     27 import android.content.Intent;
     28 import android.content.IntentFilter;
     29 import android.content.ServiceConnection;
     30 import android.os.Bundle;
     31 import android.os.Environment;
     32 import android.os.IBinder;
     33 import android.support.v7.widget.LinearLayoutManager;
     34 import android.support.v7.widget.RecyclerView;
     35 import android.util.JsonWriter;
     36 import android.util.Log;
     37 import android.widget.TextView;
     38 
     39 import com.google.android.car.diagnosticverifier.DiagnosticVerifier.VerificationResult;
     40 
     41 import java.io.File;
     42 import java.io.FileInputStream;
     43 import java.io.FileOutputStream;
     44 import java.io.IOException;
     45 import java.io.OutputStreamWriter;
     46 import java.util.ArrayList;
     47 import java.util.List;
     48 
     49 /**
     50  * The test app that does the verification of car diagnostic event data. It first reads the
     51  * truth (golden) event data from a JSON file upon starting. Then a broadcast intent such as:
     52  *
     53  *     am broadcast -a com.google.android.car.diagnosticverifier.action.START_LISTEN
     54  *
     55  * will activate the car diagnostics listener. The test app will receive events from diagnostic API.
     56  * Once it receives all the events, a broadcast intent with "stop" action such as:
     57  *
     58  *     am broadcast -a com.google.android.car.diagnosticverifier.action.STOP_LISTEN
     59  *
     60  * will deactivate the listener and start the verification process (see {@link DiagnosticVerifier}).
     61  *
     62  * Verification result will be output to a JSON file on device.
     63  */
     64 public class MainActivity extends Activity {
     65     public static final String TAG = "DiagnosticVerifier";
     66 
     67     public static final String ACTION_START_LISTEN =
     68             "com.google.android.car.diagnosticverifier.action.START_LISTEN";
     69     public static final String ACTION_STOP_LISTEN =
     70             "com.google.android.car.diagnosticverifier.action.STOP_LISTEN";
     71 
     72     private static final String DEFAULT_JSON_PATH = "/data/local/tmp/diag.json";
     73 
     74     private static final String JSON_PATH_KEY = "jsonPath";
     75     private static final String JSON_RESULT = "verification_result.json";
     76 
     77     private Car mCar;
     78     private CarDiagnosticManager mCarDiagnosticManager;
     79     private DiagnosticListener mDiagnosticListener;
     80     private BroadcastReceiver mBroadcastReceiver;
     81     private DiagnosticVerifier mVerifier;
     82     private TextView mStatusBar;
     83     private RecyclerView mRecyclerView;
     84     private VerificationResultAdapter mResultAdapter;
     85     private boolean mListening = false;
     86 
     87     private final ServiceConnection mCarConnectionListener =
     88             new ServiceConnection() {
     89                 @Override
     90                 public void onServiceConnected(ComponentName name, IBinder iBinder) {
     91                     Log.d(TAG, "Connected to " + name.flattenToString());
     92                     try {
     93                         mCarDiagnosticManager =
     94                                 (CarDiagnosticManager) mCar.getCarManager(Car.DIAGNOSTIC_SERVICE);
     95                     } catch (CarNotConnectedException e) {
     96                         Log.e(TAG, "Failed to get a connection", e);
     97                     }
     98                 }
     99 
    100                 @Override
    101                 public void onServiceDisconnected(ComponentName name) {
    102                     Log.d(TAG, "Disconnected from " + name.flattenToString());
    103 
    104                     mCar = null;
    105                     mCarDiagnosticManager = null;
    106                 }
    107             };
    108 
    109     class DiagnosticListener implements CarDiagnosticManager.OnDiagnosticEventListener {
    110 
    111         @Override
    112         public void onDiagnosticEvent(CarDiagnosticEvent carDiagnosticEvent) {
    113             Log.v(TAG, "Received Car Diagnostic Event: " + carDiagnosticEvent.toString());
    114             mVerifier.receiveEvent(carDiagnosticEvent);
    115         }
    116     }
    117 
    118     class VerifierMsgReceiver extends BroadcastReceiver {
    119 
    120         @Override
    121         public void onReceive(Context context, Intent intent) {
    122             String action = intent.getAction();
    123             Log.d(TAG, "Received intent with action: " + action);
    124             if (ACTION_START_LISTEN.equals(action)) {
    125                 try {
    126                     startListen();
    127                 } catch (CarNotConnectedException e) {
    128                     Log.e(TAG, "Failed to listen for car diagnostic event", e);
    129                 }
    130             } else if (ACTION_STOP_LISTEN.equals(action)) {
    131                 stopListen();
    132                 verify();
    133             }
    134         }
    135     }
    136 
    137     @Override
    138     public void onCreate(Bundle savedInstanceState) {
    139         super.onCreate(savedInstanceState);
    140         setContentView(R.layout.verifier_activity);
    141 
    142         mStatusBar = (TextView) findViewById(R.id.status_bar);
    143 
    144         //Setting up RecyclerView to show verification result messages
    145         mRecyclerView = (RecyclerView) findViewById(R.id.verification_results);
    146         LinearLayoutManager layoutManager =
    147                 new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
    148         mRecyclerView.setLayoutManager(layoutManager);
    149         mResultAdapter = new VerificationResultAdapter();
    150         mRecyclerView.setAdapter(mResultAdapter);
    151 
    152         //Connect to car service
    153         mCar = Car.createCar(this, mCarConnectionListener);
    154         mCar.connect();
    155 
    156         //Initialize broadcast intent receiver
    157         mBroadcastReceiver = new VerifierMsgReceiver();
    158         IntentFilter filter = new IntentFilter(ACTION_START_LISTEN);
    159         filter.addAction(ACTION_STOP_LISTEN);
    160         this.registerReceiver(mBroadcastReceiver, filter);
    161 
    162         //Read golden diagnostics JSON file
    163         String jsonPath = this.getIntent().getStringExtra(JSON_PATH_KEY);
    164         if (jsonPath == null || jsonPath.isEmpty()) {
    165             jsonPath = DEFAULT_JSON_PATH;
    166         }
    167         List<CarDiagnosticEvent> events;
    168         try {
    169             events = DiagnosticJsonConverter.readFromJson(new FileInputStream(jsonPath));
    170         } catch (IOException e) {
    171             throw new RuntimeException("Failed to read diagnostic JSON file", e);
    172         }
    173         Log.d(TAG, String.format("Read %d events from JSON file %s.", events.size(), jsonPath));
    174 
    175         mVerifier = new DiagnosticVerifier(events);
    176     }
    177 
    178     @Override
    179     protected void onDestroy() {
    180         if (mCar != null) {
    181             mCar.disconnect();
    182         }
    183         mVerifier = null;
    184         this.unregisterReceiver(mBroadcastReceiver);
    185     }
    186 
    187     private void startListen() throws CarNotConnectedException {
    188         if (mListening) {
    189             return;
    190         }
    191         if (mDiagnosticListener == null) {
    192             mDiagnosticListener = new DiagnosticListener();
    193         }
    194         Log.i(TAG, "Start listening for car diagnostics events");
    195         mCarDiagnosticManager.registerListener(
    196                 mDiagnosticListener,
    197                 CarDiagnosticManager.FRAME_TYPE_LIVE,
    198                 CarSensorManager.SENSOR_RATE_NORMAL);
    199         mCarDiagnosticManager.registerListener(
    200                 mDiagnosticListener,
    201                 CarDiagnosticManager.FRAME_TYPE_FREEZE,
    202                 CarSensorManager.SENSOR_RATE_NORMAL);
    203 
    204         mListening = true;
    205         mStatusBar.setText(R.string.status_receiving);
    206     }
    207 
    208     private void stopListen() {
    209         Log.i(TAG, "Stop listening for car diagnostics events");
    210         mCarDiagnosticManager.unregisterListener(mDiagnosticListener);
    211         mListening = false;
    212     }
    213 
    214     private boolean isExternalStorageWritable() {
    215         String state = Environment.getExternalStorageState();
    216         return Environment.MEDIA_MOUNTED.equals(state);
    217     }
    218 
    219     private File getResultJsonFile() throws IOException {
    220         if (!isExternalStorageWritable()) {
    221             throw new IOException("External storage is not writable. Cannot save content");
    222         }
    223 
    224         File resultJson = new File(Environment.getExternalStoragePublicDirectory(
    225                 Environment.DIRECTORY_DOCUMENTS), JSON_RESULT);
    226         if (!resultJson.getParentFile().mkdirs()) {
    227             Log.w(TAG, "Parent directory may already exist");
    228         }
    229         return resultJson;
    230     }
    231 
    232     private void verify() {
    233         Log.d(TAG, "Start verifying car diagnostics events");
    234         mStatusBar.setText(R.string.status_verifying);
    235         List<VerificationResult> results = mVerifier.verify();
    236         mStatusBar.setText(R.string.status_done);
    237 
    238         if (results.isEmpty()) {
    239             Log.d(TAG, "Verification result is empty.");
    240             return;
    241         }
    242 
    243         List<String> resultMessages = new ArrayList<>();
    244         try {
    245             File resultJson = getResultJsonFile();
    246             JsonWriter writer = new JsonWriter(
    247                 new OutputStreamWriter(new FileOutputStream(resultJson)));
    248 
    249             writer.beginArray();
    250             for (VerificationResult result : results) {
    251                 resultMessages.add("Test case: " + result.testCase);
    252                 resultMessages.add("Result: " + result.success);
    253                 resultMessages.add(result.errorMessage);
    254                 result.writeToJson(writer);
    255             }
    256             writer.endArray();
    257             writer.flush();
    258             writer.close();
    259             Log.i(TAG, "Verification result: " + resultJson.getAbsolutePath());
    260         } catch (IOException e) {
    261             Log.e(TAG, "Failed to save verification result.", e);
    262         }
    263         mResultAdapter.setResultMessages(resultMessages);
    264     }
    265 }
    266 
    267