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 <unistd.h>  // for gettid
10 
11 #include "nsCOMPtr.h"
12 
13 #include "mozilla/jni/Refs.h"
14 
15 #include "nsIMutableArray.h"
16 #include "nsIMIMEInfo.h"
17 
18 #include "nsIAndroidBridge.h"
19 
20 #include "mozilla/jni/Utils.h"
21 #include "nsTHashMap.h"
22 
23 // Some debug #defines
24 // #define DEBUG_ANDROID_EVENTS
25 // #define DEBUG_ANDROID_WIDGET
26 
27 namespace mozilla {
28 
29 class AutoLocalJNIFrame;
30 
31 namespace hal {
32 class BatteryInformation;
33 class NetworkInformation;
34 enum class ScreenOrientation : uint32_t;
35 }  // namespace hal
36 
37 class AndroidBridge final {
38  public:
IsJavaUiThread()39   static bool IsJavaUiThread() {
40     return mozilla::jni::GetUIThreadId() == gettid();
41   }
42 
43   static void ConstructBridge();
44   static void DeconstructBridge();
45 
Bridge()46   static AndroidBridge* Bridge() { return sBridge; }
47 
48   bool GetHandlersForURL(const nsAString& aURL,
49                          nsIMutableArray* handlersArray = nullptr,
50                          nsIHandlerApp** aDefaultApp = nullptr,
51                          const nsAString& aAction = u""_ns);
52 
53   bool GetHandlersForMimeType(const nsAString& aMimeType,
54                               nsIMutableArray* handlersArray = nullptr,
55                               nsIHandlerApp** aDefaultApp = nullptr,
56                               const nsAString& aAction = u""_ns);
57 
58   void GetMimeTypeFromExtensions(const nsACString& aFileExt,
59                                  nsCString& aMimeType);
60   void GetExtensionFromMimeType(const nsACString& aMimeType,
61                                 nsACString& aFileExt);
62 
63   void Vibrate(const nsTArray<uint32_t>& aPattern);
64 
65   void GetIconForExtension(const nsACString& aFileExt, uint32_t aIconSize,
66                            uint8_t* const aBuf);
67 
68   bool GetStaticStringField(const char* classID, const char* field,
69                             nsAString& result, JNIEnv* env = nullptr);
70 
71   bool GetStaticIntField(const char* className, const char* fieldName,
72                          int32_t* aInt, JNIEnv* env = nullptr);
73 
74   // Returns a global reference to the Context for Fennec's Activity. The
75   // caller is responsible for ensuring this doesn't leak by calling
76   // DeleteGlobalRef() when the context is no longer needed.
77   jobject GetGlobalContextRef(void);
78 
79   void GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo);
80 
81   void GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo);
82 
83   hal::ScreenOrientation GetScreenOrientation();
84   uint16_t GetScreenAngle();
85 
86   nsresult GetProxyForURI(const nsACString& aSpec, const nsACString& aScheme,
87                           const nsACString& aHost, const int32_t aPort,
88                           nsACString& aResult);
89 
90   bool PumpMessageLoop();
91 
92   // Utility methods.
93   static jfieldID GetFieldID(JNIEnv* env, jclass jClass, const char* fieldName,
94                              const char* fieldType);
95   static jfieldID GetStaticFieldID(JNIEnv* env, jclass jClass,
96                                    const char* fieldName,
97                                    const char* fieldType);
98   static jmethodID GetMethodID(JNIEnv* env, jclass jClass,
99                                const char* methodName, const char* methodType);
100   static jmethodID GetStaticMethodID(JNIEnv* env, jclass jClass,
101                                      const char* methodName,
102                                      const char* methodType);
103 
104   static jni::Object::LocalRef ChannelCreate(jni::Object::Param);
105 
106   static void InputStreamClose(jni::Object::Param obj);
107   static uint32_t InputStreamAvailable(jni::Object::Param obj);
108   static nsresult InputStreamRead(jni::Object::Param obj, char* aBuf,
109                                   uint32_t aCount, uint32_t* aRead);
110 
111  protected:
112   static nsTHashMap<nsStringHashKey, nsString> sStoragePaths;
113 
114   static AndroidBridge* sBridge;
115 
116   AndroidBridge();
117   ~AndroidBridge();
118 
119   jni::Object::GlobalRef mMessageQueue;
120   jfieldID mMessageQueueMessages;
121   jmethodID mMessageQueueNext;
122 };
123 
124 class AutoJNIClass {
125  private:
126   JNIEnv* const mEnv;
127   const jclass mClass;
128 
129  public:
AutoJNIClass(JNIEnv * jEnv,const char * name)130   AutoJNIClass(JNIEnv* jEnv, const char* name)
131       : mEnv(jEnv), mClass(jni::GetClassRef(jEnv, name)) {}
132 
~AutoJNIClass()133   ~AutoJNIClass() { mEnv->DeleteLocalRef(mClass); }
134 
getRawRef()135   jclass getRawRef() const { return mClass; }
136 
getGlobalRef()137   jclass getGlobalRef() const {
138     return static_cast<jclass>(mEnv->NewGlobalRef(mClass));
139   }
140 
getField(const char * name,const char * type)141   jfieldID getField(const char* name, const char* type) const {
142     return AndroidBridge::GetFieldID(mEnv, mClass, name, type);
143   }
144 
getStaticField(const char * name,const char * type)145   jfieldID getStaticField(const char* name, const char* type) const {
146     return AndroidBridge::GetStaticFieldID(mEnv, mClass, name, type);
147   }
148 
getMethod(const char * name,const char * type)149   jmethodID getMethod(const char* name, const char* type) const {
150     return AndroidBridge::GetMethodID(mEnv, mClass, name, type);
151   }
152 
getStaticMethod(const char * name,const char * type)153   jmethodID getStaticMethod(const char* name, const char* type) const {
154     return AndroidBridge::GetStaticMethodID(mEnv, mClass, name, type);
155   }
156 };
157 
158 class AutoJObject {
159  public:
mObject(nullptr)160   explicit AutoJObject(JNIEnv* aJNIEnv = nullptr) : mObject(nullptr) {
161     mJNIEnv = aJNIEnv ? aJNIEnv : jni::GetGeckoThreadEnv();
162   }
163 
AutoJObject(JNIEnv * aJNIEnv,jobject aObject)164   AutoJObject(JNIEnv* aJNIEnv, jobject aObject) {
165     mJNIEnv = aJNIEnv ? aJNIEnv : jni::GetGeckoThreadEnv();
166     mObject = aObject;
167   }
168 
~AutoJObject()169   ~AutoJObject() {
170     if (mObject) mJNIEnv->DeleteLocalRef(mObject);
171   }
172 
173   jobject operator=(jobject aObject) {
174     if (mObject) {
175       mJNIEnv->DeleteLocalRef(mObject);
176     }
177     return mObject = aObject;
178   }
179 
jobject()180   operator jobject() { return mObject; }
181 
182  private:
183   JNIEnv* mJNIEnv;
184   jobject mObject;
185 };
186 
187 class AutoLocalJNIFrame {
188  public:
189   explicit AutoLocalJNIFrame(int nEntries = 15)
mEntries(nEntries)190       : mEntries(nEntries),
191         mJNIEnv(jni::GetGeckoThreadEnv()),
192         mHasFrameBeenPushed(false) {
193     MOZ_ASSERT(mJNIEnv);
194     Push();
195   }
196 
197   explicit AutoLocalJNIFrame(JNIEnv* aJNIEnv, int nEntries = 15)
mEntries(nEntries)198       : mEntries(nEntries),
199         mJNIEnv(aJNIEnv ? aJNIEnv : jni::GetGeckoThreadEnv()),
200         mHasFrameBeenPushed(false) {
201     MOZ_ASSERT(mJNIEnv);
202     Push();
203   }
204 
~AutoLocalJNIFrame()205   ~AutoLocalJNIFrame() {
206     if (mHasFrameBeenPushed) {
207       Pop();
208     }
209   }
210 
GetEnv()211   JNIEnv* GetEnv() { return mJNIEnv; }
212 
CheckForException()213   bool CheckForException() {
214     if (mJNIEnv->ExceptionCheck()) {
215       MOZ_CATCH_JNI_EXCEPTION(mJNIEnv);
216       return true;
217     }
218     return false;
219   }
220 
221   // Note! Calling Purge makes all previous local refs created in
222   // the AutoLocalJNIFrame's scope INVALID; be sure that you locked down
223   // any local refs that you need to keep around in global refs!
Purge()224   void Purge() {
225     Pop();
226     Push();
227   }
228 
229   template <typename ReturnType = jobject>
230   ReturnType Pop(ReturnType aResult = nullptr) {
231     MOZ_ASSERT(mHasFrameBeenPushed);
232     mHasFrameBeenPushed = false;
233     return static_cast<ReturnType>(
234         mJNIEnv->PopLocalFrame(static_cast<jobject>(aResult)));
235   }
236 
237  private:
Push()238   void Push() {
239     MOZ_ASSERT(!mHasFrameBeenPushed);
240     // Make sure there is enough space to store a local ref to the
241     // exception.  I am not completely sure this is needed, but does
242     // not hurt.
243     if (mJNIEnv->PushLocalFrame(mEntries + 1) != 0) {
244       CheckForException();
245       return;
246     }
247     mHasFrameBeenPushed = true;
248   }
249 
250   const int mEntries;
251   JNIEnv* const mJNIEnv;
252   bool mHasFrameBeenPushed;
253 };
254 
255 }  // namespace mozilla
256 
257 #define NS_ANDROIDBRIDGE_CID                         \
258   {                                                  \
259     0x0FE2321D, 0xEBD9, 0x467D, {                    \
260       0xA7, 0x43, 0x03, 0xA6, 0x8D, 0x40, 0x59, 0x9E \
261     }                                                \
262   }
263 
264 class nsAndroidBridge final : public nsIAndroidBridge {
265  public:
266   NS_DECL_ISUPPORTS
267   NS_DECL_NSIANDROIDBRIDGE
268 
269   NS_FORWARD_SAFE_NSIANDROIDEVENTDISPATCHER(mEventDispatcher)
270 
271   nsAndroidBridge();
272 
273  private:
274   ~nsAndroidBridge();
275 
276   nsCOMPtr<nsIAndroidEventDispatcher> mEventDispatcher;
277 
278  protected:
279 };
280 
281 #endif /* AndroidBridge_h__ */
282