1 | // Copyright (c) 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; |
6 | |
7 | import android.app.Activity; |
8 | import android.content.ActivityNotFoundException; |
9 | import android.content.ContentResolver; |
10 | import android.content.Context; |
11 | import android.content.Intent; |
12 | import android.os.Bundle; |
13 | import android.util.SparseArray; |
14 | import android.widget.Toast; |
15 | |
16 | import java.util.HashMap; |
17 | |
18 | import org.chromium.base.JNINamespace; |
19 | |
20 | /** |
21 | * The window base class that has the minimum functionality. |
22 | */ |
23 | @JNINamespace("ui") |
24 | public class WindowAndroid { |
25 | |
26 | // Native pointer to the c++ WindowAndroid object. |
27 | private int mNativeWindowAndroid = 0; |
28 | |
29 | // Constants used for intent request code bounding. |
30 | private static final int REQUEST_CODE_PREFIX = 1000; |
31 | private static final int REQUEST_CODE_RANGE_SIZE = 100; |
32 | // A string used as a key to store intent errors in a bundle |
33 | static final String WINDOW_CALLBACK_ERRORS = "window_callback_errors"; |
34 | |
35 | private int mNextRequestCode = 0; |
36 | protected Activity mActivity; |
37 | protected SparseArray<IntentCallback> mOutstandingIntents; |
38 | protected HashMap<Integer, String> mIntentErrors; |
39 | |
40 | /** |
41 | * @param activity |
42 | */ |
43 | public WindowAndroid(Activity activity) { |
44 | mActivity = activity; |
45 | mOutstandingIntents = new SparseArray<IntentCallback>(); |
46 | mIntentErrors = new HashMap<Integer, String>(); |
47 | |
48 | } |
49 | |
50 | /** |
51 | * Shows an intent and returns the results to the callback object. |
52 | * @param intent The intent that needs to be showed. |
53 | * @param callback The object that will receive the results for the intent. |
54 | * @param errorId The ID of error string to be show if activity is paused before intent |
55 | * results. |
56 | * @return Whether the intent was shown. |
57 | */ |
58 | public boolean showIntent(Intent intent, IntentCallback callback, int errorId) { |
59 | int requestCode = REQUEST_CODE_PREFIX + mNextRequestCode; |
60 | mNextRequestCode = (mNextRequestCode + 1) % REQUEST_CODE_RANGE_SIZE; |
61 | |
62 | try { |
63 | mActivity.startActivityForResult(intent, requestCode); |
64 | } catch (ActivityNotFoundException e) { |
65 | return false; |
66 | } |
67 | |
68 | mOutstandingIntents.put(requestCode, callback); |
69 | mIntentErrors.put(requestCode, mActivity.getString(errorId)); |
70 | |
71 | return true; |
72 | } |
73 | |
74 | /** |
75 | * Displays an error message with a provided error message string. |
76 | * @param error The error message string to be displayed. |
77 | */ |
78 | public void showError(String error) { |
79 | if (error != null) { |
80 | Toast.makeText(mActivity, error, Toast.LENGTH_SHORT).show(); |
81 | } |
82 | } |
83 | |
84 | /** |
85 | * Displays an error message from the given resource id. |
86 | * @param resId The error message string's resource id. |
87 | */ |
88 | public void showError(int resId) { |
89 | showError(mActivity.getString(resId)); |
90 | } |
91 | |
92 | /** |
93 | * Displays an error message for a nonexistent callback. |
94 | * @param error The error message string to be displayed. |
95 | */ |
96 | protected void showCallbackNonExistentError(String error) { |
97 | showError(error); |
98 | } |
99 | |
100 | /** |
101 | * Broadcasts the given intent to all interested BroadcastReceivers. |
102 | */ |
103 | public void sendBroadcast(Intent intent) { |
104 | mActivity.sendBroadcast(intent); |
105 | } |
106 | |
107 | /** |
108 | * TODO(nileshagrawal): Stop returning Activity Context crbug.com/233440. |
109 | * @return Activity context. |
110 | */ |
111 | @Deprecated |
112 | public Context getContext() { |
113 | return mActivity; |
114 | } |
115 | |
116 | /** |
117 | * Saves the error messages that should be shown if any pending intents would return |
118 | * after the application has been put onPause. |
119 | * @param bundle The bundle to save the information in onPause |
120 | */ |
121 | public void saveInstanceState(Bundle bundle) { |
122 | bundle.putSerializable(WINDOW_CALLBACK_ERRORS, mIntentErrors); |
123 | } |
124 | |
125 | /** |
126 | * Restores the error messages that should be shown if any pending intents would return |
127 | * after the application has been put onPause. |
128 | * @param bundle The bundle to restore the information from onResume |
129 | */ |
130 | public void restoreInstanceState(Bundle bundle) { |
131 | if (bundle == null) return; |
132 | |
133 | Object errors = bundle.getSerializable(WINDOW_CALLBACK_ERRORS); |
134 | if (errors instanceof HashMap) { |
135 | @SuppressWarnings("unchecked") |
136 | HashMap<Integer, String> intentErrors = (HashMap<Integer, String>) errors; |
137 | mIntentErrors = intentErrors; |
138 | } |
139 | } |
140 | |
141 | /** |
142 | * Responds to the intent result if the intent was created by the native window. |
143 | * @param requestCode Request code of the requested intent. |
144 | * @param resultCode Result code of the requested intent. |
145 | * @param data The data returned by the intent. |
146 | * @return Boolean value of whether the intent was started by the native window. |
147 | */ |
148 | public boolean onActivityResult(int requestCode, int resultCode, Intent data) { |
149 | IntentCallback callback = mOutstandingIntents.get(requestCode); |
150 | mOutstandingIntents.delete(requestCode); |
151 | String errorMessage = mIntentErrors.remove(requestCode); |
152 | |
153 | if (callback != null) { |
154 | callback.onIntentCompleted(this, resultCode, |
155 | mActivity.getContentResolver(), data); |
156 | return true; |
157 | } else { |
158 | if (errorMessage != null) { |
159 | showCallbackNonExistentError(errorMessage); |
160 | return true; |
161 | } |
162 | } |
163 | return false; |
164 | } |
165 | |
166 | /** |
167 | * An interface that intent callback objects have to implement. |
168 | */ |
169 | public interface IntentCallback { |
170 | /** |
171 | * Handles the data returned by the requested intent. |
172 | * @param window A window reference. |
173 | * @param resultCode Result code of the requested intent. |
174 | * @param contentResolver An instance of ContentResolver class for accessing returned data. |
175 | * @param data The data returned by the intent. |
176 | */ |
177 | public void onIntentCompleted(WindowAndroid window, int resultCode, |
178 | ContentResolver contentResolver, Intent data); |
179 | } |
180 | |
181 | /** |
182 | * Destroys the c++ WindowAndroid object if one has been created. |
183 | */ |
184 | public void destroy() { |
185 | if (mNativeWindowAndroid != 0) { |
186 | nativeDestroy(mNativeWindowAndroid); |
187 | mNativeWindowAndroid = 0; |
188 | } |
189 | } |
190 | |
191 | /** |
192 | * Returns a pointer to the c++ AndroidWindow object and calls the initializer if |
193 | * the object has not been previously initialized. |
194 | * @return A pointer to the c++ AndroidWindow. |
195 | */ |
196 | public int getNativePointer() { |
197 | if (mNativeWindowAndroid == 0) { |
198 | mNativeWindowAndroid = nativeInit(); |
199 | } |
200 | return mNativeWindowAndroid; |
201 | } |
202 | |
203 | private native int nativeInit(); |
204 | private native void nativeDestroy(int nativeWindowAndroid); |
205 | |
206 | } |