1282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/*
2282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Copyright (C) 2010 The Android Open Source Project
3282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
4282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
5282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * you may not use this file except in compliance with the License.
6282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * You may obtain a copy of the License at
7282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
8282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
9282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
10282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Unless required by applicable law or agreed to in writing, software
11282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
12282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * See the License for the specific language governing permissions and
14282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * limitations under the License.
15282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
16282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
17282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipackage com.android.layoutlib.bridge.impl;
18282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
19282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport static com.android.ide.common.rendering.api.Result.Status.ERROR_LOCK_INTERRUPTED;
20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport static com.android.ide.common.rendering.api.Result.Status.ERROR_TIMEOUT;
21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.HardwareConfig;
24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.LayoutLog;
25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.RenderParams;
26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.RenderResources;
27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.RenderResources.FrameworkResourceIdProvider;
28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.Result;
29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.layoutlib.bridge.Bridge;
30282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.layoutlib.bridge.android.BridgeContext;
31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.resources.Density;
32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.resources.ResourceType;
33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.resources.ScreenOrientation;
34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.resources.ScreenSize;
35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.content.res.Configuration;
37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.os.HandlerThread_Delegate;
38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.os.Looper;
39282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.util.DisplayMetrics;
40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.view.ViewConfiguration_Accessor;
41282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.view.inputmethod.InputMethodManager;
42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.view.inputmethod.InputMethodManager_Accessor;
43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.concurrent.TimeUnit;
45282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.concurrent.locks.ReentrantLock;
46282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
47282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/**
48282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Base class for rendering action.
49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * It provides life-cycle methods to init and stop the rendering.
51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * The most important methods are:
52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * {@link #init(long)} and {@link #acquire(long)} to start a rendering and {@link #release()}
53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * after the rendering.
54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param <T> the {@link RenderParams} implementation
57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipublic abstract class RenderAction<T extends RenderParams> extends FrameworkResourceIdProvider {
60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * The current context being rendered. This is set through {@link #acquire(long)} and
63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * {@link #init(long)}, and unset in {@link #release()}.
64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private static BridgeContext sCurrentContext = null;
66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private final T mParams;
68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private BridgeContext mContext;
70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Creates a renderAction.
73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * <p>
74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * This <b>must</b> be followed by a call to {@link RenderAction#init()}, which act as a
75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * call to {@link RenderAction#acquire(long)}
76282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param params the RenderParams. This must be a copy that the action can keep
78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    protected RenderAction(T params) {
81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mParams = params;
82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Initializes and acquires the scene, creating various Android objects such as context,
86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * inflater, and parser.
87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param timeout the time to wait if another rendering is happening.
89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @return whether the scene was prepared
91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @see #acquire(long)
93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @see #release()
94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public Result init(long timeout) {
96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // acquire the lock. if the result is null, lock was just acquired, otherwise, return
97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the result.
98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Result result = acquireLock(timeout);
99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result != null) {
100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return result;
101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        HardwareConfig hardwareConfig = mParams.getHardwareConfig();
104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // setup the display Metrics.
106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        DisplayMetrics metrics = new DisplayMetrics();
107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        metrics.densityDpi = metrics.noncompatDensityDpi =
108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                hardwareConfig.getDensity().getDpiValue();
109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        metrics.density = metrics.noncompatDensity =
111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                metrics.densityDpi / (float) DisplayMetrics.DENSITY_DEFAULT;
112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        metrics.scaledDensity = metrics.noncompatScaledDensity = metrics.density;
114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        metrics.widthPixels = metrics.noncompatWidthPixels = hardwareConfig.getScreenWidth();
116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        metrics.heightPixels = metrics.noncompatHeightPixels = hardwareConfig.getScreenHeight();
117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        metrics.xdpi = metrics.noncompatXdpi = hardwareConfig.getXdpi();
118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        metrics.ydpi = metrics.noncompatYdpi = hardwareConfig.getYdpi();
119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        RenderResources resources = mParams.getResources();
121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // build the context
123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
1248930cb4f37ff0fbde65f7afd4bbe06ab77677f78Deepanshu Gupta                mParams.getProjectCallback(), getConfiguration(), mParams.getTargetSdkVersion(),
1258930cb4f37ff0fbde65f7afd4bbe06ab77677f78Deepanshu Gupta                mParams.isRtlSupported());
126282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
127282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        setUp();
128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return SUCCESS.createResult();
130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Prepares the scene for action.
135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * <p>
136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * This call is blocking if another rendering/inflating is currently happening, and will return
137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * whether the preparation worked.
138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * The preparation can fail if another rendering took too long and the timeout was elapsed.
140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * More than one call to this from the same thread will have no effect and will return
142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * {@link Result#SUCCESS}.
143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
144282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * After scene actions have taken place, only one call to {@link #release()} must be
145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * done.
146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param timeout the time to wait if another rendering is happening.
148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @return whether the scene was prepared
150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @see #release()
152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @throws IllegalStateException if {@link #init(long)} was never called.
154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public Result acquire(long timeout) {
156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (mContext == null) {
157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            throw new IllegalStateException("After scene creation, #init() must be called");
158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // acquire the lock. if the result is null, lock was just acquired, otherwise, return
161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the result.
162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Result result = acquireLock(timeout);
163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result != null) {
164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return result;
165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        setUp();
168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return SUCCESS.createResult();
170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Acquire the lock so that the scene can be acted upon.
174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * <p>
175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * This returns null if the lock was just acquired, otherwise it returns
176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * {@link Result#SUCCESS} if the lock already belonged to that thread, or another
177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * instance (see {@link Result#getStatus()}) if an error occurred.
178282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param timeout the time to wait if another rendering is happening.
180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @return null if the lock was just acquire or another result depending on the state.
181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @throws IllegalStateException if the current context is different than the one owned by
183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *      the scene.
184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private Result acquireLock(long timeout) {
186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ReentrantLock lock = Bridge.getLock();
187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (lock.isHeldByCurrentThread() == false) {
188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            try {
189282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                if (acquired == false) {
192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    return ERROR_TIMEOUT.createResult();
193282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } catch (InterruptedException e) {
195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return ERROR_LOCK_INTERRUPTED.createResult();
196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // This thread holds the lock already. Checks that this wasn't for a different context.
199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // If this is called by init, mContext will be null and so should sCurrentContext
200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // anyway
201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (mContext != sCurrentContext) {
202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                throw new IllegalStateException("Acquiring different scenes from same thread without releases");
203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return SUCCESS.createResult();
205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return null;
208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Cleans up the scene after an action.
212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public void release() {
214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ReentrantLock lock = Bridge.getLock();
215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // with the use of finally blocks, it is possible to find ourself calling this
217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // without a successful call to prepareScene. This test makes sure that unlock() will
218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // not throw IllegalMonitorStateException.
219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (lock.isHeldByCurrentThread()) {
220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tearDown();
221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            lock.unlock();
222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Sets up the session for rendering.
227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * <p/>
228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * The counterpart is {@link #tearDown()}.
229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private void setUp() {
231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // make sure the Resources object references the context (and other objects) for this
232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // scene
233282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mContext.initResources();
234282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sCurrentContext = mContext;
235282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // create an InputMethodManager
237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        InputMethodManager.getInstance();
238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        LayoutLog currentLog = mParams.getLog();
240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Bridge.setLog(currentLog);
241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mContext.getRenderResources().setFrameworkResourceIdProvider(this);
242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mContext.getRenderResources().setLogger(currentLog);
243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Tear down the session after rendering.
247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * <p/>
248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * The counterpart is {@link #setUp()}.
249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private void tearDown() {
25103a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta        // The context may be null, if there was an error during init().
25203a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta        if (mContext != null) {
25303a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta            // Make sure to remove static references, otherwise we could not unload the lib
25403a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta            mContext.disposeResources();
25503a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta        }
256282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
25703a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta        if (sCurrentContext != null) {
25803a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta            // quit HandlerThread created during this session.
25903a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta            HandlerThread_Delegate.cleanUp(sCurrentContext);
26003a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta        }
261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
262282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // clear the stored ViewConfiguration since the map is per density and not per context.
263282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ViewConfiguration_Accessor.clearConfigurations();
264282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
265282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // remove the InputMethodManager
266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        InputMethodManager_Accessor.resetInstance();
267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sCurrentContext = null;
269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Bridge.setLog(null);
27103a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta        if (mContext != null) {
27203a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta            mContext.getRenderResources().setFrameworkResourceIdProvider(null);
27303a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta            mContext.getRenderResources().setLogger(null);
27403a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta        }
27503a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta
276282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
277282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
278282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static BridgeContext getCurrentContext() {
279282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return sCurrentContext;
280282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
281282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    protected T getParams() {
283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return mParams;
284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    protected BridgeContext getContext() {
287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return mContext;
288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Returns the log associated with the session.
292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @return the log or null if there are none.
293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public LayoutLog getLog() {
295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (mParams != null) {
296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return mParams.getLog();
297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return null;
300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Checks that the lock is owned by the current thread and that the current context is the one
304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * from this scene.
305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @throws IllegalStateException if the current context is different than the one owned by
307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *      the scene, or if {@link #acquire(long)} was not called.
308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    protected void checkLock() {
310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ReentrantLock lock = Bridge.getLock();
311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (lock.isHeldByCurrentThread() == false) {
312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            throw new IllegalStateException("scene must be acquired first. see #acquire(long)");
313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (sCurrentContext != mContext) {
315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            throw new IllegalStateException("Thread acquired a scene but is rendering a different one");
316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
317282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private Configuration getConfiguration() {
320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Configuration config = new Configuration();
321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        HardwareConfig hardwareConfig = mParams.getHardwareConfig();
323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ScreenSize screenSize = hardwareConfig.getScreenSize();
325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (screenSize != null) {
326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            switch (screenSize) {
327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                case SMALL:
328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    config.screenLayout |= Configuration.SCREENLAYOUT_SIZE_SMALL;
329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    break;
330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                case NORMAL:
331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    config.screenLayout |= Configuration.SCREENLAYOUT_SIZE_NORMAL;
332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    break;
333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                case LARGE:
334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    config.screenLayout |= Configuration.SCREENLAYOUT_SIZE_LARGE;
335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    break;
336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                case XLARGE:
337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    config.screenLayout |= Configuration.SCREENLAYOUT_SIZE_XLARGE;
338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    break;
339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Density density = hardwareConfig.getDensity();
343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (density == null) {
344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            density = Density.MEDIUM;
345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        config.screenWidthDp = hardwareConfig.getScreenWidth() / density.getDpiValue();
348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        config.screenHeightDp = hardwareConfig.getScreenHeight() / density.getDpiValue();
349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (config.screenHeightDp < config.screenWidthDp) {
350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            config.smallestScreenWidthDp = config.screenHeightDp;
351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            config.smallestScreenWidthDp = config.screenWidthDp;
353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        config.densityDpi = density.getDpiValue();
355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
356282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // never run in compat mode:
357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        config.compatScreenWidthDp = config.screenWidthDp;
358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        config.compatScreenHeightDp = config.screenHeightDp;
359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ScreenOrientation orientation = hardwareConfig.getOrientation();
361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (orientation != null) {
362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            switch (orientation) {
363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            case PORTRAIT:
364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                config.orientation = Configuration.ORIENTATION_PORTRAIT;
365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            case LANDSCAPE:
367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                config.orientation = Configuration.ORIENTATION_LANDSCAPE;
368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            case SQUARE:
370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                config.orientation = Configuration.ORIENTATION_SQUARE;
371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            config.orientation = Configuration.ORIENTATION_UNDEFINED;
375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
377282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // TODO: fill in more config info.
378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return config;
380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // --- FrameworkResourceIdProvider methods
384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
385282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    @Override
386282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public Integer getId(ResourceType resType, String resName) {
387282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return Bridge.getResourceId(resType, resName);
388282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
389282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
390