1b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet/*
2b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet * Copyright (C) 2010 The Android Open Source Project
3b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet *
4b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet * Licensed under the Apache License, Version 2.0 (the "License");
5b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet * you may not use this file except in compliance with the License.
6b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet * You may obtain a copy of the License at
7b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet *
8b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet *      http://www.apache.org/licenses/LICENSE-2.0
9b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet *
10b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet * Unless required by applicable law or agreed to in writing, software
11b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS,
12b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet * See the License for the specific language governing permissions and
14b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet * limitations under the License.
15b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet */
16b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
17b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohetpackage com.android.layoutlib.bridge.impl;
18b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
19b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_LOCK_INTERRUPTED;
20b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.ERROR_TIMEOUT;
21b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohetimport static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
22b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
23891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohetimport com.android.ide.common.rendering.api.HardwareConfig;
24b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohetimport com.android.ide.common.rendering.api.LayoutLog;
25b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohetimport com.android.ide.common.rendering.api.RenderParams;
26b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohetimport com.android.ide.common.rendering.api.RenderResources;
27b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohetimport com.android.ide.common.rendering.api.RenderResources.FrameworkResourceIdProvider;
28891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohetimport com.android.ide.common.rendering.api.Result;
29b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohetimport com.android.layoutlib.bridge.Bridge;
30b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohetimport com.android.layoutlib.bridge.android.BridgeContext;
310a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohetimport com.android.resources.Density;
32b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohetimport com.android.resources.ResourceType;
330a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohetimport com.android.resources.ScreenSize;
34b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
350a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohetimport android.content.res.Configuration;
36fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohetimport android.os.HandlerThread_Delegate;
3796131eef3869f2be1300e1620f5c3874b41bb534Xavier Ducrohetimport android.os.Looper;
38b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohetimport android.util.DisplayMetrics;
397f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohetimport android.view.ViewConfiguration_Accessor;
4096131eef3869f2be1300e1620f5c3874b41bb534Xavier Ducrohetimport android.view.inputmethod.InputMethodManager;
417f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohetimport android.view.inputmethod.InputMethodManager_Accessor;
42b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
43b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohetimport java.util.concurrent.TimeUnit;
44b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohetimport java.util.concurrent.locks.ReentrantLock;
45b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
46b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet/**
47fd18f573280bbbcc549b35b548580a562bd960e2Xavier Ducrohet * Base class for rendering action.
48fd18f573280bbbcc549b35b548580a562bd960e2Xavier Ducrohet *
49fd18f573280bbbcc549b35b548580a562bd960e2Xavier Ducrohet * It provides life-cycle methods to init and stop the rendering.
50fd18f573280bbbcc549b35b548580a562bd960e2Xavier Ducrohet * The most important methods are:
51fd18f573280bbbcc549b35b548580a562bd960e2Xavier Ducrohet * {@link #init(long)} and {@link #acquire(long)} to start a rendering and {@link #release()}
52fd18f573280bbbcc549b35b548580a562bd960e2Xavier Ducrohet * after the rendering.
53b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet *
54b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet *
55b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet * @param <T> the {@link RenderParams} implementation
56b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet *
57b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet */
58fd18f573280bbbcc549b35b548580a562bd960e2Xavier Ducrohetpublic abstract class RenderAction<T extends RenderParams> extends FrameworkResourceIdProvider {
59b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
60b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    /**
61b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * The current context being rendered. This is set through {@link #acquire(long)} and
62b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * {@link #init(long)}, and unset in {@link #release()}.
63b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     */
64b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    private static BridgeContext sCurrentContext = null;
65b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
66b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    private final T mParams;
67b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
68b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    private BridgeContext mContext;
69b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
70b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    /**
71b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * Creates a renderAction.
72b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * <p>
73b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * This <b>must</b> be followed by a call to {@link RenderAction#init()}, which act as a
74b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * call to {@link RenderAction#acquire(long)}
75b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     *
76b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * @param params the RenderParams. This must be a copy that the action can keep
77b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     *
78b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     */
79fd18f573280bbbcc549b35b548580a562bd960e2Xavier Ducrohet    protected RenderAction(T params) {
80b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        mParams = params;
81b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    }
82b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
83b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    /**
84b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * Initializes and acquires the scene, creating various Android objects such as context,
85b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * inflater, and parser.
86b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     *
87b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
88b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     *
89b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * @return whether the scene was prepared
90b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     *
91b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * @see #acquire(long)
92b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * @see #release()
93b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     */
94b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    public Result init(long timeout) {
95b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        // acquire the lock. if the result is null, lock was just acquired, otherwise, return
96b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        // the result.
97b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        Result result = acquireLock(timeout);
98b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        if (result != null) {
99b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            return result;
100b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        }
101b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
102891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet        HardwareConfig hardwareConfig = mParams.getHardwareConfig();
103891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet
104b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        // setup the display Metrics.
105b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        DisplayMetrics metrics = new DisplayMetrics();
106891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet        metrics.densityDpi = metrics.noncompatDensityDpi =
107891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet                hardwareConfig.getDensity().getDpiValue();
1080a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet
1090a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet        metrics.density = metrics.noncompatDensity =
1100a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet                metrics.densityDpi / (float) DisplayMetrics.DENSITY_DEFAULT;
1110a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet
1120a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet        metrics.scaledDensity = metrics.noncompatScaledDensity = metrics.density;
1130a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet
114891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet        metrics.widthPixels = metrics.noncompatWidthPixels = hardwareConfig.getScreenWidth();
115891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet        metrics.heightPixels = metrics.noncompatHeightPixels = hardwareConfig.getScreenHeight();
116891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet        metrics.xdpi = metrics.noncompatXdpi = hardwareConfig.getXdpi();
117891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet        metrics.ydpi = metrics.noncompatYdpi = hardwareConfig.getYdpi();
118b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
119b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        RenderResources resources = mParams.getResources();
120b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
121b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        // build the context
122b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
1230a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet                mParams.getProjectCallback(), getConfiguration(), mParams.getTargetSdkVersion());
124b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
125b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        setUp();
126b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
127b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        return SUCCESS.createResult();
128b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    }
129b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
1300a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet
131b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    /**
132b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * Prepares the scene for action.
133b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * <p>
134b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * This call is blocking if another rendering/inflating is currently happening, and will return
135b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * whether the preparation worked.
136b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     *
137b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * The preparation can fail if another rendering took too long and the timeout was elapsed.
138b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     *
139b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * More than one call to this from the same thread will have no effect and will return
140b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * {@link Result#SUCCESS}.
141b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     *
142b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * After scene actions have taken place, only one call to {@link #release()} must be
143b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * done.
144b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     *
145b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
146b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     *
147b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * @return whether the scene was prepared
148b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     *
149b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * @see #release()
150b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     *
151b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * @throws IllegalStateException if {@link #init(long)} was never called.
152b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     */
153b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    public Result acquire(long timeout) {
154b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        if (mContext == null) {
155b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            throw new IllegalStateException("After scene creation, #init() must be called");
156b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        }
157b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
158b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        // acquire the lock. if the result is null, lock was just acquired, otherwise, return
159b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        // the result.
160b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        Result result = acquireLock(timeout);
161b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        if (result != null) {
162b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            return result;
163b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        }
164b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
165b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        setUp();
166b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
167b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        return SUCCESS.createResult();
168b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    }
169b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
170b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    /**
171b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * Acquire the lock so that the scene can be acted upon.
172b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * <p>
173b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * This returns null if the lock was just acquired, otherwise it returns
174b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * {@link Result#SUCCESS} if the lock already belonged to that thread, or another
175b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * instance (see {@link Result#getStatus()}) if an error occurred.
176b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     *
177b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * @param timeout the time to wait if another rendering is happening.
178b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * @return null if the lock was just acquire or another result depending on the state.
179b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     *
180b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
181b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     *      the scene.
182b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     */
183b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    private Result acquireLock(long timeout) {
184b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        ReentrantLock lock = Bridge.getLock();
185b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        if (lock.isHeldByCurrentThread() == false) {
186b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            try {
187b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
188b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
189b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                if (acquired == false) {
190b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                    return ERROR_TIMEOUT.createResult();
191b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                }
192b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            } catch (InterruptedException e) {
193b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                return ERROR_LOCK_INTERRUPTED.createResult();
194b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            }
195b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        } else {
196b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            // This thread holds the lock already. Checks that this wasn't for a different context.
197b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            // If this is called by init, mContext will be null and so should sCurrentContext
198b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            // anyway
199b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            if (mContext != sCurrentContext) {
200b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet                throw new IllegalStateException("Acquiring different scenes from same thread without releases");
201b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            }
202b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            return SUCCESS.createResult();
203b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        }
204b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
205b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        return null;
206b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    }
207b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
208b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    /**
209b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * Cleans up the scene after an action.
210b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     */
211b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    public void release() {
212b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        ReentrantLock lock = Bridge.getLock();
213b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
214b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        // with the use of finally blocks, it is possible to find ourself calling this
215b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        // without a successful call to prepareScene. This test makes sure that unlock() will
216b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        // not throw IllegalMonitorStateException.
217b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        if (lock.isHeldByCurrentThread()) {
218b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            tearDown();
219b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            lock.unlock();
220b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        }
221b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    }
222b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
223b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    /**
224b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * Sets up the session for rendering.
225b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * <p/>
226b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * The counterpart is {@link #tearDown()}.
227b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     */
228b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    private void setUp() {
229b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        // make sure the Resources object references the context (and other objects) for this
230b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        // scene
231b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        mContext.initResources();
232b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        sCurrentContext = mContext;
233b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
23496131eef3869f2be1300e1620f5c3874b41bb534Xavier Ducrohet        // create an InputMethodManager
23596131eef3869f2be1300e1620f5c3874b41bb534Xavier Ducrohet        InputMethodManager.getInstance(Looper.myLooper());
23696131eef3869f2be1300e1620f5c3874b41bb534Xavier Ducrohet
237b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        LayoutLog currentLog = mParams.getLog();
238b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        Bridge.setLog(currentLog);
239b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        mContext.getRenderResources().setFrameworkResourceIdProvider(this);
240b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        mContext.getRenderResources().setLogger(currentLog);
241b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    }
242b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
243b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    /**
244b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * Tear down the session after rendering.
245b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * <p/>
246b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * The counterpart is {@link #setUp()}.
247b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     */
248b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    private void tearDown() {
249b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        // Make sure to remove static references, otherwise we could not unload the lib
250b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        mContext.disposeResources();
251fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
252fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet        // quit HandlerThread created during this session.
253fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet        HandlerThread_Delegate.cleanUp(sCurrentContext);
254fb93ce9684120a36862b5b5e67b1865a652907e9Xavier Ducrohet
2550a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet        // clear the stored ViewConfiguration since the map is per density and not per context.
2567f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohet        ViewConfiguration_Accessor.clearConfigurations();
2570a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet
25896131eef3869f2be1300e1620f5c3874b41bb534Xavier Ducrohet        // remove the InputMethodManager
2597f9f99ea11051614a7727dfb9f9578b518e76e3cXavier Ducrohet        InputMethodManager_Accessor.resetInstance();
26096131eef3869f2be1300e1620f5c3874b41bb534Xavier Ducrohet
261b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        sCurrentContext = null;
262b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
263b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        Bridge.setLog(null);
264b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        mContext.getRenderResources().setFrameworkResourceIdProvider(null);
265b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        mContext.getRenderResources().setLogger(null);
266b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    }
267b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
268b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    public static BridgeContext getCurrentContext() {
269b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        return sCurrentContext;
270b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    }
271b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
272b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    protected T getParams() {
273b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        return mParams;
274b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    }
275b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
276b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    protected BridgeContext getContext() {
277b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        return mContext;
278b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    }
279b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
280b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    /**
281b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * Returns the log associated with the session.
282b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * @return the log or null if there are none.
283b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     */
284b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    public LayoutLog getLog() {
285b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        if (mParams != null) {
286b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            return mParams.getLog();
287b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        }
288b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
289b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        return null;
290b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    }
291b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
292b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    /**
293b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * Checks that the lock is owned by the current thread and that the current context is the one
294b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * from this scene.
295b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     *
296b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     * @throws IllegalStateException if the current context is different than the one owned by
297b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     *      the scene, or if {@link #acquire(long)} was not called.
298b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet     */
299b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    protected void checkLock() {
300b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        ReentrantLock lock = Bridge.getLock();
301b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        if (lock.isHeldByCurrentThread() == false) {
302b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            throw new IllegalStateException("scene must be acquired first. see #acquire(long)");
303b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        }
304b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        if (sCurrentContext != mContext) {
305b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet            throw new IllegalStateException("Thread acquired a scene but is rendering a different one");
306b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        }
307b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    }
308b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
3090a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet    private Configuration getConfiguration() {
3100a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet        Configuration config = new Configuration();
3110a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet
312891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet        HardwareConfig hardwareConfig = mParams.getHardwareConfig();
313891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet
314891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet        ScreenSize screenSize = hardwareConfig.getScreenSize();
3150a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet        if (screenSize != null) {
3160a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet            switch (screenSize) {
3170a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet                case SMALL:
3180a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet                    config.screenLayout |= Configuration.SCREENLAYOUT_SIZE_SMALL;
3190a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet                    break;
3200a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet                case NORMAL:
3210a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet                    config.screenLayout |= Configuration.SCREENLAYOUT_SIZE_NORMAL;
3220a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet                    break;
3230a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet                case LARGE:
3240a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet                    config.screenLayout |= Configuration.SCREENLAYOUT_SIZE_LARGE;
3250a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet                    break;
3260a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet                case XLARGE:
3270a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet                    config.screenLayout |= Configuration.SCREENLAYOUT_SIZE_XLARGE;
3280a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet                    break;
3290a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet            }
3300a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet        }
3310a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet
332891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet        Density density = hardwareConfig.getDensity();
3330a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet        if (density == null) {
3340a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet            density = Density.MEDIUM;
3350a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet        }
3360a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet
337891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet        config.screenWidthDp = hardwareConfig.getScreenWidth() / density.getDpiValue();
338891b703f7b1e0e396d16477cc66a286da7161b49Xavier Ducrohet        config.screenHeightDp = hardwareConfig.getScreenHeight() / density.getDpiValue();
3390a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet        if (config.screenHeightDp < config.screenWidthDp) {
3400a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet            config.smallestScreenWidthDp = config.screenHeightDp;
3410a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet        } else {
3420a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet            config.smallestScreenWidthDp = config.screenWidthDp;
3430a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet        }
344908aecc3a63c5520d5b11da14a9383f885b7d126Dianne Hackborn        config.densityDpi = density.getDpiValue();
3450a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet
3460a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet        // never run in compat mode:
3470a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet        config.compatScreenWidthDp = config.screenWidthDp;
3480a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet        config.compatScreenHeightDp = config.screenHeightDp;
3490a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet
3500a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet        // TODO: fill in more config info.
3510a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet
3520a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet        return config;
3530a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet    }
3540a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet
3550a49635b171f3ba366b1a7ebf28791c4661829bdXavier Ducrohet
356b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    // --- FrameworkResourceIdProvider methods
357b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet
358b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    @Override
359b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    public Integer getId(ResourceType resType, String resName) {
360b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet        return Bridge.getResourceId(resType, resName);
361b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet    }
362b0d34f9c99cbd43e8238c5952b19d032f02dd168Xavier Ducrohet}
363