mobile/android/base/GeckoScreenOrientation.java

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:2012bed10d73
1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 package org.mozilla.gecko;
7
8 import android.content.Context;
9 import android.content.pm.ActivityInfo;
10 import android.content.res.Configuration;
11 import android.util.Log;
12 import android.view.Surface;
13 import android.app.Activity;
14
15 import java.util.Arrays;
16 import java.util.List;
17
18 /*
19 * Updates, locks and unlocks the screen orientation.
20 *
21 * Note: Replaces the OnOrientationChangeListener to avoid redundant rotation
22 * event handling.
23 */
24 public class GeckoScreenOrientation {
25 private static final String LOGTAG = "GeckoScreenOrientation";
26
27 // Make sure that any change in dom/base/ScreenOrientation.h happens here too.
28 public enum ScreenOrientation {
29 NONE(0),
30 PORTRAIT_PRIMARY(1 << 0),
31 PORTRAIT_SECONDARY(1 << 1),
32 LANDSCAPE_PRIMARY(1 << 2),
33 LANDSCAPE_SECONDARY(1 << 3),
34 DEFAULT(1 << 4);
35
36 public final short value;
37
38 private ScreenOrientation(int value) {
39 this.value = (short)value;
40 }
41
42 public static ScreenOrientation get(short value) {
43 switch (value) {
44 case (1 << 0): return PORTRAIT_PRIMARY;
45 case (1 << 1): return PORTRAIT_SECONDARY;
46 case (1 << 2): return LANDSCAPE_PRIMARY;
47 case (1 << 3): return LANDSCAPE_SECONDARY;
48 case (1 << 4): return DEFAULT;
49 default: return NONE;
50 }
51 }
52 }
53
54 // Singleton instance.
55 private static GeckoScreenOrientation sInstance = null;
56 // Default screen orientation, used for initialization and unlocking.
57 private static final ScreenOrientation DEFAULT_SCREEN_ORIENTATION = ScreenOrientation.DEFAULT;
58 // Default rotation, used when device rotation is unknown.
59 private static final int DEFAULT_ROTATION = Surface.ROTATION_0;
60 // Default orientation, used if screen orientation is unspecified.
61 private ScreenOrientation mDefaultScreenOrientation;
62 // Last updated screen orientation.
63 private ScreenOrientation mScreenOrientation;
64 // Whether the update should notify Gecko about screen orientation changes.
65 private boolean mShouldNotify = true;
66 // Configuration screen orientation preference path.
67 private static final String DEFAULT_SCREEN_ORIENTATION_PREF = "app.orientation.default";
68
69 public GeckoScreenOrientation() {
70 PrefsHelper.getPref(DEFAULT_SCREEN_ORIENTATION_PREF, new PrefsHelper.PrefHandlerBase() {
71 @Override public void prefValue(String pref, String value) {
72 // Read and update the configuration default preference.
73 mDefaultScreenOrientation = screenOrientationFromArrayString(value);
74 setRequestedOrientation(mDefaultScreenOrientation);
75 }
76 });
77
78 mDefaultScreenOrientation = DEFAULT_SCREEN_ORIENTATION;
79 update();
80 }
81
82 public static GeckoScreenOrientation getInstance() {
83 if (sInstance == null) {
84 sInstance = new GeckoScreenOrientation();
85 }
86 return sInstance;
87 }
88
89 /*
90 * Enable Gecko screen orientation events on update.
91 */
92 public void enableNotifications() {
93 update();
94 mShouldNotify = true;
95 }
96
97 /*
98 * Disable Gecko screen orientation events on update.
99 */
100 public void disableNotifications() {
101 mShouldNotify = false;
102 }
103
104 /*
105 * Update screen orientation.
106 * Retrieve orientation and rotation via GeckoAppShell.
107 *
108 * @return Whether the screen orientation has changed.
109 */
110 public boolean update() {
111 Activity activity = GeckoAppShell.getGeckoInterface().getActivity();
112 if (activity == null) {
113 return false;
114 }
115 Configuration config = activity.getResources().getConfiguration();
116 return update(config.orientation);
117 }
118
119 /*
120 * Update screen orientation given the android orientation.
121 * Retrieve rotation via GeckoAppShell.
122 *
123 * @param aAndroidOrientation
124 * Android screen orientation from Configuration.orientation.
125 *
126 * @return Whether the screen orientation has changed.
127 */
128 public boolean update(int aAndroidOrientation) {
129 return update(getScreenOrientation(aAndroidOrientation, getRotation()));
130 }
131
132 /*
133 * Update screen orientation given the screen orientation.
134 *
135 * @param aScreenOrientation
136 * Gecko screen orientation based on android orientation and rotation.
137 *
138 * @return Whether the screen orientation has changed.
139 */
140 public boolean update(ScreenOrientation aScreenOrientation) {
141 if (mScreenOrientation == aScreenOrientation) {
142 return false;
143 }
144 mScreenOrientation = aScreenOrientation;
145 Log.d(LOGTAG, "updating to new orientation " + mScreenOrientation);
146 if (mShouldNotify) {
147 GeckoAppShell.sendEventToGecko(GeckoEvent.createScreenOrientationEvent(mScreenOrientation.value));
148 }
149 return true;
150 }
151
152 /*
153 * @return The Android orientation (Configuration.orientation).
154 */
155 public int getAndroidOrientation() {
156 return screenOrientationToAndroidOrientation(getScreenOrientation());
157 }
158
159 /*
160 * @return The Gecko screen orientation derived from Android orientation and
161 * rotation.
162 */
163 public ScreenOrientation getScreenOrientation() {
164 return mScreenOrientation;
165 }
166
167 /*
168 * Lock screen orientation given the Android orientation.
169 * Retrieve rotation via GeckoAppShell.
170 *
171 * @param aAndroidOrientation
172 * The Android orientation provided by Configuration.orientation.
173 */
174 public void lock(int aAndroidOrientation) {
175 lock(getScreenOrientation(aAndroidOrientation, getRotation()));
176 }
177
178 /*
179 * Lock screen orientation given the Gecko screen orientation.
180 * Retrieve rotation via GeckoAppShell.
181 *
182 * @param aScreenOrientation
183 * Gecko screen orientation derived from Android orientation and
184 * rotation.
185 *
186 * @return Whether the locking was successful.
187 */
188 public boolean lock(ScreenOrientation aScreenOrientation) {
189 Log.d(LOGTAG, "locking to " + aScreenOrientation);
190 update(aScreenOrientation);
191 return setRequestedOrientation(aScreenOrientation);
192 }
193
194 /*
195 * Unlock and update screen orientation.
196 *
197 * @return Whether the unlocking was successful.
198 */
199 public boolean unlock() {
200 Log.d(LOGTAG, "unlocking");
201 setRequestedOrientation(mDefaultScreenOrientation);
202 return update();
203 }
204
205 /*
206 * Set the given requested orientation for the current activity.
207 * This is essentially an unlock without an update.
208 *
209 * @param aScreenOrientation
210 * Gecko screen orientation.
211 *
212 * @return Whether the requested orientation was set. This can only fail if
213 * the current activity cannot be retrieved vie GeckoAppShell.
214 *
215 */
216 private boolean setRequestedOrientation(ScreenOrientation aScreenOrientation) {
217 int activityOrientation = screenOrientationToActivityInfoOrientation(aScreenOrientation);
218 Activity activity = GeckoAppShell.getGeckoInterface().getActivity();
219 if (activity == null) {
220 Log.w(LOGTAG, "setRequestOrientation: failed to get activity");
221 }
222 if (activity.getRequestedOrientation() == activityOrientation) {
223 return false;
224 }
225 activity.setRequestedOrientation(activityOrientation);
226 return true;
227 }
228
229 /*
230 * Combine the Android orientation and rotation to the Gecko orientation.
231 *
232 * @param aAndroidOrientation
233 * Android orientation from Configuration.orientation.
234 * @param aRotation
235 * Device rotation from Display.getRotation().
236 *
237 * @return Gecko screen orientation.
238 */
239 private ScreenOrientation getScreenOrientation(int aAndroidOrientation, int aRotation) {
240 boolean isPrimary = aRotation == Surface.ROTATION_0 || aRotation == Surface.ROTATION_90;
241 if (aAndroidOrientation == Configuration.ORIENTATION_PORTRAIT) {
242 if (isPrimary) {
243 // Non-rotated portrait device or landscape device rotated
244 // to primary portrait mode counter-clockwise.
245 return ScreenOrientation.PORTRAIT_PRIMARY;
246 }
247 return ScreenOrientation.PORTRAIT_SECONDARY;
248 }
249 if (aAndroidOrientation == Configuration.ORIENTATION_LANDSCAPE) {
250 if (isPrimary) {
251 // Non-rotated landscape device or portrait device rotated
252 // to primary landscape mode counter-clockwise.
253 return ScreenOrientation.LANDSCAPE_PRIMARY;
254 }
255 return ScreenOrientation.LANDSCAPE_SECONDARY;
256 }
257 return ScreenOrientation.NONE;
258 }
259
260 /*
261 * @return Device rotation from Display.getRotation().
262 */
263 private int getRotation() {
264 Activity activity = GeckoAppShell.getGeckoInterface().getActivity();
265 if (activity == null) {
266 Log.w(LOGTAG, "getRotation: failed to get activity");
267 return DEFAULT_ROTATION;
268 }
269 return activity.getWindowManager().getDefaultDisplay().getRotation();
270 }
271
272 /*
273 * Retrieve the screen orientation from an array string.
274 *
275 * @param aArray
276 * String containing comma-delimited strings.
277 *
278 * @return First parsed Gecko screen orientation.
279 */
280 public static ScreenOrientation screenOrientationFromArrayString(String aArray) {
281 List<String> orientations = Arrays.asList(aArray.split(","));
282 if (orientations.size() == 0) {
283 // If nothing is listed, return default.
284 Log.w(LOGTAG, "screenOrientationFromArrayString: no orientation in string");
285 return DEFAULT_SCREEN_ORIENTATION;
286 }
287
288 // We don't support multiple orientations yet. To avoid developer
289 // confusion, just take the first one listed.
290 return screenOrientationFromString(orientations.get(0));
291 }
292
293 /*
294 * Retrieve the scren orientation from a string.
295 *
296 * @param aStr
297 * String hopefully containing a screen orientation name.
298 * @return Gecko screen orientation if matched, DEFAULT_SCREEN_ORIENTATION
299 * otherwise.
300 */
301 public static ScreenOrientation screenOrientationFromString(String aStr) {
302 if ("portrait".equals(aStr)) {
303 return ScreenOrientation.PORTRAIT_PRIMARY;
304 }
305 else if ("landscape".equals(aStr)) {
306 return ScreenOrientation.LANDSCAPE_PRIMARY;
307 }
308 else if ("portrait-primary".equals(aStr)) {
309 return ScreenOrientation.PORTRAIT_PRIMARY;
310 }
311 else if ("portrait-secondary".equals(aStr)) {
312 return ScreenOrientation.PORTRAIT_SECONDARY;
313 }
314 else if ("landscape-primary".equals(aStr)) {
315 return ScreenOrientation.LANDSCAPE_PRIMARY;
316 }
317 else if ("landscape-secondary".equals(aStr)) {
318 return ScreenOrientation.LANDSCAPE_SECONDARY;
319 }
320 Log.w(LOGTAG, "screenOrientationFromString: unknown orientation string");
321 return DEFAULT_SCREEN_ORIENTATION;
322 }
323
324 /*
325 * Convert Gecko screen orientation to Android orientation.
326 *
327 * @param aScreenOrientation
328 * Gecko screen orientation.
329 * @return Android orientation. This conversion is lossy, the Android
330 * orientation does not differentiate between primary and secondary
331 * orientations.
332 */
333 public static int screenOrientationToAndroidOrientation(ScreenOrientation aScreenOrientation) {
334 switch (aScreenOrientation) {
335 case PORTRAIT_PRIMARY:
336 case PORTRAIT_SECONDARY:
337 return Configuration.ORIENTATION_PORTRAIT;
338 case LANDSCAPE_PRIMARY:
339 case LANDSCAPE_SECONDARY:
340 return Configuration.ORIENTATION_LANDSCAPE;
341 case NONE:
342 case DEFAULT:
343 default:
344 return Configuration.ORIENTATION_UNDEFINED;
345 }
346 }
347
348
349 /*
350 * Convert Gecko screen orientation to Android ActivityInfo orientation.
351 * This is yet another orientation used by Android, but it's more detailed
352 * than the Android orientation.
353 * It is required for screen orientation locking and unlocking.
354 *
355 * @param aScreenOrientation
356 * Gecko screen orientation.
357 * @return Android ActivityInfo orientation.
358 */
359 public static int screenOrientationToActivityInfoOrientation(ScreenOrientation aScreenOrientation) {
360 switch (aScreenOrientation) {
361 case PORTRAIT_PRIMARY:
362 return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
363 case PORTRAIT_SECONDARY:
364 return ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
365 case LANDSCAPE_PRIMARY:
366 return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
367 case LANDSCAPE_SECONDARY:
368 return ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
369 case DEFAULT:
370 case NONE:
371 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
372 default:
373 return ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
374 }
375 }
376 }

mercurial