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
17package com.android.mediaframeworktest.helpers;
18
19import android.app.Instrumentation;
20import android.os.Bundle;
21import android.os.Environment;
22import android.util.Log;
23
24import java.io.BufferedWriter;
25import java.io.File;
26import java.io.FileWriter;
27
28public class CameraTestResultPrinter {
29
30    private static final String TAG = CameraTestResultPrinter.class.getSimpleName();
31    private static final String RESULT_DIR = Environment.getExternalStorageDirectory() +
32            "/camera-out/";
33    private static final String RESULT_FILE_FORMAT = "fwk-stress_camera_%s.txt";
34    private static final String RESULT_SWAP_FILE = "fwk-stress.swp";
35    private static final String KEY_NUM_ATTEMPTS = "numAttempts";   // Total number of iterations
36    private static final String KEY_ITERATION = "iteration";
37    private static final String KEY_CAMERA_ID = "cameraId";
38    private static final int INST_STATUS_IN_PROGRESS = 2;
39
40    private Instrumentation mInst = null;
41    private boolean mWriteToFile = true;
42
43
44    public CameraTestResultPrinter(Instrumentation instrumentation, boolean writeToFile) {
45        mInst = instrumentation;
46        mWriteToFile = writeToFile;
47
48        // Create a log directory if not exists.
49        File baseDir = new File(RESULT_DIR);
50        if (!baseDir.exists() && !baseDir.mkdirs()) {
51            throw new IllegalStateException("Couldn't create directory for logs: " + baseDir);
52        }
53        Log.v(TAG, String.format("Saving test results under: %s", baseDir.getAbsolutePath()));
54        // Remove all logs but not the base directory before a test run.
55        purgeFiles(baseDir);
56    }
57
58    public void printStatus(int numAttempts, int iteration, String cameraId) throws Exception {
59        Log.v(TAG, String.format("Print status: numAttempts=%d iteration=%d cameraId=%s",
60                numAttempts, iteration, cameraId));
61        // Write stats to instrumentation results.
62        sendInstrumentationStatus(numAttempts, iteration, cameraId);
63
64        if (mWriteToFile) {
65            writeToFile(numAttempts, iteration, cameraId);
66        }
67    }
68
69    /**
70     *  Report the test results to instrumentation status or a file.
71     */
72    public void printStatus(int numAttempts, int iteration) throws Exception {
73        printStatus(numAttempts, iteration, "");
74    }
75
76    /**
77     * Write stats to instrumentation results.
78     */
79    private void sendInstrumentationStatus(int numAttempts, int iteration, String cameraId)
80            throws Exception {
81        Bundle output = new Bundle();
82        output.putString(KEY_NUM_ATTEMPTS, String.valueOf(numAttempts));
83        output.putString(KEY_ITERATION, String.valueOf(iteration));
84        if (!"".equals(cameraId)) {
85            output.putString(KEY_CAMERA_ID, cameraId);
86        }
87        mInst.sendStatus(INST_STATUS_IN_PROGRESS, output);
88    }
89
90    private void writeToFile(final int numAttempts, final int iteration, String cameraId) {
91        // Format output in a form of pairs of key and value
92        // eg, "numAttempts=500|iteration=400[|cameraId=0]"
93        String results = String.format("%s=%d|%s=%d", KEY_NUM_ATTEMPTS, numAttempts,
94                KEY_ITERATION, iteration);
95        if (!"".equals(cameraId)) {
96            results += String.format("|%s=%s", KEY_CAMERA_ID, cameraId);
97        }
98        Log.v(TAG, String.format("Writing result to a file: %s", results));
99
100        // Write results to a swap file temporarily, then rename it to a text file when writing
101        // has successfully completed, so that process crash during file writing would
102        // not corrupt the file.
103        File swapFile = new File(RESULT_DIR, RESULT_SWAP_FILE);
104        BufferedWriter out = null;
105        try {
106            out = new BufferedWriter(new FileWriter(swapFile));
107            out.write(results);
108            out.flush();
109        } catch (Exception e) {
110            Log.w(TAG, String.format("Failed to write results to a file: %s", e));
111        } finally {
112            if (out != null) {
113                try {
114                    out.close();
115                    // Delete an old file just before renaming, instead of overwriting.
116                    String resultFileName = String.format(RESULT_FILE_FORMAT, cameraId);
117                    File txtFile = new File(RESULT_DIR, resultFileName);
118                    txtFile.delete();
119                    swapFile.renameTo(txtFile);
120                } catch (Exception e) {
121                    Log.w(TAG, String.format("Failed to write results to a file: %s", e));
122                }
123            }
124        }
125    }
126
127    // Remove sub directories and their contents, but not given directory.
128    private void purgeFiles(File path) {
129        File[] files = path.listFiles();
130        if (files != null) {
131            for (File child : files) {
132                if (path.isDirectory()) {
133                    purgeFiles(child);
134                }
135                child.delete();
136            }
137        }
138    }
139}
140