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