1 /* 2 * Copyright (C) 2011 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.android.cts.verifier; 18 19 import android.app.AlertDialog; 20 import android.content.Context; 21 import android.os.AsyncTask; 22 import android.os.Build; 23 import android.os.Environment; 24 25 import com.android.compatibility.common.util.FileUtil; 26 import com.android.compatibility.common.util.IInvocationResult; 27 import com.android.compatibility.common.util.InvocationResult; 28 import com.android.compatibility.common.util.ResultHandler; 29 import com.android.compatibility.common.util.ZipUtil; 30 31 import org.xmlpull.v1.XmlPullParserException; 32 33 import java.io.BufferedOutputStream; 34 import java.io.File; 35 import java.io.FileInputStream; 36 import java.io.FileOutputStream; 37 import java.io.IOException; 38 import java.io.InputStream; 39 import java.lang.System; 40 import java.nio.file.Files; 41 import java.nio.file.Paths; 42 import java.text.SimpleDateFormat; 43 import java.util.Date; 44 import java.util.Locale; 45 import java.util.logging.Level; 46 import java.util.logging.Logger; 47 import java.util.zip.ZipEntry; 48 import java.util.zip.ZipOutputStream; 49 50 /** 51 * Background task to generate a report and save it to external storage. 52 */ 53 class ReportExporter extends AsyncTask<Void, Void, String> { 54 55 private static final String COMMAND_LINE_ARGS = ""; 56 private static final String LOG_URL = null; 57 private static final String REFERENCE_URL = null; 58 private static final String SUITE_NAME_METADATA_KEY = "SuiteName"; 59 private static final String SUITE_PLAN = "verifier"; 60 private static final String SUITE_BUILD = "0"; 61 62 private static final long START_MS = System.currentTimeMillis(); 63 private static final long END_MS = START_MS; 64 65 private static final String REPORT_DIRECTORY = "verifierReports"; 66 private static final String ZIP_EXTENSION = ".zip"; 67 68 protected static final Logger LOG = Logger.getLogger(ReportExporter.class.getName()); 69 70 private final Context mContext; 71 private final TestListAdapter mAdapter; 72 ReportExporter(Context context, TestListAdapter adapter)73 ReportExporter(Context context, TestListAdapter adapter) { 74 this.mContext = context; 75 this.mAdapter = adapter; 76 } 77 78 @Override doInBackground(Void... params)79 protected String doInBackground(Void... params) { 80 if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { 81 LOG.log(Level.WARNING, "External storage is not writable."); 82 return mContext.getString(R.string.no_storage); 83 } 84 IInvocationResult result; 85 try { 86 TestResultsReport report = new TestResultsReport(mContext, mAdapter); 87 result = report.generateResult(); 88 } catch (Exception e) { 89 LOG.log(Level.WARNING, "Couldn't create test results report", e); 90 return mContext.getString(R.string.test_results_error); 91 } 92 // create a directory for CTS Verifier reports 93 File externalStorageDirectory = Environment.getExternalStorageDirectory(); 94 File verifierReportsDir = new File(externalStorageDirectory, REPORT_DIRECTORY); 95 verifierReportsDir.mkdirs(); 96 97 String suiteName = Version.getMetadata(mContext, SUITE_NAME_METADATA_KEY); 98 // create a temporary directory for this particular report 99 File tempDir = new File(verifierReportsDir, getReportName(suiteName)); 100 tempDir.mkdirs(); 101 102 // create a File object for a report ZIP file 103 File reportZipFile = new File( 104 verifierReportsDir, getReportName(suiteName) + ZIP_EXTENSION); 105 106 try { 107 // Serialize the report 108 String versionName = Version.getVersionName(mContext); 109 ResultHandler.writeResults(suiteName, versionName, SUITE_PLAN, SUITE_BUILD, 110 result, tempDir, START_MS, END_MS, REFERENCE_URL, LOG_URL, 111 COMMAND_LINE_ARGS); 112 113 // copy formatting files to the temporary report directory 114 copyFormattingFiles(tempDir); 115 116 // create a compressed ZIP file containing the temporary report directory 117 ZipUtil.createZip(tempDir, reportZipFile); 118 } catch (IOException | XmlPullParserException e) { 119 LOG.log(Level.WARNING, "I/O exception writing report to storage.", e); 120 return mContext.getString(R.string.no_storage); 121 } finally { 122 // delete the temporary directory and its files made for the report 123 FileUtil.recursiveDelete(tempDir); 124 } 125 return mContext.getString(R.string.report_saved, reportZipFile.getPath()); 126 } 127 128 /** 129 * Copy the XML formatting files stored in the assets directory to the result output. 130 * 131 * @param resultsDir 132 */ copyFormattingFiles(File resultsDir)133 private void copyFormattingFiles(File resultsDir) { 134 for (String resultFileName : ResultHandler.RESULT_RESOURCES) { 135 InputStream rawStream = null; 136 try { 137 rawStream = mContext.getAssets().open( 138 String.format("report/%s", resultFileName)); 139 } catch (IOException e) { 140 LOG.log(Level.WARNING, "Failed to load " + resultFileName + " from assets."); 141 } 142 if (rawStream != null) { 143 File resultFile = new File(resultsDir, resultFileName); 144 try { 145 FileUtil.writeToFile(rawStream, resultFile); 146 } catch (IOException e) { 147 LOG.log(Level.WARNING, "Failed to write " + resultFileName + " to a file."); 148 } 149 } 150 } 151 } 152 getReportName(String suiteName)153 private String getReportName(String suiteName) { 154 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd_HH.mm.ss", Locale.ENGLISH); 155 String date = dateFormat.format(new Date()); 156 return String.format( "%s-%s-%s-%s-%s-%s", 157 date, suiteName, Build.MANUFACTURER, Build.PRODUCT, Build.DEVICE, Build.ID); 158 } 159 160 @Override onPostExecute(String result)161 protected void onPostExecute(String result) { 162 new AlertDialog.Builder(mContext) 163 .setMessage(result) 164 .setPositiveButton(android.R.string.ok, null) 165 .show(); 166 } 167 } 168