/* * Copyright 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "agq.h" #include #include #include #define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, "AndroidGameQualification", __VA_ARGS__)) static JavaVM* sJavaVm = nullptr; static JNIEnv* sJniEnv = nullptr; // Initialize sJavaVm if the app uses JNI. JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) { sJavaVm = vm; sJavaVm->GetEnv(reinterpret_cast(&sJniEnv), JNI_VERSION_1_6); return sJniEnv->GetVersion(); } namespace android { static const char* const INTENT_START = "com.android.game.qualification.START"; static JNIEnv* getJniEnv() { if (sJniEnv == nullptr) { sJavaVm->AttachCurrentThread(&sJniEnv, nullptr); } return sJniEnv; } // Convert timespec to milliseconds. jlong timespecToMs(timespec spec) { return jlong(spec.tv_sec) * 1000 + spec.tv_nsec / 1000000; } // Create an Intent jobject in Java. static jobject createIntent() { struct timespec spec; clock_gettime(CLOCK_MONOTONIC, &spec); JNIEnv* env = getJniEnv(); jclass intentClass = env->FindClass("android/content/Intent"); jmethodID constructor = env->GetMethodID(intentClass, "", "(Ljava/lang/String;)V"); jobject intent = env->NewObject(intentClass, constructor, env->NewStringUTF(INTENT_START)); jmethodID set_type = env->GetMethodID( intentClass, "setType", "(Ljava/lang/String;)Landroid/content/Intent;"); env->CallObjectMethod(intent, set_type, env->NewStringUTF("text/plain")); jmethodID put_extra = env->GetMethodID( intentClass, "putExtra", "(Ljava/lang/String;J)Landroid/content/Intent;"); jlong timestamp = timespecToMs(spec); env->CallObjectMethod(intent, put_extra, env->NewStringUTF("timestamp"), timestamp); LOGD("Created intent %s at %lld", INTENT_START, (long long)timestamp); return intent; } // Implementation of android::GameQualification::Impl. class GameQualification::Impl { public: void startLoop(jobject context); void startLoop(ANativeActivity* activity); }; void GameQualification::Impl::startLoop(jobject context) { JNIEnv* env = getJniEnv(); jclass contextClass = env->FindClass("android/content/Context"); jmethodID method = env->GetMethodID( contextClass, "sendBroadcast", "(Landroid/content/Intent;)V"); env->CallVoidMethod(context, method, createIntent()); } void GameQualification::Impl::startLoop(ANativeActivity* activity) { sJavaVm = activity->vm; startLoop(activity->clazz); } /* Implementation of GameQualification */ GameQualification::GameQualification() { mImpl = new GameQualification::Impl(); } GameQualification::~GameQualification() { delete mImpl; } void GameQualification::startLoop(jobject context) { mImpl->startLoop(context); } void GameQualification::startLoop(ANativeActivity* activity) { mImpl->startLoop(activity); } } // end of namespace android