1 /*
2  * Copyright (C) 2010 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.app.stubs;
18 
19 import static org.junit.Assert.assertTrue;
20 
21 import android.app.Activity;
22 import android.content.pm.ActivityInfo;
23 import android.content.res.Resources;
24 import android.view.DisplayInfo;
25 
26 import java.util.concurrent.CountDownLatch;
27 import java.util.concurrent.TimeUnit;
28 import java.util.concurrent.atomic.AtomicReference;
29 
30 public class OrientationTestUtils {
31     /**
32      * Change the activity's orientation to something different and then switch back. This is used
33      * to trigger {@link Activity#onConfigurationChanged(android.content.res.Configuration)}.
34      *
35      * @param activity whose orientation will be changed and restored
36      */
toggleOrientation(Activity activity)37     public static void toggleOrientation(Activity activity) {
38         final int[] orientations = getOrientations(activity);
39         activity.setRequestedOrientation(orientations[1]);
40         activity.setRequestedOrientation(orientations[0]);
41     }
42 
43     /**
44      * Switches the device's orientation from landscape to portrait or portrait to landscape.
45      *
46      * @param activity whose orientation will be changed
47      * @return original orientation
48      */
switchOrientation(final Activity activity)49     public static void switchOrientation(final Activity activity) {
50         final int[] orientations = getOrientations(activity);
51         activity.setRequestedOrientation(orientations[1]);
52     }
53 
54     /**
55      * Returns display original orientation and toggled orientation.
56      * @param activity context to get the display info
57      * @return The first element is original orientation and the second element is toggled
58      *     orientation.
59      */
getOrientations(final Activity activity)60     private static int[] getOrientations(final Activity activity) {
61         // Check the display dimension to get the current device orientation.
62         final DisplayInfo displayInfo = new DisplayInfo();
63         activity.getDisplay().getDisplayInfo(displayInfo);
64         final int originalOrientation = displayInfo.logicalWidth > displayInfo.logicalHeight
65                 ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
66                 : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
67         final int newOrientation = originalOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
68                 ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
69                 : ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
70         return new int[] { originalOrientation, newOrientation };
71     }
72 
73     /** Checks whether the display dimension is close to square. */
isCloseToSquareDisplay(final Activity activity)74     public static boolean isCloseToSquareDisplay(final Activity activity) {
75         final Resources resources = activity.getResources();
76         final float closeToSquareMaxAspectRatio;
77         try {
78             closeToSquareMaxAspectRatio = resources.getFloat(resources.getIdentifier(
79                     "config_closeToSquareDisplayMaxAspectRatio", "dimen", "android"));
80         } catch (Resources.NotFoundException e) {
81             // Assume device is not close to square.
82             return false;
83         }
84         final DisplayInfo displayInfo = new DisplayInfo();
85         activity.getDisplay().getDisplayInfo(displayInfo);
86         final int w = displayInfo.logicalWidth;
87         final int h = displayInfo.logicalHeight;
88         final float aspectRatio = Math.max(w, h) / (float) Math.min(w, h);
89         return aspectRatio <= closeToSquareMaxAspectRatio;
90     }
91 
92     /**
93      * Observer used in stub activities to wait for some event.
94      */
95     public static class Observer {
96         private static final int TIMEOUT_SEC = 3;
97         private final AtomicReference<CountDownLatch> mLatch = new AtomicReference();
98 
99         /**
100          * Starts observing event.
101          * The returned CountDownLatch will get activated when onObserved is invoked after this
102          * call. The method cannot be called multiple times unless reset() is invoked.
103          * @return CountDownLatch will get activated when onObserved is invoked after this call.
104          */
startObserving()105         public void startObserving() {
106             final CountDownLatch latch = new CountDownLatch(1);
107             assertTrue(mLatch.compareAndSet(null, latch));
108         }
109 
110         /**
111          * Waits until onObserved is invoked.
112          */
await()113         public void await() throws InterruptedException {
114             try {
115                 assertTrue(mLatch.get().await(TIMEOUT_SEC, TimeUnit.SECONDS));
116             } finally {
117                 mLatch.set(null);
118             }
119         }
120 
121         /**
122          * Notifies an event is observed.
123          * If this method is invoked after startObserving, the returned CountDownLatch will get
124          * activated. Otherwise it does nothing.
125          */
onObserved()126         public void onObserved() {
127             final CountDownLatch latch = mLatch.get();
128             if (latch != null) {
129                 latch.countDown();
130             }
131         }
132     }
133 }
134