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