1 /* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; 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
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef AndroidBridge_h__
7 #define AndroidBridge_h__
8 
9 #include <jni.h>
10 #include <android/log.h>
11 #include <cstdlib>
12 #include <unistd.h>
13 
14 #include "APKOpen.h"
15 
16 #include "nsCOMPtr.h"
17 #include "nsCOMArray.h"
18 
19 #include "js/RootingAPI.h"
20 #include "js/Value.h"
21 #include "mozilla/jni/Refs.h"
22 
23 #include "nsIMutableArray.h"
24 #include "nsIMIMEInfo.h"
25 #include "nsColor.h"
26 #include "gfxRect.h"
27 
28 #include "nsIAndroidBridge.h"
29 
30 #include "mozilla/Likely.h"
31 #include "mozilla/Mutex.h"
32 #include "mozilla/Types.h"
33 #include "mozilla/gfx/Point.h"
34 #include "mozilla/jni/Utils.h"
35 #include "nsTHashMap.h"
36 
37 #include "Units.h"
38 
39 // Some debug #defines
40 // #define DEBUG_ANDROID_EVENTS
41 // #define DEBUG_ANDROID_WIDGET
42 
43 class nsPIDOMWindowOuter;
44 
45 typedef void* EGLSurface;
46 class nsIRunnable;
47 
48 namespace mozilla {
49 
50 class AutoLocalJNIFrame;
51 
52 namespace hal {
53 class BatteryInformation;
54 class NetworkInformation;
55 }  // namespace hal
56 
57 // The order and number of the members in this structure must correspond
58 // to the attrsAppearance array in GeckoAppShell.getSystemColors()
59 typedef struct AndroidSystemColors {
60   nscolor textColorPrimary;
61   nscolor textColorPrimaryInverse;
62   nscolor textColorSecondary;
63   nscolor textColorSecondaryInverse;
64   nscolor textColorTertiary;
65   nscolor textColorTertiaryInverse;
66   nscolor textColorHighlight;
67   nscolor colorForeground;
68   nscolor colorBackground;
69   nscolor panelColorForeground;
70   nscolor panelColorBackground;
71 } AndroidSystemColors;
72 
73 class AndroidBridge final {
74  public:
75   enum {
76     // Values for NotifyIME, in addition to values from the Gecko
77     // IMEMessage enum; use negative values here to prevent conflict
78     NOTIFY_IME_OPEN_VKB = -2,
79     NOTIFY_IME_REPLY_EVENT = -1,
80   };
81 
82   enum {
83     LAYER_CLIENT_TYPE_NONE = 0,
84     LAYER_CLIENT_TYPE_GL = 2  // AndroidGeckoGLLayerClient
85   };
86 
IsJavaUiThread()87   static bool IsJavaUiThread() {
88     return mozilla::jni::GetUIThreadId() == gettid();
89   }
90 
91   static void ConstructBridge();
92   static void DeconstructBridge();
93 
Bridge()94   static AndroidBridge* Bridge() { return sBridge; }
95 
96   bool GetHandlersForURL(const nsAString& aURL,
97                          nsIMutableArray* handlersArray = nullptr,
98                          nsIHandlerApp** aDefaultApp = nullptr,
99                          const nsAString& aAction = u""_ns);
100 
101   bool GetHandlersForMimeType(const nsAString& aMimeType,
102                               nsIMutableArray* handlersArray = nullptr,
103                               nsIHandlerApp** aDefaultApp = nullptr,
104                               const nsAString& aAction = u""_ns);
105 
106   bool HasHWVP8Encoder();
107   bool HasHWVP8Decoder();
108   bool HasHWH264();
109 
110   void GetMimeTypeFromExtensions(const nsACString& aFileExt,
111                                  nsCString& aMimeType);
112   void GetExtensionFromMimeType(const nsACString& aMimeType,
113                                 nsACString& aFileExt);
114 
115   gfx::Rect getScreenSize();
116   int GetScreenDepth();
117 
118   void Vibrate(const nsTArray<uint32_t>& aPattern);
119 
120   void GetIconForExtension(const nsACString& aFileExt, uint32_t aIconSize,
121                            uint8_t* const aBuf);
122 
123   bool GetStaticStringField(const char* classID, const char* field,
124                             nsAString& result, JNIEnv* env = nullptr);
125 
126   bool GetStaticIntField(const char* className, const char* fieldName,
127                          int32_t* aInt, JNIEnv* env = nullptr);
128 
129   // Returns a global reference to the Context for Fennec's Activity. The
130   // caller is responsible for ensuring this doesn't leak by calling
131   // DeleteGlobalRef() when the context is no longer needed.
132   jobject GetGlobalContextRef(void);
133 
134   void GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo);
135 
136   void GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo);
137 
138   // These methods don't use a ScreenOrientation because it's an
139   // enum and that would require including the header which requires
140   // include IPC headers which requires including basictypes.h which
141   // requires a lot of changes...
142   uint32_t GetScreenOrientation();
143   uint16_t GetScreenAngle();
144 
145   nsresult GetProxyForURI(const nsACString& aSpec, const nsACString& aScheme,
146                           const nsACString& aHost, const int32_t aPort,
147                           nsACString& aResult);
148 
149   bool PumpMessageLoop();
150 
151   // Utility methods.
152   static jfieldID GetFieldID(JNIEnv* env, jclass jClass, const char* fieldName,
153                              const char* fieldType);
154   static jfieldID GetStaticFieldID(JNIEnv* env, jclass jClass,
155                                    const char* fieldName,
156                                    const char* fieldType);
157   static jmethodID GetMethodID(JNIEnv* env, jclass jClass,
158                                const char* methodName, const char* methodType);
159   static jmethodID GetStaticMethodID(JNIEnv* env, jclass jClass,
160                                      const char* methodName,
161                                      const char* methodType);
162 
163   static jni::Object::LocalRef ChannelCreate(jni::Object::Param);
164 
165   static void InputStreamClose(jni::Object::Param obj);
166   static uint32_t InputStreamAvailable(jni::Object::Param obj);
167   static nsresult InputStreamRead(jni::Object::Param obj, char* aBuf,
168                                   uint32_t aCount, uint32_t* aRead);
169 
170  protected:
171   static nsTHashMap<nsStringHashKey, nsString> sStoragePaths;
172 
173   static AndroidBridge* sBridge;
174 
175   AndroidBridge();
176   ~AndroidBridge();
177 
178   jni::Object::GlobalRef mMessageQueue;
179   jfieldID mMessageQueueMessages;
180   jmethodID mMessageQueueNext;
181 };
182 
183 class AutoJNIClass {
184  private:
185   JNIEnv* const mEnv;
186   const jclass mClass;
187 
188  public:
AutoJNIClass(JNIEnv * jEnv,const char * name)189   AutoJNIClass(JNIEnv* jEnv, const char* name)
190       : mEnv(jEnv), mClass(jni::GetClassRef(jEnv, name)) {}
191 
~AutoJNIClass()192   ~AutoJNIClass() { mEnv->DeleteLocalRef(mClass); }
193 
getRawRef()194   jclass getRawRef() const { return mClass; }
195 
getGlobalRef()196   jclass getGlobalRef() const {
197     return static_cast<jclass>(mEnv->NewGlobalRef(mClass));
198   }
199 
getField(const char * name,const char * type)200   jfieldID getField(const char* name, const char* type) const {
201     return AndroidBridge::GetFieldID(mEnv, mClass, name, type);
202   }
203 
getStaticField(const char * name,const char * type)204   jfieldID getStaticField(const char* name, const char* type) const {
205     return AndroidBridge::GetStaticFieldID(mEnv, mClass, name, type);
206   }
207 
getMethod(const char * name,const char * type)208   jmethodID getMethod(const char* name, const char* type) const {
209     return AndroidBridge::GetMethodID(mEnv, mClass, name, type);
210   }
211 
getStaticMethod(const char * name,const char * type)212   jmethodID getStaticMethod(const char* name, const char* type) const {
213     return AndroidBridge::GetStaticMethodID(mEnv, mClass, name, type);
214   }
215 };
216 
217 class AutoJObject {
218  public:
mObject(nullptr)219   explicit AutoJObject(JNIEnv* aJNIEnv = nullptr) : mObject(nullptr) {
220     mJNIEnv = aJNIEnv ? aJNIEnv : jni::GetGeckoThreadEnv();
221   }
222 
AutoJObject(JNIEnv * aJNIEnv,jobject aObject)223   AutoJObject(JNIEnv* aJNIEnv, jobject aObject) {
224     mJNIEnv = aJNIEnv ? aJNIEnv : jni::GetGeckoThreadEnv();
225     mObject = aObject;
226   }
227 
~AutoJObject()228   ~AutoJObject() {
229     if (mObject) mJNIEnv->DeleteLocalRef(mObject);
230   }
231 
232   jobject operator=(jobject aObject) {
233     if (mObject) {
234       mJNIEnv->DeleteLocalRef(mObject);
235     }
236     return mObject = aObject;
237   }
238 
jobject()239   operator jobject() { return mObject; }
240 
241  private:
242   JNIEnv* mJNIEnv;
243   jobject mObject;
244 };
245 
246 class AutoLocalJNIFrame {
247  public:
248   explicit AutoLocalJNIFrame(int nEntries = 15)
mEntries(nEntries)249       : mEntries(nEntries),
250         mJNIEnv(jni::GetGeckoThreadEnv()),
251         mHasFrameBeenPushed(false) {
252     MOZ_ASSERT(mJNIEnv);
253     Push();
254   }
255 
256   explicit AutoLocalJNIFrame(JNIEnv* aJNIEnv, int nEntries = 15)
mEntries(nEntries)257       : mEntries(nEntries),
258         mJNIEnv(aJNIEnv ? aJNIEnv : jni::GetGeckoThreadEnv()),
259         mHasFrameBeenPushed(false) {
260     MOZ_ASSERT(mJNIEnv);
261     Push();
262   }
263 
~AutoLocalJNIFrame()264   ~AutoLocalJNIFrame() {
265     if (mHasFrameBeenPushed) {
266       Pop();
267     }
268   }
269 
GetEnv()270   JNIEnv* GetEnv() { return mJNIEnv; }
271 
CheckForException()272   bool CheckForException() {
273     if (mJNIEnv->ExceptionCheck()) {
274       MOZ_CATCH_JNI_EXCEPTION(mJNIEnv);
275       return true;
276     }
277     return false;
278   }
279 
280   // Note! Calling Purge makes all previous local refs created in
281   // the AutoLocalJNIFrame's scope INVALID; be sure that you locked down
282   // any local refs that you need to keep around in global refs!
Purge()283   void Purge() {
284     Pop();
285     Push();
286   }
287 
288   template <typename ReturnType = jobject>
289   ReturnType Pop(ReturnType aResult = nullptr) {
290     MOZ_ASSERT(mHasFrameBeenPushed);
291     mHasFrameBeenPushed = false;
292     return static_cast<ReturnType>(
293         mJNIEnv->PopLocalFrame(static_cast<jobject>(aResult)));
294   }
295 
296  private:
Push()297   void Push() {
298     MOZ_ASSERT(!mHasFrameBeenPushed);
299     // Make sure there is enough space to store a local ref to the
300     // exception.  I am not completely sure this is needed, but does
301     // not hurt.
302     if (mJNIEnv->PushLocalFrame(mEntries + 1) != 0) {
303       CheckForException();
304       return;
305     }
306     mHasFrameBeenPushed = true;
307   }
308 
309   const int mEntries;
310   JNIEnv* const mJNIEnv;
311   bool mHasFrameBeenPushed;
312 };
313 
314 }  // namespace mozilla
315 
316 #define NS_ANDROIDBRIDGE_CID                         \
317   {                                                  \
318     0x0FE2321D, 0xEBD9, 0x467D, {                    \
319       0xA7, 0x43, 0x03, 0xA6, 0x8D, 0x40, 0x59, 0x9E \
320     }                                                \
321   }
322 
323 class nsAndroidBridge final : public nsIAndroidBridge {
324  public:
325   NS_DECL_ISUPPORTS
326   NS_DECL_NSIANDROIDBRIDGE
327 
328   NS_FORWARD_SAFE_NSIANDROIDEVENTDISPATCHER(mEventDispatcher)
329 
330   nsAndroidBridge();
331 
332  private:
333   ~nsAndroidBridge();
334 
335   nsCOMPtr<nsIAndroidEventDispatcher> mEventDispatcher;
336 
337  protected:
338 };
339 
340 #endif /* AndroidBridge_h__ */
341