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 com.android.ide.common.rendering.api.HardwareConfig;
20282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.LayoutLog;
21282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.RenderParams;
22282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.RenderResources;
23282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.RenderResources.FrameworkResourceIdProvider;
24282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.ide.common.rendering.api.Result;
25282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.layoutlib.bridge.Bridge;
26282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.layoutlib.bridge.android.BridgeContext;
27282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.resources.Density;
28282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.resources.ResourceType;
29282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.resources.ScreenOrientation;
30295ef6be084d1c2f22ef25a87e508c1f5c14ee5aDeepanshu Guptaimport com.android.resources.ScreenRound;
31282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport com.android.resources.ScreenSize;
32282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
33282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.content.res.Configuration;
34282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.os.HandlerThread_Delegate;
35282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.util.DisplayMetrics;
36282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.view.ViewConfiguration_Accessor;
37282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.view.inputmethod.InputMethodManager;
38282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport android.view.inputmethod.InputMethodManager_Accessor;
39b556decf75b2b084e1aed54ac7fa23a141eedb7fDeepanshu Guptaimport android.widget.SimpleMonthView_Delegate;
40282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4182c7fdb1f6346862de373c95c618e370f81d8df6Deepanshu Guptaimport java.util.Locale;
42282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.concurrent.TimeUnit;
43282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskiimport java.util.concurrent.locks.ReentrantLock;
44282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
4537dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_LOCK_INTERRUPTED;
4637dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.ERROR_TIMEOUT;
4737dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
4837dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta
49282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski/**
50282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * Base class for rendering action.
51282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
52282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * It provides life-cycle methods to init and stop the rendering.
53282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * The most important methods are:
54282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * {@link #init(long)} and {@link #acquire(long)} to start a rendering and {@link #release()}
55282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * after the rendering.
56282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
57282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
58282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski * @param <T> the {@link RenderParams} implementation
59282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski *
60282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski */
61282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinskipublic abstract class RenderAction<T extends RenderParams> extends FrameworkResourceIdProvider {
62282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
63282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
64282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * The current context being rendered. This is set through {@link #acquire(long)} and
65282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * {@link #init(long)}, and unset in {@link #release()}.
66282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
67282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private static BridgeContext sCurrentContext = null;
68282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
69282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private final T mParams;
70282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
71282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private BridgeContext mContext;
72282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
73282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
74282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Creates a renderAction.
75282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * <p>
76d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta     * This <b>must</b> be followed by a call to {@link RenderAction#init(long)}, which act as a
77282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * call to {@link RenderAction#acquire(long)}
78282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
79282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param params the RenderParams. This must be a copy that the action can keep
80282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
81282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
82282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    protected RenderAction(T params) {
83282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mParams = params;
84282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
85282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
86282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
87282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Initializes and acquires the scene, creating various Android objects such as context,
88282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * inflater, and parser.
89282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
90282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param timeout the time to wait if another rendering is happening.
91282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
92282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @return whether the scene was prepared
93282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
94282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @see #acquire(long)
95282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @see #release()
96282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
97282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public Result init(long timeout) {
98282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // acquire the lock. if the result is null, lock was just acquired, otherwise, return
99282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the result.
100282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Result result = acquireLock(timeout);
101282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result != null) {
102282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return result;
103282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
104282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
105282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        HardwareConfig hardwareConfig = mParams.getHardwareConfig();
106282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
107282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // setup the display Metrics.
108282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        DisplayMetrics metrics = new DisplayMetrics();
109282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        metrics.densityDpi = metrics.noncompatDensityDpi =
110282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                hardwareConfig.getDensity().getDpiValue();
111282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
112282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        metrics.density = metrics.noncompatDensity =
113282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                metrics.densityDpi / (float) DisplayMetrics.DENSITY_DEFAULT;
114282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
115282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        metrics.scaledDensity = metrics.noncompatScaledDensity = metrics.density;
116282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
117282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        metrics.widthPixels = metrics.noncompatWidthPixels = hardwareConfig.getScreenWidth();
118282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        metrics.heightPixels = metrics.noncompatHeightPixels = hardwareConfig.getScreenHeight();
119282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        metrics.xdpi = metrics.noncompatXdpi = hardwareConfig.getXdpi();
120282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        metrics.ydpi = metrics.noncompatYdpi = hardwareConfig.getYdpi();
121282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
122282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        RenderResources resources = mParams.getResources();
123282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
124282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // build the context
125282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
12637dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta                mParams.getAssets(), mParams.getLayoutlibCallback(), getConfiguration(),
127d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta                mParams.getTargetSdkVersion(), mParams.isRtlSupported());
128282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
129282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        setUp();
130282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
131282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return SUCCESS.createResult();
132282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
133282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
134282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
135282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
136282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Prepares the scene for action.
137282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * <p>
138282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * This call is blocking if another rendering/inflating is currently happening, and will return
139282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * whether the preparation worked.
140282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
141282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * The preparation can fail if another rendering took too long and the timeout was elapsed.
142282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
143282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * More than one call to this from the same thread will have no effect and will return
144d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta     * {@link Result.Status#SUCCESS}.
145282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
146282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * After scene actions have taken place, only one call to {@link #release()} must be
147282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * done.
148282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
149282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param timeout the time to wait if another rendering is happening.
150282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
151282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @return whether the scene was prepared
152282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
153282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @see #release()
154282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
155282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @throws IllegalStateException if {@link #init(long)} was never called.
156282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
157282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public Result acquire(long timeout) {
158282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (mContext == null) {
159282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            throw new IllegalStateException("After scene creation, #init() must be called");
160282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
161282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
162282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // acquire the lock. if the result is null, lock was just acquired, otherwise, return
163282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // the result.
164282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Result result = acquireLock(timeout);
165282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (result != null) {
166282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return result;
167282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
168282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
169282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        setUp();
170282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
171282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return SUCCESS.createResult();
172282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
173282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
174282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
175282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Acquire the lock so that the scene can be acted upon.
176282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * <p>
177282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * This returns null if the lock was just acquired, otherwise it returns
178d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta     * {@link Result.Status#SUCCESS} if the lock already belonged to that thread, or another
179282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * instance (see {@link Result#getStatus()}) if an error occurred.
180282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
181282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @param timeout the time to wait if another rendering is happening.
182282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @return null if the lock was just acquire or another result depending on the state.
183282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
184282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @throws IllegalStateException if the current context is different than the one owned by
185282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *      the scene.
186282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
187282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private Result acquireLock(long timeout) {
188282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ReentrantLock lock = Bridge.getLock();
189d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta        if (!lock.isHeldByCurrentThread()) {
190282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            try {
191282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
192282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
193d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta                if (!acquired) {
194282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    return ERROR_TIMEOUT.createResult();
195282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                }
196282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            } catch (InterruptedException e) {
197282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                return ERROR_LOCK_INTERRUPTED.createResult();
198282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
199282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
200282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // This thread holds the lock already. Checks that this wasn't for a different context.
201282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // If this is called by init, mContext will be null and so should sCurrentContext
202282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            // anyway
203282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            if (mContext != sCurrentContext) {
204282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                throw new IllegalStateException("Acquiring different scenes from same thread without releases");
205282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
206282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return SUCCESS.createResult();
207282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
208282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
209282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return null;
210282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
211282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
212282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
213282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Cleans up the scene after an action.
214282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
215282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public void release() {
216282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ReentrantLock lock = Bridge.getLock();
217282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
218282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // with the use of finally blocks, it is possible to find ourself calling this
219282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // without a successful call to prepareScene. This test makes sure that unlock() will
220282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // not throw IllegalMonitorStateException.
221282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (lock.isHeldByCurrentThread()) {
222282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            tearDown();
223282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            lock.unlock();
224282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
225282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
226282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
227282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
228282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Sets up the session for rendering.
229282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * <p/>
230282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * The counterpart is {@link #tearDown()}.
231282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
232282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private void setUp() {
233996458b76c944f78eee26d7bd8cb4d39303b9119Deepanshu Gupta        // setup the ParserFactory
234996458b76c944f78eee26d7bd8cb4d39303b9119Deepanshu Gupta        ParserFactory.setParserFactory(mParams.getLayoutlibCallback().getParserFactory());
235996458b76c944f78eee26d7bd8cb4d39303b9119Deepanshu Gupta
236282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // make sure the Resources object references the context (and other objects) for this
237282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // scene
238282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mContext.initResources();
239282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sCurrentContext = mContext;
240282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
241282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // create an InputMethodManager
242282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        InputMethodManager.getInstance();
243282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
244282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        LayoutLog currentLog = mParams.getLog();
245282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Bridge.setLog(currentLog);
246282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mContext.getRenderResources().setFrameworkResourceIdProvider(this);
247282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        mContext.getRenderResources().setLogger(currentLog);
248282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
249282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
250282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
251282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Tear down the session after rendering.
252282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * <p/>
253282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * The counterpart is {@link #setUp()}.
254282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
255282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private void tearDown() {
25603a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta        // The context may be null, if there was an error during init().
25703a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta        if (mContext != null) {
25803a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta            // Make sure to remove static references, otherwise we could not unload the lib
25903a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta            mContext.disposeResources();
26003a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta        }
261282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
26203a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta        if (sCurrentContext != null) {
26303a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta            // quit HandlerThread created during this session.
26403a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta            HandlerThread_Delegate.cleanUp(sCurrentContext);
26503a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta        }
266282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
267282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // clear the stored ViewConfiguration since the map is per density and not per context.
268282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ViewConfiguration_Accessor.clearConfigurations();
269282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
270282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // remove the InputMethodManager
271282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        InputMethodManager_Accessor.resetInstance();
272282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
273282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        sCurrentContext = null;
274282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
275282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Bridge.setLog(null);
27603a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta        if (mContext != null) {
27703a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta            mContext.getRenderResources().setFrameworkResourceIdProvider(null);
27803a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta            mContext.getRenderResources().setLogger(null);
27903a057c1af9ca3f125c7924bf0b78da52223d8d3Deepanshu Gupta        }
280f2d408b51debadca830eefbf8131185ac55ce699Deepanshu Gupta        ParserFactory.setParserFactory(null);
281b556decf75b2b084e1aed54ac7fa23a141eedb7fDeepanshu Gupta        SimpleMonthView_Delegate.clearCache();
282282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
283282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
284282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public static BridgeContext getCurrentContext() {
285282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return sCurrentContext;
286282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
287282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
288282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    protected T getParams() {
289282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return mParams;
290282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
291282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
292282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    protected BridgeContext getContext() {
293282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return mContext;
294282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
295282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
296282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
297282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Returns the log associated with the session.
298282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @return the log or null if there are none.
299282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
300282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public LayoutLog getLog() {
301282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (mParams != null) {
302282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            return mParams.getLog();
303282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
304282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
305282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return null;
306282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
307282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
308282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    /**
309282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * Checks that the lock is owned by the current thread and that the current context is the one
310282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * from this scene.
311282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *
312282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     * @throws IllegalStateException if the current context is different than the one owned by
313282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     *      the scene, or if {@link #acquire(long)} was not called.
314282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski     */
315282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    protected void checkLock() {
316282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ReentrantLock lock = Bridge.getLock();
317d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta        if (!lock.isHeldByCurrentThread()) {
318282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            throw new IllegalStateException("scene must be acquired first. see #acquire(long)");
319282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
320282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (sCurrentContext != mContext) {
321282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            throw new IllegalStateException("Thread acquired a scene but is rendering a different one");
322282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
323282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
324282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
325282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    private Configuration getConfiguration() {
326282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Configuration config = new Configuration();
327282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
328282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        HardwareConfig hardwareConfig = mParams.getHardwareConfig();
329282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
330282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ScreenSize screenSize = hardwareConfig.getScreenSize();
331282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (screenSize != null) {
332282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            switch (screenSize) {
333282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                case SMALL:
334282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    config.screenLayout |= Configuration.SCREENLAYOUT_SIZE_SMALL;
335282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    break;
336282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                case NORMAL:
337282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    config.screenLayout |= Configuration.SCREENLAYOUT_SIZE_NORMAL;
338282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    break;
339282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                case LARGE:
340282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    config.screenLayout |= Configuration.SCREENLAYOUT_SIZE_LARGE;
341282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    break;
342282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                case XLARGE:
343282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    config.screenLayout |= Configuration.SCREENLAYOUT_SIZE_XLARGE;
344282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                    break;
345282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
346282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
347282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
348282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        Density density = hardwareConfig.getDensity();
349282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (density == null) {
350282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            density = Density.MEDIUM;
351282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
352282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
353282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        config.screenWidthDp = hardwareConfig.getScreenWidth() / density.getDpiValue();
354282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        config.screenHeightDp = hardwareConfig.getScreenHeight() / density.getDpiValue();
355282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (config.screenHeightDp < config.screenWidthDp) {
356d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta            //noinspection SuspiciousNameCombination
357282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            config.smallestScreenWidthDp = config.screenHeightDp;
358282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
359282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            config.smallestScreenWidthDp = config.screenWidthDp;
360282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
361282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        config.densityDpi = density.getDpiValue();
362282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
363282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // never run in compat mode:
364282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        config.compatScreenWidthDp = config.screenWidthDp;
365282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        config.compatScreenHeightDp = config.screenHeightDp;
366282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
367282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        ScreenOrientation orientation = hardwareConfig.getOrientation();
368282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        if (orientation != null) {
369282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            switch (orientation) {
370282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            case PORTRAIT:
371282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                config.orientation = Configuration.ORIENTATION_PORTRAIT;
372282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
373282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            case LANDSCAPE:
374282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                config.orientation = Configuration.ORIENTATION_LANDSCAPE;
375282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
376282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            case SQUARE:
377d51834bdfad0cd3142ac464ab3a3b0db14f884c3Deepanshu Gupta                //noinspection deprecation
378282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                config.orientation = Configuration.ORIENTATION_SQUARE;
379282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski                break;
380282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            }
381282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        } else {
382282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski            config.orientation = Configuration.ORIENTATION_UNDEFINED;
383282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        }
384282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
385295ef6be084d1c2f22ef25a87e508c1f5c14ee5aDeepanshu Gupta        try {
386295ef6be084d1c2f22ef25a87e508c1f5c14ee5aDeepanshu Gupta            ScreenRound roundness = hardwareConfig.getScreenRoundness();
387295ef6be084d1c2f22ef25a87e508c1f5c14ee5aDeepanshu Gupta            if (roundness != null) {
388295ef6be084d1c2f22ef25a87e508c1f5c14ee5aDeepanshu Gupta                switch (roundness) {
389295ef6be084d1c2f22ef25a87e508c1f5c14ee5aDeepanshu Gupta                    case ROUND:
390295ef6be084d1c2f22ef25a87e508c1f5c14ee5aDeepanshu Gupta                        config.screenLayout |= Configuration.SCREENLAYOUT_ROUND_YES;
391295ef6be084d1c2f22ef25a87e508c1f5c14ee5aDeepanshu Gupta                        break;
392295ef6be084d1c2f22ef25a87e508c1f5c14ee5aDeepanshu Gupta                    case NOTROUND:
393295ef6be084d1c2f22ef25a87e508c1f5c14ee5aDeepanshu Gupta                        config.screenLayout |= Configuration.SCREENLAYOUT_ROUND_NO;
394295ef6be084d1c2f22ef25a87e508c1f5c14ee5aDeepanshu Gupta                }
395295ef6be084d1c2f22ef25a87e508c1f5c14ee5aDeepanshu Gupta            } else {
396295ef6be084d1c2f22ef25a87e508c1f5c14ee5aDeepanshu Gupta                config.screenLayout |= Configuration.SCREENLAYOUT_ROUND_UNDEFINED;
397295ef6be084d1c2f22ef25a87e508c1f5c14ee5aDeepanshu Gupta            }
398295ef6be084d1c2f22ef25a87e508c1f5c14ee5aDeepanshu Gupta        } catch (NoSuchMethodError ignored) {
399295ef6be084d1c2f22ef25a87e508c1f5c14ee5aDeepanshu Gupta            // getScreenRoundness was added in later stages of API 15. So, it's not present on some
400295ef6be084d1c2f22ef25a87e508c1f5c14ee5aDeepanshu Gupta            // preview releases of API 15.
401295ef6be084d1c2f22ef25a87e508c1f5c14ee5aDeepanshu Gupta            // TODO: Remove the try catch around Oct 2015.
402295ef6be084d1c2f22ef25a87e508c1f5c14ee5aDeepanshu Gupta        }
40382c7fdb1f6346862de373c95c618e370f81d8df6Deepanshu Gupta        String locale = getParams().getLocale();
40482c7fdb1f6346862de373c95c618e370f81d8df6Deepanshu Gupta        if (locale != null && !locale.isEmpty()) config.locale = new Locale(locale);
405295ef6be084d1c2f22ef25a87e508c1f5c14ee5aDeepanshu Gupta
406282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        // TODO: fill in more config info.
407282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
408282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return config;
409282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
410282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
411282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
412282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    // --- FrameworkResourceIdProvider methods
413282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski
414282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    @Override
415282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    public Integer getId(ResourceType resType, String resName) {
416282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski        return Bridge.getResourceId(resType, resName);
417282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski    }
418282e181b58cf72b6ca770dc7ca5f91f135444502Adam Lesinski}
419