1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.layoutlib.bridge.remote.server;
18 
19 import com.android.ide.common.rendering.api.DrawableParams;
20 import com.android.ide.common.rendering.api.RenderParams;
21 import com.android.ide.common.rendering.api.Result;
22 import com.android.ide.common.rendering.api.SessionParams;
23 import com.android.layout.remote.api.RemoteBridge;
24 import com.android.layout.remote.api.RemoteDrawableParams;
25 import com.android.layout.remote.api.RemoteLayoutLog;
26 import com.android.layout.remote.api.RemoteRenderParams;
27 import com.android.layout.remote.api.RemoteRenderSession;
28 import com.android.layout.remote.api.RemoteSessionParams;
29 import com.android.layoutlib.bridge.Bridge;
30 import com.android.layoutlib.bridge.remote.server.adapters.RemoteAssetRepositoryAdapter;
31 import com.android.layoutlib.bridge.remote.server.adapters.RemoteILayoutPullParserAdapter;
32 import com.android.layoutlib.bridge.remote.server.adapters.RemoteLayoutLogAdapter;
33 import com.android.layoutlib.bridge.remote.server.adapters.RemoteLayoutlibCallbackAdapter;
34 import com.android.layoutlib.bridge.remote.server.adapters.RemoteRenderResourcesAdapter;
35 import com.android.layoutlib.bridge.remote.server.adapters.RemoteRenderSessionAdapter;
36 import com.android.tools.layoutlib.annotations.NotNull;
37 
38 import java.io.File;
39 import java.rmi.RemoteException;
40 import java.util.HashMap;
41 import java.util.HashSet;
42 import java.util.Map;
43 import java.util.Set;
44 
45 /**
46  * Remote {@link Bridge} implementation. This class is the remote entry point for the server. Its
47  * responsibility is to receive the remote calls and apply the required transformations to convert
48  * it into a regular call to the {@link Bridge} class.
49  */
50 public class RemoteBridgeImpl implements RemoteBridge {
51     private Bridge mBridge = new Bridge();
52 
53     /**
54      * The project keys are used as key for some caches. They are usually expected to remain in
55      * memory so WeakReferences are used in the caches.
56      * Because in the remote bridge we do not have a real pointer to the object, we keep the strings
57      * in memory until they are cleared.
58      */
59     private Map<String, String> mCachedProjectKeys = new HashMap<>();
60 
61     @Override
init(Map<String, String> platformProperties, File fontLocation, String nativeLibPath, String icuDataPath, Map<String, Map<String, Integer>> enumValueMap, RemoteLayoutLog log)62     public boolean init(Map<String, String> platformProperties, File fontLocation,
63             String nativeLibPath, String icuDataPath,
64             Map<String, Map<String, Integer>> enumValueMap, RemoteLayoutLog log) {
65         return mBridge.init(platformProperties, fontLocation, nativeLibPath, icuDataPath,
66                 enumValueMap, log != null ? new RemoteLayoutLogAdapter(log) : null);
67     }
68 
69     @Override
dispose()70     public boolean dispose() {
71         return mBridge.dispose();
72     }
73 
setupRenderParams(@otNull RenderParams params, @NotNull RemoteRenderParams remoteParams)74     private static void setupRenderParams(@NotNull RenderParams params,
75             @NotNull RemoteRenderParams remoteParams) throws RemoteException {
76         params.setAssetRepository(new RemoteAssetRepositoryAdapter(remoteParams.getAssets()));
77         params.setActivityName(remoteParams.getActivityName());
78         params.setAppIcon(remoteParams.getAppIcon());
79         params.setAppLabel(remoteParams.getAppLabel());
80         params.setTimeout(remoteParams.getTimeout());
81         params.setLocale(remoteParams.getLocale());
82         if (remoteParams.isForceNoDecor()) {
83             params.setForceNoDecor();
84         }
85         params.setRtlSupport(remoteParams.isRtlSupported());
86         if (remoteParams.isTransparentBackground()) {
87             params.setTransparentBackground();
88         }
89         params.setImageFactory(remoteParams.getImageFactory());
90         // TODO: Also unpack remote flags and pass them to RenderParams
91     }
92 
93     @NotNull
94     @Override
createSession(@otNull RemoteSessionParams remoteParams)95     public RemoteRenderSession createSession(@NotNull RemoteSessionParams remoteParams) {
96         try {
97             String projectKey = mCachedProjectKeys.putIfAbsent(remoteParams.getProjectKey(),
98                     remoteParams.getProjectKey());
99 
100             // Unpack the remote params and convert it into the local SessionParams.
101             SessionParams params = new SessionParams(
102                     new RemoteILayoutPullParserAdapter(remoteParams.getLayoutDescription()),
103                     remoteParams.getRenderingMode(), projectKey,
104                     remoteParams.getRemoteHardwareConfig().getHardwareConfig(),
105                     new RemoteRenderResourcesAdapter(remoteParams.getRemoteResources()),
106                     new RemoteLayoutlibCallbackAdapter(remoteParams.getRemoteLayoutlibCallback()),
107                     remoteParams.getMinSdkVersion(), remoteParams.getTargetSdkVersion(),
108                     new RemoteLayoutLogAdapter(remoteParams.getLog()));
109             setupRenderParams(params, remoteParams);
110             return RemoteRenderSessionAdapter.create(mBridge.createSession(params));
111 
112         } catch (RemoteException e) {
113             throw new RuntimeException(e);
114         }
115     }
116 
117     @NotNull
118     @Override
renderDrawable(@otNull RemoteDrawableParams remoteParams)119     public Result renderDrawable(@NotNull RemoteDrawableParams remoteParams) {
120         try {
121             String projectKey = mCachedProjectKeys.putIfAbsent(remoteParams.getProjectKey(),
122                     remoteParams.getProjectKey());
123 
124             DrawableParams params = new DrawableParams(
125                     remoteParams.getDrawable(),
126                     projectKey,
127                     remoteParams.getRemoteHardwareConfig().getHardwareConfig(),
128                     new RemoteRenderResourcesAdapter(remoteParams.getRemoteResources()),
129                     new RemoteLayoutlibCallbackAdapter(remoteParams.getRemoteLayoutlibCallback()),
130                     remoteParams.getMinSdkVersion(), remoteParams.getTargetSdkVersion(),
131                     new RemoteLayoutLogAdapter(remoteParams.getLog()));
132             setupRenderParams(params, remoteParams);
133             return mBridge.renderDrawable(params);
134         } catch (RemoteException e) {
135             throw new RuntimeException(e);
136         }
137     }
138 
139     @Override
clearResourceCaches(String projectKey)140     public void clearResourceCaches(String projectKey) {
141         mCachedProjectKeys.remove(projectKey);
142         mBridge.clearResourceCaches(projectKey);
143     }
144 
145     @Override
isRtl(String locale)146     public boolean isRtl(String locale) {
147         return mBridge.isRtl(locale);
148     }
149 }
150