Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / ui / android / java / src / org / chromium / ui / base / WindowAndroid.java
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.ui.base;
6
7 import android.annotation.SuppressLint;
8 import android.app.Activity;
9 import android.app.PendingIntent;
10 import android.content.ContentResolver;
11 import android.content.Context;
12 import android.content.Intent;
13 import android.os.Bundle;
14 import android.util.Log;
15 import android.util.SparseArray;
16 import android.widget.Toast;
17
18 import org.chromium.base.CalledByNative;
19 import org.chromium.base.JNINamespace;
20 import org.chromium.ui.VSyncMonitor;
21
22 import java.lang.ref.WeakReference;
23 import java.util.HashMap;
24
25 /**
26  * The window base class that has the minimum functionality.
27  */
28 @JNINamespace("ui")
29 public class WindowAndroid {
30     private static final String TAG = "WindowAndroid";
31
32     // Native pointer to the c++ WindowAndroid object.
33     private long mNativeWindowAndroid = 0;
34     private final VSyncMonitor mVSyncMonitor;
35     private VSyncClient mVSyncClient = null;
36
37     // A string used as a key to store intent errors in a bundle
38     static final String WINDOW_CALLBACK_ERRORS = "window_callback_errors";
39
40     // Error code returned when an Intent fails to start an Activity.
41     public static final int START_INTENT_FAILURE = -1;
42
43     protected Context mApplicationContext;
44     protected SparseArray<IntentCallback> mOutstandingIntents;
45
46     // Ideally, this would be a SparseArray<String>, but there's no easy way to store a
47     // SparseArray<String> in a bundle during saveInstanceState(). So we use a HashMap and suppress
48     // the Android lint warning "UseSparseArrays".
49     protected HashMap<Integer, String> mIntentErrors;
50
51     private final VSyncMonitor.Listener mVSyncListener = new VSyncMonitor.Listener() {
52         @Override
53         public void onVSync(VSyncMonitor monitor, long vsyncTimeMicros) {
54             if (mVSyncClient != null) {
55                 mVSyncClient.onVSync(vsyncTimeMicros);
56             }
57             if (mNativeWindowAndroid != 0) {
58                 nativeOnVSync(mNativeWindowAndroid, vsyncTimeMicros);
59             }
60         }
61     };
62
63     /**
64      * @param context The application context.
65      */
66     @SuppressLint("UseSparseArrays")
67     public WindowAndroid(Context context) {
68         assert context == context.getApplicationContext();
69         mApplicationContext = context;
70         mOutstandingIntents = new SparseArray<IntentCallback>();
71         mIntentErrors = new HashMap<Integer, String>();
72         mVSyncMonitor = new VSyncMonitor(context, mVSyncListener);
73     }
74
75     /**
76      * Shows an intent and returns the results to the callback object.
77      * @param intent   The PendingIntent that needs to be shown.
78      * @param callback The object that will receive the results for the intent.
79      * @param errorId  The ID of error string to be show if activity is paused before intent
80      *                 results.
81      * @return Whether the intent was shown.
82      */
83     public boolean showIntent(PendingIntent intent, IntentCallback callback, int errorId) {
84         return showCancelableIntent(intent, callback, errorId) >= 0;
85     }
86
87     /**
88      * Shows an intent and returns the results to the callback object.
89      * @param intent   The intent that needs to be shown.
90      * @param callback The object that will receive the results for the intent.
91      * @param errorId  The ID of error string to be show if activity is paused before intent
92      *                 results.
93      * @return Whether the intent was shown.
94      */
95     public boolean showIntent(Intent intent, IntentCallback callback, int errorId) {
96         return showCancelableIntent(intent, callback, errorId) >= 0;
97     }
98
99     /**
100      * Shows an intent that could be canceled and returns the results to the callback object.
101      * @param  intent   The PendingIntent that needs to be shown.
102      * @param  callback The object that will receive the results for the intent.
103      * @param  errorId  The ID of error string to be show if activity is paused before intent
104      *                  results.
105      * @return A non-negative request code that could be used for finishActivity, or
106      *         START_INTENT_FAILURE if failed.
107      */
108     public int showCancelableIntent(PendingIntent intent, IntentCallback callback, int errorId) {
109         Log.d(TAG, "Can't show intent as context is not an Activity: " + intent);
110         return START_INTENT_FAILURE;
111     }
112
113     /**
114      * Shows an intent that could be canceled and returns the results to the callback object.
115      * @param  intent   The intent that needs to be showed.
116      * @param  callback The object that will receive the results for the intent.
117      * @param  errorId  The ID of error string to be show if activity is paused before intent
118      *                  results.
119      * @return A non-negative request code that could be used for finishActivity, or
120      *         START_INTENT_FAILURE if failed.
121      */
122     public int showCancelableIntent(Intent intent, IntentCallback callback, int errorId) {
123         Log.d(TAG, "Can't show intent as context is not an Activity: " + intent);
124         return START_INTENT_FAILURE;
125     }
126
127     /**
128      * Force finish another activity that you had previously started with showCancelableIntent.
129      * @param requestCode The request code returned from showCancelableIntent.
130      */
131     public void cancelIntent(int requestCode) {
132         Log.d(TAG, "Can't cancel intent as context is not an Activity: " + requestCode);
133     }
134
135     /**
136      * Removes a callback from the list of pending intents, so that nothing happens if/when the
137      * result for that intent is received.
138      * @param callback The object that should have received the results
139      * @return True if the callback was removed, false if it was not found.
140     */
141     public boolean removeIntentCallback(IntentCallback callback) {
142         int requestCode = mOutstandingIntents.indexOfValue(callback);
143         if (requestCode < 0) return false;
144         mOutstandingIntents.remove(requestCode);
145         mIntentErrors.remove(requestCode);
146         return true;
147     }
148
149     /**
150      * Displays an error message with a provided error message string.
151      * @param error The error message string to be displayed.
152      */
153     public void showError(String error) {
154         if (error != null) {
155             Toast.makeText(mApplicationContext, error, Toast.LENGTH_SHORT).show();
156         }
157     }
158
159     /**
160      * Displays an error message from the given resource id.
161      * @param resId The error message string's resource id.
162      */
163     public void showError(int resId) {
164         showError(mApplicationContext.getString(resId));
165     }
166
167     /**
168      * Displays an error message for a nonexistent callback.
169      * @param error The error message string to be displayed.
170      */
171     protected void showCallbackNonExistentError(String error) {
172         showError(error);
173     }
174
175     /**
176      * Broadcasts the given intent to all interested BroadcastReceivers.
177      */
178     public void sendBroadcast(Intent intent) {
179         mApplicationContext.sendBroadcast(intent);
180     }
181
182     /**
183      * @return A reference to owning Activity.  The returned WeakReference will never be null, but
184      *         the contained Activity can be null (either if it has been garbage collected or if
185      *         this is in the context of a WebView that was not created using an Activity).
186      */
187     public WeakReference<Activity> getActivity() {
188         return new WeakReference<Activity>(null);
189     }
190
191     /**
192      * @return The application context for this activity.
193      */
194     public Context getApplicationContext() {
195         return mApplicationContext;
196     }
197
198     /**
199      * Saves the error messages that should be shown if any pending intents would return
200      * after the application has been put onPause.
201      * @param bundle The bundle to save the information in onPause
202      */
203     public void saveInstanceState(Bundle bundle) {
204         bundle.putSerializable(WINDOW_CALLBACK_ERRORS, mIntentErrors);
205     }
206
207     /**
208      * Restores the error messages that should be shown if any pending intents would return
209      * after the application has been put onPause.
210      * @param bundle The bundle to restore the information from onResume
211      */
212     public void restoreInstanceState(Bundle bundle) {
213         if (bundle == null) return;
214
215         Object errors = bundle.getSerializable(WINDOW_CALLBACK_ERRORS);
216         if (errors instanceof HashMap) {
217             @SuppressWarnings("unchecked")
218             HashMap<Integer, String> intentErrors = (HashMap<Integer, String>) errors;
219             mIntentErrors = intentErrors;
220         }
221     }
222
223     /**
224      * Responds to the intent result if the intent was created by the native window.
225      * @param requestCode Request code of the requested intent.
226      * @param resultCode Result code of the requested intent.
227      * @param data The data returned by the intent.
228      * @return Boolean value of whether the intent was started by the native window.
229      */
230     public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
231         return false;
232     }
233
234     /**
235      * An interface to receive VSync notifications from the window.
236      * The one and only client is set with setVSyncClient(client).
237      */
238     public interface VSyncClient {
239         /**
240          * Called very soon after the start of the display's vertical sync period.
241          * @param vsyncTimeMicros Absolute frame time in microseconds.
242          */
243         void onVSync(long vsyncTimeMicros);
244     }
245
246     /**
247      * Sets the VSyncClient.
248      * @param client The client receiving VSync notifications.
249      */
250     public void setVSyncClient(VSyncClient client) {
251         assert mVSyncClient == null || client == null;
252         mVSyncClient = client;
253     }
254
255     /**
256      * Request a VSync callback.
257      * VSyncClient.onVSync() will be called at least once.
258      */
259     @CalledByNative
260     public void requestVSyncUpdate() {
261         mVSyncMonitor.requestUpdate();
262     }
263
264     /**
265      * An interface that intent callback objects have to implement.
266      */
267     public interface IntentCallback {
268         /**
269          * Handles the data returned by the requested intent.
270          * @param window A window reference.
271          * @param resultCode Result code of the requested intent.
272          * @param contentResolver An instance of ContentResolver class for accessing returned data.
273          * @param data The data returned by the intent.
274          */
275         void onIntentCompleted(WindowAndroid window, int resultCode,
276                 ContentResolver contentResolver, Intent data);
277     }
278
279     /**
280      * Tests that an activity is available to handle the passed in intent.
281      * @param  intent The intent to check.
282      * @return True if an activity is available to process this intent when started, meaning that
283      *         Context.startActivity will not throw ActivityNotFoundException.
284      */
285     public boolean canResolveActivity(Intent intent) {
286         return mApplicationContext.getPackageManager().resolveActivity(intent, 0) != null;
287     }
288
289     /**
290      * Destroys the c++ WindowAndroid object if one has been created.
291      */
292     public void destroy() {
293         if (mNativeWindowAndroid != 0) {
294             nativeDestroy(mNativeWindowAndroid);
295             mNativeWindowAndroid = 0;
296         }
297     }
298
299     /**
300      * Returns a pointer to the c++ AndroidWindow object and calls the initializer if
301      * the object has not been previously initialized.
302      * @return A pointer to the c++ AndroidWindow.
303      */
304     public long getNativePointer() {
305         if (mNativeWindowAndroid == 0) {
306             mNativeWindowAndroid = nativeInit(mVSyncMonitor.getVSyncPeriodInMicroseconds());
307         }
308         return mNativeWindowAndroid;
309     }
310
311     /**
312      * Returns a PNG-encoded screenshot of the the window region at (|windowX|,
313      * |windowY|) with the size |width| by |height| pixels.
314      */
315     @CalledByNative
316     public byte[] grabSnapshot(int windowX, int windowY, int width, int height) {
317         return null;
318     }
319
320     private native long nativeInit(long vsyncPeriod);
321     private native void nativeOnVSync(long nativeWindowAndroid, long vsyncTimeMicros);
322     private native void nativeDestroy(long nativeWindowAndroid);
323
324 }