1 /*
2  * Copyright (C) 2018 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.layout.remote.api;
18 
19 import com.android.ide.common.rendering.api.ResourceNamespace.Resolver;
20 import com.android.ide.common.rendering.api.ResourceValue;
21 import com.android.layout.remote.util.RemoteResolverAdapter;
22 import com.android.tools.layoutlib.annotations.NotNull;
23 import com.android.tools.layoutlib.annotations.Nullable;
24 
25 import java.io.Serializable;
26 import java.rmi.RemoteException;
27 
28 /**
29  * Wrapper for {@link ResourceValue} that can be transferred to a different VM.
30  *
31  * @param <T> the ResourceValue instance type
32  */
33 public class RemoteResourceValue<T extends ResourceValue> implements Serializable {
34     private static final RemoteResourceValue<ResourceValue> NULL_INSTANCE =
35             new RemoteResourceValue<>(null, null);
36 
37     private final T mResourceValue;
38     private final RemoteNamespaceResolver mRemoteResolver;
39 
RemoteResourceValue(@ullable T resourceValue, @Nullable RemoteNamespaceResolver remoteResolver)40     private RemoteResourceValue(@Nullable T resourceValue,
41             @Nullable RemoteNamespaceResolver remoteResolver) {
42         mResourceValue = resourceValue;
43         mRemoteResolver = remoteResolver;
44     }
45 
46     /**
47      * Returns a RemoteResourceValue that wraps the given {@link ResourceValue} instance. The passed
48      * resource value can be null.
49      */
50     @NotNull
fromResourceValue( T resourceValue)51     public static <T extends ResourceValue> RemoteResourceValue<T> fromResourceValue(
52             T resourceValue) {
53         if (resourceValue == null) {
54             //noinspection unchecked
55             return (RemoteResourceValue<T>) NULL_INSTANCE;
56         }
57         try {
58             return new RemoteResourceValue<>(resourceValue,
59                     RemoteResolverAdapter.create(resourceValue.getNamespaceResolver()));
60 
61         } catch (RemoteException e) {
62             throw new RuntimeException(e);
63         }
64     }
65 
66     /**
67      * Returns the {@link ResourceValue} wrapped by a remote wrapper
68      */
69     @NotNull
toResourceValue( @otNull RemoteResourceValue<T> remoteResourceValue)70     private static <T extends ResourceValue> T toResourceValue(
71             @NotNull RemoteResourceValue<T> remoteResourceValue) {
72         T remoteValue = remoteResourceValue.mResourceValue;
73         if (remoteValue == null) {
74             return null;
75         }
76 
77         // The Resolver is not transferred in the ResourceValue (it's transient) so we use the
78         // information in the wrapper to reconstruct it.
79         RemoteNamespaceResolver remoteResolver = remoteResourceValue.mRemoteResolver;
80 
81 //        TODO: Rethink this as setNamespaceResolver is not available in prebuilts any more
82 //        if (remoteResolver != null) {
83 //            remoteValue.setNamespaceResolver(new Resolver() {
84 //                @Override
85 //                public String prefixToUri(String namespacePrefix) {
86 //                    try {
87 //                        return remoteResolver.remotePrefixToUri(namespacePrefix);
88 //                    } catch (RemoteException e) {
89 //                        throw new RuntimeException(e);
90 //                    }
91 //                }
92 //
93 //                @Override
94 //                public String uriToPrefix(String namespaceUri) {
95 //                    try {
96 //                        return remoteResolver.remoteUriToPrefix(namespaceUri);
97 //                    } catch (RemoteException e) {
98 //                        throw new RuntimeException(e);
99 //                    }
100 //                }
101 //            });
102 //        }
103 //        else {
104 //            remoteValue.setNamespaceResolver(Resolver.EMPTY_RESOLVER);
105 //        }
106 
107         return remoteValue;
108     }
109 
110     /**
111      * Returns the {@link ResourceValue} wrapped by this remote wrapper
112      */
113     @NotNull
toResourceValue()114     public T toResourceValue() {
115         return RemoteResourceValue.toResourceValue(this);
116     }
117 }
118