android_view_ThreadedRenderer.cpp revision f47a594f5250b1914c36423ee6b371f0b8db09d0
1cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck/*
2cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck * Copyright (C) 2010 The Android Open Source Project
3cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck *
4cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck * Licensed under the Apache License, Version 2.0 (the "License");
5cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck * you may not use this file except in compliance with the License.
6cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck * You may obtain a copy of the License at
7cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck *
8cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck *      http://www.apache.org/licenses/LICENSE-2.0
9cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck *
10cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck * Unless required by applicable law or agreed to in writing, software
11cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck * distributed under the License is distributed on an "AS IS" BASIS,
12cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck * See the License for the specific language governing permissions and
14cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck * limitations under the License.
15cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck */
16cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck
1723b797ab5151eb2474f3bdd679f2f07bfd723042John Reck#define LOG_TAG "ThreadedRenderer"
18cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck
19e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck#include <algorithm>
20e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
21cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck#include "jni.h"
22cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck#include <nativehelper/JNIHelp.h>
23cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck#include <android_runtime/AndroidRuntime.h>
24cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck
2584a4c887a07c1c2939443f4e0587d7f1ac109e4bJohn Reck#include <EGL/egl.h>
2684a4c887a07c1c2939443f4e0587d7f1ac109e4bJohn Reck#include <EGL/eglext.h>
2784a4c887a07c1c2939443f4e0587d7f1ac109e4bJohn Reck#include <EGL/egl_cache.h>
2884a4c887a07c1c2939443f4e0587d7f1ac109e4bJohn Reck
294f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck#include <utils/StrongPointer.h>
304f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck#include <android_runtime/android_view_Surface.h>
314f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck#include <system/window.h>
324f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck
3366f0be65a1046f54ddce0498b242c1fa0776b1eaJohn Reck#include "android_view_GraphicBuffer.h"
3466f0be65a1046f54ddce0498b242c1fa0776b1eaJohn Reck
3552244fff29042926e21fa897ef5ab11148e35299John Reck#include <Animator.h>
36e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck#include <RenderNode.h>
3766f0be65a1046f54ddce0498b242c1fa0776b1eaJohn Reck#include <renderthread/CanvasContext.h>
384f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck#include <renderthread/RenderProxy.h>
39cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck#include <renderthread/RenderTask.h>
40cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck#include <renderthread/RenderThread.h>
41797b95b26bbb7557678af78b9a2a61830158920fChris Craik#include <Vector.h>
42cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck
43cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Recknamespace android {
44cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck
45cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck#ifdef USE_OPENGL_RENDERER
46cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck
474f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reckusing namespace android::uirenderer;
484f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reckusing namespace android::uirenderer::renderthread;
49cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck
50c25e506f7fc08790c0532f927f31310a2ca778b7John Reckstatic JNIEnv* getenv(JavaVM* vm) {
51c25e506f7fc08790c0532f927f31310a2ca778b7John Reck    JNIEnv* env;
52c25e506f7fc08790c0532f927f31310a2ca778b7John Reck    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
53c25e506f7fc08790c0532f927f31310a2ca778b7John Reck        LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", vm);
54c25e506f7fc08790c0532f927f31310a2ca778b7John Reck    }
55c25e506f7fc08790c0532f927f31310a2ca778b7John Reck    return env;
56c25e506f7fc08790c0532f927f31310a2ca778b7John Reck}
57c25e506f7fc08790c0532f927f31310a2ca778b7John Reck
5852244fff29042926e21fa897ef5ab11148e35299John Reckclass OnFinishedEvent {
5952244fff29042926e21fa897ef5ab11148e35299John Reckpublic:
60ff941dcd815021bb20d6504eb486acb1e50592c3John Reck    OnFinishedEvent(BaseRenderNodeAnimator* animator, AnimationListener* listener)
6152244fff29042926e21fa897ef5ab11148e35299John Reck            : animator(animator), listener(listener) {}
62ff941dcd815021bb20d6504eb486acb1e50592c3John Reck    sp<BaseRenderNodeAnimator> animator;
6352244fff29042926e21fa897ef5ab11148e35299John Reck    sp<AnimationListener> listener;
6452244fff29042926e21fa897ef5ab11148e35299John Reck};
6552244fff29042926e21fa897ef5ab11148e35299John Reck
66e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reckclass InvokeAnimationListeners : public MessageHandler {
67e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reckpublic:
6852244fff29042926e21fa897ef5ab11148e35299John Reck    InvokeAnimationListeners(std::vector<OnFinishedEvent>& events) {
6952244fff29042926e21fa897ef5ab11148e35299John Reck        mOnFinishedEvents.swap(events);
70e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    }
71e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
7252244fff29042926e21fa897ef5ab11148e35299John Reck    static void callOnFinished(OnFinishedEvent& event) {
7352244fff29042926e21fa897ef5ab11148e35299John Reck        event.listener->onAnimationFinished(event.animator.get());
74e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    }
75e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
76e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    virtual void handleMessage(const Message& message) {
7752244fff29042926e21fa897ef5ab11148e35299John Reck        std::for_each(mOnFinishedEvents.begin(), mOnFinishedEvents.end(), callOnFinished);
7852244fff29042926e21fa897ef5ab11148e35299John Reck        mOnFinishedEvents.clear();
79e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    }
80e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
81e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reckprivate:
8252244fff29042926e21fa897ef5ab11148e35299John Reck    std::vector<OnFinishedEvent> mOnFinishedEvents;
83e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck};
84e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
85c25e506f7fc08790c0532f927f31310a2ca778b7John Reckclass RenderingException : public MessageHandler {
86e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reckpublic:
87c25e506f7fc08790c0532f927f31310a2ca778b7John Reck    RenderingException(JavaVM* vm, const std::string& message)
88c25e506f7fc08790c0532f927f31310a2ca778b7John Reck            : mVm(vm)
89c25e506f7fc08790c0532f927f31310a2ca778b7John Reck            , mMessage(message) {
90c25e506f7fc08790c0532f927f31310a2ca778b7John Reck    }
91c25e506f7fc08790c0532f927f31310a2ca778b7John Reck
92c25e506f7fc08790c0532f927f31310a2ca778b7John Reck    virtual void handleMessage(const Message&) {
93c25e506f7fc08790c0532f927f31310a2ca778b7John Reck        throwException(mVm, mMessage);
94c25e506f7fc08790c0532f927f31310a2ca778b7John Reck    }
95c25e506f7fc08790c0532f927f31310a2ca778b7John Reck
96c25e506f7fc08790c0532f927f31310a2ca778b7John Reck    static void throwException(JavaVM* vm, const std::string& message) {
97c25e506f7fc08790c0532f927f31310a2ca778b7John Reck        JNIEnv* env = getenv(vm);
98c25e506f7fc08790c0532f927f31310a2ca778b7John Reck        jniThrowException(env, "java/lang/IllegalStateException", message.c_str());
99c25e506f7fc08790c0532f927f31310a2ca778b7John Reck    }
100c25e506f7fc08790c0532f927f31310a2ca778b7John Reck
101c25e506f7fc08790c0532f927f31310a2ca778b7John Reckprivate:
102c25e506f7fc08790c0532f927f31310a2ca778b7John Reck    JavaVM* mVm;
103c25e506f7fc08790c0532f927f31310a2ca778b7John Reck    std::string mMessage;
104c25e506f7fc08790c0532f927f31310a2ca778b7John Reck};
105c25e506f7fc08790c0532f927f31310a2ca778b7John Reck
106c25e506f7fc08790c0532f927f31310a2ca778b7John Reckclass RootRenderNode : public RenderNode, AnimationHook, ErrorHandler {
107c25e506f7fc08790c0532f927f31310a2ca778b7John Reckpublic:
108c25e506f7fc08790c0532f927f31310a2ca778b7John Reck    RootRenderNode(JNIEnv* env) : RenderNode() {
109e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck        mLooper = Looper::getForThread();
110e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck        LOG_ALWAYS_FATAL_IF(!mLooper.get(),
111e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck                "Must create RootRenderNode on a thread with a looper!");
112c25e506f7fc08790c0532f927f31310a2ca778b7John Reck        env->GetJavaVM(&mVm);
113e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    }
114e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
115e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    virtual ~RootRenderNode() {}
116e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
117ff941dcd815021bb20d6504eb486acb1e50592c3John Reck    virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) {
11852244fff29042926e21fa897ef5ab11148e35299John Reck        OnFinishedEvent event(animator, listener);
11952244fff29042926e21fa897ef5ab11148e35299John Reck        mOnFinishedEvents.push_back(event);
120e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    }
121e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
122c25e506f7fc08790c0532f927f31310a2ca778b7John Reck    virtual void onError(const std::string& message) {
123c25e506f7fc08790c0532f927f31310a2ca778b7John Reck        mLooper->sendMessage(new RenderingException(mVm, message), 0);
124c25e506f7fc08790c0532f927f31310a2ca778b7John Reck    }
125c25e506f7fc08790c0532f927f31310a2ca778b7John Reck
126e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    virtual void prepareTree(TreeInfo& info) {
12752244fff29042926e21fa897ef5ab11148e35299John Reck        info.animationHook = this;
128c25e506f7fc08790c0532f927f31310a2ca778b7John Reck        info.errorHandler = this;
129e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck        RenderNode::prepareTree(info);
13052244fff29042926e21fa897ef5ab11148e35299John Reck        info.animationHook = NULL;
131c25e506f7fc08790c0532f927f31310a2ca778b7John Reck        info.errorHandler = NULL;
132e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
133e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck        // post all the finished stuff
13452244fff29042926e21fa897ef5ab11148e35299John Reck        if (mOnFinishedEvents.size()) {
135e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck            sp<InvokeAnimationListeners> message
13652244fff29042926e21fa897ef5ab11148e35299John Reck                    = new InvokeAnimationListeners(mOnFinishedEvents);
137e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck            mLooper->sendMessage(message, 0);
138e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck        }
139e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    }
140e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
141e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reckprotected:
142e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    virtual void damageSelf(TreeInfo& info) {
143e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        // Intentionally a no-op. As RootRenderNode gets a new DisplayListData
144e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        // every frame this would result in every draw push being a full inval,
145e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        // which is wrong. Only RootRenderNode has this issue.
146e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    }
147e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck
148e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reckprivate:
149e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    sp<Looper> mLooper;
15052244fff29042926e21fa897ef5ab11148e35299John Reck    std::vector<OnFinishedEvent> mOnFinishedEvents;
151c25e506f7fc08790c0532f927f31310a2ca778b7John Reck    JavaVM* mVm;
152e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck};
153e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
15466f0be65a1046f54ddce0498b242c1fa0776b1eaJohn Reckstatic void android_view_ThreadedRenderer_setAtlas(JNIEnv* env, jobject clazz,
1553b20251a355c88193c439f928a84ae69483fb488John Reck        jlong proxyPtr, jobject graphicBuffer, jlongArray atlasMapArray) {
15666f0be65a1046f54ddce0498b242c1fa0776b1eaJohn Reck    sp<GraphicBuffer> buffer = graphicBufferForJavaObject(env, graphicBuffer);
15766f0be65a1046f54ddce0498b242c1fa0776b1eaJohn Reck    jsize len = env->GetArrayLength(atlasMapArray);
15866f0be65a1046f54ddce0498b242c1fa0776b1eaJohn Reck    if (len <= 0) {
15966f0be65a1046f54ddce0498b242c1fa0776b1eaJohn Reck        ALOGW("Failed to initialize atlas, invalid map length: %d", len);
16066f0be65a1046f54ddce0498b242c1fa0776b1eaJohn Reck        return;
16166f0be65a1046f54ddce0498b242c1fa0776b1eaJohn Reck    }
16266f0be65a1046f54ddce0498b242c1fa0776b1eaJohn Reck    int64_t* map = new int64_t[len];
16366f0be65a1046f54ddce0498b242c1fa0776b1eaJohn Reck    env->GetLongArrayRegion(atlasMapArray, 0, len, map);
16466f0be65a1046f54ddce0498b242c1fa0776b1eaJohn Reck
1653b20251a355c88193c439f928a84ae69483fb488John Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
1663b20251a355c88193c439f928a84ae69483fb488John Reck    proxy->setTextureAtlas(buffer, map, len);
1674f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck}
1684f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck
169e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reckstatic jlong android_view_ThreadedRenderer_createRootRenderNode(JNIEnv* env, jobject clazz) {
170c25e506f7fc08790c0532f927f31310a2ca778b7John Reck    RootRenderNode* node = new RootRenderNode(env);
171e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    node->incStrong(0);
172e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    node->setName("RootRenderNode");
173e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    return reinterpret_cast<jlong>(node);
174e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck}
175e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck
1764f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reckstatic jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject clazz,
177e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck        jboolean translucent, jlong rootRenderNodePtr) {
178e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    RenderNode* rootRenderNode = reinterpret_cast<RenderNode*>(rootRenderNodePtr);
179e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    return (jlong) new RenderProxy(translucent, rootRenderNode);
1804f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck}
1814f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck
1824f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reckstatic void android_view_ThreadedRenderer_deleteProxy(JNIEnv* env, jobject clazz,
1834f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck        jlong proxyPtr) {
18419b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
1854f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck    delete proxy;
1864f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck}
1874f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck
18818f16e6fba74eda173e1e7c869e6e2e2acc073ffJohn Reckstatic void android_view_ThreadedRenderer_setFrameInterval(JNIEnv* env, jobject clazz,
18918f16e6fba74eda173e1e7c869e6e2e2acc073ffJohn Reck        jlong proxyPtr, jlong frameIntervalNanos) {
19018f16e6fba74eda173e1e7c869e6e2e2acc073ffJohn Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
19118f16e6fba74eda173e1e7c869e6e2e2acc073ffJohn Reck    proxy->setFrameInterval(frameIntervalNanos);
19218f16e6fba74eda173e1e7c869e6e2e2acc073ffJohn Reck}
19318f16e6fba74eda173e1e7c869e6e2e2acc073ffJohn Reck
194e4280baaa709c74d86cf6a389a4674ca665f5af6John Reckstatic jboolean android_view_ThreadedRenderer_loadSystemProperties(JNIEnv* env, jobject clazz,
195e4280baaa709c74d86cf6a389a4674ca665f5af6John Reck        jlong proxyPtr) {
196e4280baaa709c74d86cf6a389a4674ca665f5af6John Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
197e4280baaa709c74d86cf6a389a4674ca665f5af6John Reck    return proxy->loadSystemProperties();
198e4280baaa709c74d86cf6a389a4674ca665f5af6John Reck}
199e4280baaa709c74d86cf6a389a4674ca665f5af6John Reck
2004f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reckstatic jboolean android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
2014f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck        jlong proxyPtr, jobject jsurface) {
20219b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
2034f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck    sp<ANativeWindow> window = android_view_Surface_getNativeWindow(env, jsurface);
204f7d9c1dc84671d4e99657ef071d275700d85bb11John Reck    return proxy->initialize(window);
2054f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck}
2064f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck
2074f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reckstatic void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz,
2084f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck        jlong proxyPtr, jobject jsurface) {
20919b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
2104f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck    sp<ANativeWindow> window;
2114f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck    if (jsurface) {
2124f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck        window = android_view_Surface_getNativeWindow(env, jsurface);
2134f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck    }
214f7d9c1dc84671d4e99657ef071d275700d85bb11John Reck    proxy->updateSurface(window);
215f7d9c1dc84671d4e99657ef071d275700d85bb11John Reck}
216f7d9c1dc84671d4e99657ef071d275700d85bb11John Reck
217f7d9c1dc84671d4e99657ef071d275700d85bb11John Reckstatic void android_view_ThreadedRenderer_pauseSurface(JNIEnv* env, jobject clazz,
218f7d9c1dc84671d4e99657ef071d275700d85bb11John Reck        jlong proxyPtr, jobject jsurface) {
219f7d9c1dc84671d4e99657ef071d275700d85bb11John Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
220f7d9c1dc84671d4e99657ef071d275700d85bb11John Reck    sp<ANativeWindow> window;
221f7d9c1dc84671d4e99657ef071d275700d85bb11John Reck    if (jsurface) {
222f7d9c1dc84671d4e99657ef071d275700d85bb11John Reck        window = android_view_Surface_getNativeWindow(env, jsurface);
223f7d9c1dc84671d4e99657ef071d275700d85bb11John Reck    }
224f7d9c1dc84671d4e99657ef071d275700d85bb11John Reck    proxy->pauseSurface(window);
2254f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck}
2264f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck
227797b95b26bbb7557678af78b9a2a61830158920fChris Craikstatic void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr,
228797b95b26bbb7557678af78b9a2a61830158920fChris Craik        jint width, jint height,
229797b95b26bbb7557678af78b9a2a61830158920fChris Craik        jfloat lightX, jfloat lightY, jfloat lightZ, jfloat lightRadius) {
23019b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
231797b95b26bbb7557678af78b9a2a61830158920fChris Craik    proxy->setup(width, height, Vector3(lightX, lightY, lightZ), lightRadius);
2324f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck}
2334f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck
23463a06673253914510bbeebd500655008682dade1John Reckstatic void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
23563a06673253914510bbeebd500655008682dade1John Reck        jlong proxyPtr, jboolean opaque) {
23663a06673253914510bbeebd500655008682dade1John Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
23763a06673253914510bbeebd500655008682dade1John Reck    proxy->setOpaque(opaque);
23863a06673253914510bbeebd500655008682dade1John Reck}
23963a06673253914510bbeebd500655008682dade1John Reck
240f9be77940e365036fecd8cc0e491e8545c34e79bJohn Reckstatic int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
241e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck        jlong proxyPtr, jlong frameTimeNanos, jlong recordDuration, jfloat density) {
24219b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
243e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    return proxy->syncAndDrawFrame(frameTimeNanos, recordDuration, density);
2444f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck}
2454f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck
246fae904d63947fe1687d1d44be29234cc3d538f24John Reckstatic void android_view_ThreadedRenderer_destroyCanvasAndSurface(JNIEnv* env, jobject clazz,
2474f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck        jlong proxyPtr) {
24819b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
249fae904d63947fe1687d1d44be29234cc3d538f24John Reck    proxy->destroyCanvasAndSurface();
2504f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck}
2514f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck
2520d1f634f4b5e1bb37aa51777efb6a68619488d01John Reckstatic void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
2533b20251a355c88193c439f928a84ae69483fb488John Reck        jlong functorPtr, jboolean waitForCompletion) {
2540d1f634f4b5e1bb37aa51777efb6a68619488d01John Reck    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
2553b20251a355c88193c439f928a84ae69483fb488John Reck    RenderProxy::invokeFunctor(functor, waitForCompletion);
2560d1f634f4b5e1bb37aa51777efb6a68619488d01John Reck}
2570d1f634f4b5e1bb37aa51777efb6a68619488d01John Reck
25819b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reckstatic jlong android_view_ThreadedRenderer_createDisplayListLayer(JNIEnv* env, jobject clazz,
25919b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck        jlong proxyPtr, jint width, jint height) {
26019b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
26119b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    DeferredLayerUpdater* layer = proxy->createDisplayListLayer(width, height);
26219b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    return reinterpret_cast<jlong>(layer);
26319b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck}
26419b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck
26519b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reckstatic jlong android_view_ThreadedRenderer_createTextureLayer(JNIEnv* env, jobject clazz,
26619b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck        jlong proxyPtr) {
26719b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
26819b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    DeferredLayerUpdater* layer = proxy->createTextureLayer();
26919b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    return reinterpret_cast<jlong>(layer);
27019b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck}
27119b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck
27219b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reckstatic jboolean android_view_ThreadedRenderer_copyLayerInto(JNIEnv* env, jobject clazz,
27319b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck        jlong proxyPtr, jlong layerPtr, jlong bitmapPtr) {
27419b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
27519b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
27619b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
27719b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    return proxy->copyLayerInto(layer, bitmap);
27819b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck}
27919b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck
280d72e0a339b54af0c4e731513bbad120dff694723John Reckstatic void android_view_ThreadedRenderer_pushLayerUpdate(JNIEnv* env, jobject clazz,
28119b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck        jlong proxyPtr, jlong layerPtr) {
28219b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
28319b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
284d72e0a339b54af0c4e731513bbad120dff694723John Reck    proxy->pushLayerUpdate(layer);
285d72e0a339b54af0c4e731513bbad120dff694723John Reck}
286d72e0a339b54af0c4e731513bbad120dff694723John Reck
287d72e0a339b54af0c4e731513bbad120dff694723John Reckstatic void android_view_ThreadedRenderer_cancelLayerUpdate(JNIEnv* env, jobject clazz,
288d72e0a339b54af0c4e731513bbad120dff694723John Reck        jlong proxyPtr, jlong layerPtr) {
289d72e0a339b54af0c4e731513bbad120dff694723John Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
290d72e0a339b54af0c4e731513bbad120dff694723John Reck    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
291d72e0a339b54af0c4e731513bbad120dff694723John Reck    proxy->cancelLayerUpdate(layer);
29219b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck}
29319b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck
294918ad523b2780e0c893f3d2a32d4ec13f2a7e921John Reckstatic void android_view_ThreadedRenderer_detachSurfaceTexture(JNIEnv* env, jobject clazz,
295918ad523b2780e0c893f3d2a32d4ec13f2a7e921John Reck        jlong proxyPtr, jlong layerPtr) {
296918ad523b2780e0c893f3d2a32d4ec13f2a7e921John Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
297918ad523b2780e0c893f3d2a32d4ec13f2a7e921John Reck    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
298918ad523b2780e0c893f3d2a32d4ec13f2a7e921John Reck    proxy->detachSurfaceTexture(layer);
299918ad523b2780e0c893f3d2a32d4ec13f2a7e921John Reck}
300918ad523b2780e0c893f3d2a32d4ec13f2a7e921John Reck
301f47a594f5250b1914c36423ee6b371f0b8db09d0John Reckstatic void android_view_ThreadedRenderer_destroyHardwareResources(JNIEnv* env, jobject clazz,
302f47a594f5250b1914c36423ee6b371f0b8db09d0John Reck        jlong proxyPtr) {
303e1628b7c6fc3822fa83cf02028ce8ad67abb0afeJohn Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
304f47a594f5250b1914c36423ee6b371f0b8db09d0John Reck    proxy->destroyHardwareResources();
305f47a594f5250b1914c36423ee6b371f0b8db09d0John Reck}
306f47a594f5250b1914c36423ee6b371f0b8db09d0John Reck
307f47a594f5250b1914c36423ee6b371f0b8db09d0John Reckstatic void android_view_ThreadedRenderer_trimMemory(JNIEnv* env, jobject clazz,
308f47a594f5250b1914c36423ee6b371f0b8db09d0John Reck        jint level) {
309f47a594f5250b1914c36423ee6b371f0b8db09d0John Reck    RenderProxy::trimMemory(level);
310e1628b7c6fc3822fa83cf02028ce8ad67abb0afeJohn Reck}
311e1628b7c6fc3822fa83cf02028ce8ad67abb0afeJohn Reck
31228ad7b52e038ef0cdd89f753d9839444a434b299John Reckstatic void android_view_ThreadedRenderer_fence(JNIEnv* env, jobject clazz,
31328ad7b52e038ef0cdd89f753d9839444a434b299John Reck        jlong proxyPtr) {
31428ad7b52e038ef0cdd89f753d9839444a434b299John Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
31528ad7b52e038ef0cdd89f753d9839444a434b299John Reck    proxy->fence();
31628ad7b52e038ef0cdd89f753d9839444a434b299John Reck}
31728ad7b52e038ef0cdd89f753d9839444a434b299John Reck
318f47a594f5250b1914c36423ee6b371f0b8db09d0John Reckstatic void android_view_ThreadedRenderer_stopDrawing(JNIEnv* env, jobject clazz,
319f47a594f5250b1914c36423ee6b371f0b8db09d0John Reck        jlong proxyPtr) {
320f47a594f5250b1914c36423ee6b371f0b8db09d0John Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
321f47a594f5250b1914c36423ee6b371f0b8db09d0John Reck    proxy->stopDrawing();
322f47a594f5250b1914c36423ee6b371f0b8db09d0John Reck}
323f47a594f5250b1914c36423ee6b371f0b8db09d0John Reck
324a5dda645da738da7b4ae15e28fa7d93d3b04b94fJohn Reckstatic void android_view_ThreadedRenderer_notifyFramePending(JNIEnv* env, jobject clazz,
325a5dda645da738da7b4ae15e28fa7d93d3b04b94fJohn Reck        jlong proxyPtr) {
326a5dda645da738da7b4ae15e28fa7d93d3b04b94fJohn Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
327a5dda645da738da7b4ae15e28fa7d93d3b04b94fJohn Reck    proxy->notifyFramePending();
328a5dda645da738da7b4ae15e28fa7d93d3b04b94fJohn Reck}
329a5dda645da738da7b4ae15e28fa7d93d3b04b94fJohn Reck
330fe5e7b7346a54537b980796ceeca66bfdbd05561John Reckstatic void android_view_ThreadedRenderer_dumpProfileInfo(JNIEnv* env, jobject clazz,
331fe5e7b7346a54537b980796ceeca66bfdbd05561John Reck        jlong proxyPtr, jobject javaFileDescriptor) {
332fe5e7b7346a54537b980796ceeca66bfdbd05561John Reck    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
333fe5e7b7346a54537b980796ceeca66bfdbd05561John Reck    int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
334fe5e7b7346a54537b980796ceeca66bfdbd05561John Reck    proxy->dumpProfileInfo(fd);
335fe5e7b7346a54537b980796ceeca66bfdbd05561John Reck}
336fe5e7b7346a54537b980796ceeca66bfdbd05561John Reck
337cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck#endif
338cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck
339cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck// ----------------------------------------------------------------------------
34084a4c887a07c1c2939443f4e0587d7f1ac109e4bJohn Reck// Shaders
34184a4c887a07c1c2939443f4e0587d7f1ac109e4bJohn Reck// ----------------------------------------------------------------------------
34284a4c887a07c1c2939443f4e0587d7f1ac109e4bJohn Reck
34384a4c887a07c1c2939443f4e0587d7f1ac109e4bJohn Reckstatic void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
34484a4c887a07c1c2939443f4e0587d7f1ac109e4bJohn Reck        jstring diskCachePath) {
34584a4c887a07c1c2939443f4e0587d7f1ac109e4bJohn Reck
34684a4c887a07c1c2939443f4e0587d7f1ac109e4bJohn Reck    const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL);
34784a4c887a07c1c2939443f4e0587d7f1ac109e4bJohn Reck    egl_cache_t::get()->setCacheFilename(cacheArray);
34884a4c887a07c1c2939443f4e0587d7f1ac109e4bJohn Reck    env->ReleaseStringUTFChars(diskCachePath, cacheArray);
34984a4c887a07c1c2939443f4e0587d7f1ac109e4bJohn Reck}
35084a4c887a07c1c2939443f4e0587d7f1ac109e4bJohn Reck
35184a4c887a07c1c2939443f4e0587d7f1ac109e4bJohn Reck// ----------------------------------------------------------------------------
352cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck// JNI Glue
353cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck// ----------------------------------------------------------------------------
354cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck
355cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reckconst char* const kClassPathName = "android/view/ThreadedRenderer";
356cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck
357cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reckstatic JNINativeMethod gMethods[] = {
358cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck#ifdef USE_OPENGL_RENDERER
3593b20251a355c88193c439f928a84ae69483fb488John Reck    { "nSetAtlas", "(JLandroid/view/GraphicBuffer;[J)V",   (void*) android_view_ThreadedRenderer_setAtlas },
360e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
361e45b1fd03b524d2b57cc6c222d89076a31a08beaJohn Reck    { "nCreateProxy", "(ZJ)J", (void*) android_view_ThreadedRenderer_createProxy },
3624f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck    { "nDeleteProxy", "(J)V", (void*) android_view_ThreadedRenderer_deleteProxy },
36318f16e6fba74eda173e1e7c869e6e2e2acc073ffJohn Reck    { "nSetFrameInterval", "(JJ)V", (void*) android_view_ThreadedRenderer_setFrameInterval },
364e4280baaa709c74d86cf6a389a4674ca665f5af6John Reck    { "nLoadSystemProperties", "(J)Z", (void*) android_view_ThreadedRenderer_loadSystemProperties },
3654f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck    { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize },
3664f02bf4eef6af47f35c70c4dda5b7b9523d89ca0John Reck    { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
367f7d9c1dc84671d4e99657ef071d275700d85bb11John Reck    { "nPauseSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_pauseSurface },
368797b95b26bbb7557678af78b9a2a61830158920fChris Craik    { "nSetup", "(JIIFFFF)V", (void*) android_view_ThreadedRenderer_setup },
36963a06673253914510bbeebd500655008682dade1John Reck    { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
370e4267ea4f20740c37c01bfb6aefcf61fddc4566aJohn Reck    { "nSyncAndDrawFrame", "(JJJF)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
371fae904d63947fe1687d1d44be29234cc3d538f24John Reck    { "nDestroyCanvasAndSurface", "(J)V", (void*) android_view_ThreadedRenderer_destroyCanvasAndSurface },
3723b20251a355c88193c439f928a84ae69483fb488John Reck    { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
37319b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    { "nCreateDisplayListLayer", "(JII)J", (void*) android_view_ThreadedRenderer_createDisplayListLayer },
37419b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
37519b6bcfd83eb7fb92ebd06d2fec89e308311f1d0John Reck    { "nCopyLayerInto", "(JJJ)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
376d72e0a339b54af0c4e731513bbad120dff694723John Reck    { "nPushLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_pushLayerUpdate },
377d72e0a339b54af0c4e731513bbad120dff694723John Reck    { "nCancelLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_cancelLayerUpdate },
378918ad523b2780e0c893f3d2a32d4ec13f2a7e921John Reck    { "nDetachSurfaceTexture", "(JJ)V", (void*) android_view_ThreadedRenderer_detachSurfaceTexture },
379f47a594f5250b1914c36423ee6b371f0b8db09d0John Reck    { "nDestroyHardwareResources", "(J)V", (void*) android_view_ThreadedRenderer_destroyHardwareResources },
380f47a594f5250b1914c36423ee6b371f0b8db09d0John Reck    { "nTrimMemory", "(I)V", (void*) android_view_ThreadedRenderer_trimMemory },
38128ad7b52e038ef0cdd89f753d9839444a434b299John Reck    { "nFence", "(J)V", (void*) android_view_ThreadedRenderer_fence },
382f47a594f5250b1914c36423ee6b371f0b8db09d0John Reck    { "nStopDrawing", "(J)V", (void*) android_view_ThreadedRenderer_stopDrawing },
383a5dda645da738da7b4ae15e28fa7d93d3b04b94fJohn Reck    { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending },
384fe5e7b7346a54537b980796ceeca66bfdbd05561John Reck    { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
385cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck#endif
38684a4c887a07c1c2939443f4e0587d7f1ac109e4bJohn Reck    { "setupShadersDiskCache", "(Ljava/lang/String;)V",
38784a4c887a07c1c2939443f4e0587d7f1ac109e4bJohn Reck                (void*) android_view_ThreadedRenderer_setupShadersDiskCache },
388cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck};
389cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck
390cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reckint register_android_view_ThreadedRenderer(JNIEnv* env) {
391cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
392cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck}
393cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck
394cec24ae16e9a0a7c3075f1a8d9149bb7fb3813fcJohn Reck}; // namespace android
395