1 /*
2  * Copyright (C) 2015 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 android.theme.app;
18 
19 import android.Manifest.permission;
20 import android.app.Activity;
21 import android.app.KeyguardManager;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.pm.PackageManager;
25 import android.os.Build.VERSION;
26 import android.os.Bundle;
27 import android.os.Environment;
28 import android.os.Handler;
29 import android.util.Log;
30 import android.view.WindowManager.LayoutParams;
31 
32 import java.io.File;
33 import java.util.concurrent.CountDownLatch;
34 
35 /**
36  * Generates images by iterating through all themes and launching instances of
37  * {@link ThemeDeviceActivity}.
38  */
39 public class GenerateImagesActivity extends Activity {
40     private static final String TAG = "GenerateImagesActivity";
41 
42     private static final String OUT_DIR = "cts-theme-assets";
43     private static final int REQUEST_CODE = 1;
44 
45     private final CountDownLatch mLatch = new CountDownLatch(1);
46 
47     private File mOutputDir;
48     private int mCurrentTheme;
49     private String mFinishReason;
50     private boolean mFinishSuccess;
51 
52     @Override
onCreate(Bundle savedInstanceState)53     protected void onCreate(Bundle savedInstanceState) {
54         super.onCreate(savedInstanceState);
55 
56         getWindow().addFlags(LayoutParams.FLAG_KEEP_SCREEN_ON
57                 | LayoutParams.FLAG_TURN_SCREEN_ON
58                 | LayoutParams.FLAG_DISMISS_KEYGUARD);
59 
60         mOutputDir = new File(Environment.getExternalStorageDirectory(), OUT_DIR);
61         ThemeTestUtils.deleteDirectory(mOutputDir);
62         mOutputDir.mkdirs();
63 
64         if (!mOutputDir.exists()) {
65             finish("Failed to create output directory " + mOutputDir.getAbsolutePath(), false);
66             return;
67         }
68 
69         final boolean canDisableKeyguard = checkCallingOrSelfPermission(
70                 permission.DISABLE_KEYGUARD) == PackageManager.PERMISSION_GRANTED;
71         if (!canDisableKeyguard) {
72             finish("Not granted permission to disable keyguard", false);
73             return;
74         }
75 
76         new KeyguardCheck(this) {
77             @Override
78             public void onSuccess() {
79                 generateNextImage();
80             }
81 
82             @Override
83             public void onFailure() {
84                 finish("Device is locked", false);
85             }
86         }.start();
87     }
88 
finish(String reason, boolean success)89     private void finish(String reason, boolean success) {
90         mFinishSuccess = success;
91         mFinishReason = reason;
92 
93         Log.i(TAG, (success ? "OKAY" : "FAIL") + ":" + reason);
94         finish();
95     }
96 
isFinishSuccess()97     public boolean isFinishSuccess() {
98         return mFinishSuccess;
99     }
100 
getFinishReason()101     public String getFinishReason() {
102         return mFinishReason;
103     }
104 
105     static abstract class KeyguardCheck implements Runnable {
106         private static final int MAX_RETRIES = 3;
107         private static final int RETRY_DELAY = 500;
108 
109         private final Handler mHandler;
110         private final KeyguardManager mKeyguard;
111 
112         private int mRetries;
113 
KeyguardCheck(Context context)114         public KeyguardCheck(Context context) {
115             mHandler = new Handler(context.getMainLooper());
116             mKeyguard = (KeyguardManager) context.getSystemService(KEYGUARD_SERVICE);
117         }
118 
start()119         public void start() {
120             mRetries = 0;
121 
122             mHandler.removeCallbacks(this);
123             mHandler.post(this);
124         }
125 
cancel()126         public void cancel() {
127             mHandler.removeCallbacks(this);
128         }
129 
130         @Override
run()131         public void run() {
132             if (!mKeyguard.isKeyguardLocked()) {
133                 onSuccess();
134             } else if (mRetries < MAX_RETRIES) {
135                 mRetries++;
136                 mHandler.postDelayed(this, RETRY_DELAY);
137             } else {
138                 onFailure();
139             }
140 
141         }
142 
onSuccess()143         public abstract void onSuccess();
onFailure()144         public abstract void onFailure();
145     }
146 
getOutputDir()147     public File getOutputDir() {
148         return mOutputDir;
149     }
150 
151     /**
152      * Starts the activity to generate the next image.
153      */
generateNextImage()154     private boolean generateNextImage() {
155         final ThemeDeviceActivity.Theme theme = ThemeDeviceActivity.THEMES[mCurrentTheme];
156         if (theme.apiLevel > VERSION.SDK_INT) {
157             Log.v(TAG, "Skipping theme \"" + theme.name
158                     + "\" (requires API " + theme.apiLevel + ")");
159             return false;
160         }
161 
162         Log.v(TAG, "Generating images for theme \"" + theme.name + "\"...");
163 
164         final Intent intent = new Intent(this, ThemeDeviceActivity.class);
165         intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
166         intent.putExtra(ThemeDeviceActivity.EXTRA_THEME, mCurrentTheme);
167         intent.putExtra(ThemeDeviceActivity.EXTRA_OUTPUT_DIR, mOutputDir.getAbsolutePath());
168         startActivityForResult(intent, REQUEST_CODE);
169         return true;
170     }
171 
172     @Override
onActivityResult(int requestCode, int resultCode, Intent data)173     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
174         if (resultCode != RESULT_OK) {
175             Log.i(TAG, "FAIL:Failed to generate images for theme " + mCurrentTheme);
176             finish();
177             return;
178         }
179 
180         // Keep trying themes until one works.
181         boolean success = false;
182         while (++mCurrentTheme < ThemeDeviceActivity.THEMES.length && !success) {
183             success = generateNextImage();
184         }
185 
186         // If we ran out of themes, we're done.
187         if (!success) {
188             finish("Image generation complete!", true);
189         }
190     }
191 
finish()192     public void finish() {
193         mLatch.countDown();
194         super.finish();
195     }
196 
waitForCompletion()197     public void waitForCompletion() throws InterruptedException {
198         mLatch.await();
199     }
200 }
201