1 /*
2  * Copyright (C) 2013 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 android.content.res;
18 
19 import static android.os.Build.VERSION_CODES.O;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.compat.annotation.UnsupportedAppUsage;
24 import android.content.res.loader.ResourcesLoader;
25 import android.text.TextUtils;
26 
27 import java.util.Arrays;
28 import java.util.Objects;
29 
30 /** @hide */
31 public final class ResourcesKey {
32     @Nullable
33     @UnsupportedAppUsage
34     public final String mResDir;
35 
36     @Nullable
37     @UnsupportedAppUsage
38     public final String[] mSplitResDirs;
39 
40     @Nullable
41     public final String[] mOverlayPaths;
42 
43     @Nullable
44     public final String[] mLibDirs;
45 
46     /**
47      * The display ID that overrides the global resources display to produce the Resources display.
48      * If set to something other than {@link android.view.Display#INVALID_DISPLAY} this will
49      * override the global resources display for this key.
50      */
51     @UnsupportedAppUsage(maxTargetSdk = O)
52     public int mDisplayId;
53 
54     /**
55      * The configuration applied to the global configuration to produce the Resources configuration.
56      */
57     @NonNull
58     public final Configuration mOverrideConfiguration;
59 
60     @NonNull
61     public final CompatibilityInfo mCompatInfo;
62 
63     @Nullable
64     public final ResourcesLoader[] mLoaders;
65 
66     private final int mHash;
67 
ResourcesKey(@ullable String resDir, @Nullable String[] splitResDirs, @Nullable String[] overlayPaths, @Nullable String[] libDirs, int overrideDisplayId, @Nullable Configuration overrideConfig, @Nullable CompatibilityInfo compatInfo, @Nullable ResourcesLoader[] loader)68     public ResourcesKey(@Nullable String resDir,
69                         @Nullable String[] splitResDirs,
70                         @Nullable String[] overlayPaths,
71                         @Nullable String[] libDirs,
72                         int overrideDisplayId,
73                         @Nullable Configuration overrideConfig,
74                         @Nullable CompatibilityInfo compatInfo,
75                         @Nullable ResourcesLoader[] loader) {
76         mResDir = resDir;
77         mSplitResDirs = splitResDirs;
78         mOverlayPaths = overlayPaths;
79         mLibDirs = libDirs;
80         mLoaders = (loader != null && loader.length == 0) ? null : loader;
81         mDisplayId = overrideDisplayId;
82         mOverrideConfiguration = new Configuration(overrideConfig != null
83                 ? overrideConfig : Configuration.EMPTY);
84         mCompatInfo = compatInfo != null ? compatInfo : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
85 
86         int hash = 17;
87         hash = 31 * hash + Objects.hashCode(mResDir);
88         hash = 31 * hash + Arrays.hashCode(mSplitResDirs);
89         hash = 31 * hash + Arrays.hashCode(mOverlayPaths);
90         hash = 31 * hash + Arrays.hashCode(mLibDirs);
91         hash = 31 * hash + Objects.hashCode(mDisplayId);
92         hash = 31 * hash + Objects.hashCode(mOverrideConfiguration);
93         hash = 31 * hash + Objects.hashCode(mCompatInfo);
94         hash = 31 * hash + Arrays.hashCode(mLoaders);
95         mHash = hash;
96     }
97 
98     @UnsupportedAppUsage
ResourcesKey(@ullable String resDir, @Nullable String[] splitResDirs, @Nullable String[] overlayPaths, @Nullable String[] libDirs, int displayId, @Nullable Configuration overrideConfig, @Nullable CompatibilityInfo compatInfo)99     public ResourcesKey(@Nullable String resDir,
100             @Nullable String[] splitResDirs,
101             @Nullable String[] overlayPaths,
102             @Nullable String[] libDirs,
103             int displayId,
104             @Nullable Configuration overrideConfig,
105             @Nullable CompatibilityInfo compatInfo) {
106         this(resDir, splitResDirs, overlayPaths, libDirs, displayId, overrideConfig, compatInfo,
107                 null);
108     }
109 
hasOverrideConfiguration()110     public boolean hasOverrideConfiguration() {
111         return !Configuration.EMPTY.equals(mOverrideConfiguration);
112     }
113 
isPathReferenced(String path)114     public boolean isPathReferenced(String path) {
115         if (mResDir != null && mResDir.startsWith(path)) {
116             return true;
117         } else {
118             return anyStartsWith(mSplitResDirs, path) || anyStartsWith(mOverlayPaths, path)
119                     || anyStartsWith(mLibDirs, path);
120         }
121     }
122 
anyStartsWith(String[] list, String prefix)123     private static boolean anyStartsWith(String[] list, String prefix) {
124         if (list != null) {
125             for (String s : list) {
126                 if (s != null && s.startsWith(prefix)) {
127                     return true;
128                 }
129             }
130         }
131         return false;
132     }
133 
134     @Override
hashCode()135     public int hashCode() {
136         return mHash;
137     }
138 
139     @Override
equals(@ullable Object obj)140     public boolean equals(@Nullable Object obj) {
141         if (!(obj instanceof ResourcesKey)) {
142             return false;
143         }
144 
145         ResourcesKey peer = (ResourcesKey) obj;
146         if (mHash != peer.mHash) {
147             // If the hashes don't match, the objects can't match.
148             return false;
149         }
150 
151         if (!Objects.equals(mResDir, peer.mResDir)) {
152             return false;
153         }
154         if (!Arrays.equals(mSplitResDirs, peer.mSplitResDirs)) {
155             return false;
156         }
157         if (!Arrays.equals(mOverlayPaths, peer.mOverlayPaths)) {
158             return false;
159         }
160         if (!Arrays.equals(mLibDirs, peer.mLibDirs)) {
161             return false;
162         }
163         if (mDisplayId != peer.mDisplayId) {
164             return false;
165         }
166         if (!Objects.equals(mOverrideConfiguration, peer.mOverrideConfiguration)) {
167             return false;
168         }
169         if (!Objects.equals(mCompatInfo, peer.mCompatInfo)) {
170             return false;
171         }
172         if (!Arrays.equals(mLoaders, peer.mLoaders)) {
173             return false;
174         }
175         return true;
176     }
177 
178     @Override
toString()179     public String toString() {
180         StringBuilder builder = new StringBuilder().append("ResourcesKey{");
181         builder.append(" mHash=").append(Integer.toHexString(mHash));
182         builder.append(" mResDir=").append(mResDir);
183         builder.append(" mSplitDirs=[");
184         if (mSplitResDirs != null) {
185             builder.append(TextUtils.join(",", mSplitResDirs));
186         }
187         builder.append("]");
188         builder.append(" mOverlayDirs=[");
189         if (mOverlayPaths != null) {
190             builder.append(TextUtils.join(",", mOverlayPaths));
191         }
192         builder.append("]");
193         builder.append(" mLibDirs=[");
194         if (mLibDirs != null) {
195             builder.append(TextUtils.join(",", mLibDirs));
196         }
197         builder.append("]");
198         builder.append(" mDisplayId=").append(mDisplayId);
199         builder.append(" mOverrideConfig=").append(Configuration.resourceQualifierString(
200                 mOverrideConfiguration));
201         builder.append(" mCompatInfo=").append(mCompatInfo);
202         builder.append(" mLoaders=[");
203         if (mLoaders != null) {
204             builder.append(TextUtils.join(",", mLoaders));
205         }
206         builder.append("]}");
207         return builder.toString();
208     }
209 }
210