1 /*
2  * Copyright (C) 2015 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.camera.settings;
18 
19 import com.android.camera.async.Observable;
20 import com.android.camera.async.SafeCloseable;
21 
22 import java.util.concurrent.Executor;
23 
24 import javax.annotation.CheckReturnValue;
25 import javax.annotation.Nonnull;
26 import javax.annotation.concurrent.ThreadSafe;
27 
28 /**
29  * Wraps a {@link SettingsManager} setting with thread-safe interfaces for
30  * observing changes.
31  */
32 @ThreadSafe
33 public final class SettingObserver<T> implements Observable<T> {
34     private class Listener implements SettingsManager.OnSettingChangedListener, SafeCloseable {
35         private final Runnable mRunnable;
36         private final Executor mExecutor;
37 
Listener(Runnable runnable, Executor executor)38         private Listener(Runnable runnable, Executor executor) {
39             mRunnable = runnable;
40             mExecutor = executor;
41         }
42 
43         @Override
onSettingChanged(SettingsManager settingsManager, String key)44         public void onSettingChanged(SettingsManager settingsManager, String key) {
45             mExecutor.execute(mRunnable);
46         }
47 
48         @Override
close()49         public void close() {
50             mSettingsManager.removeListener(this);
51         }
52     }
53 
54     private final SettingsManager mSettingsManager;
55     private final String mScope;
56     private final String mKey;
57     private final Class<T> mTClass;
58 
SettingObserver(SettingsManager manager, String scope, String key, Class<T> tClass)59     private SettingObserver(SettingsManager manager, String scope, String key, Class<T> tClass) {
60         mSettingsManager = manager;
61         mScope = scope;
62         mKey = key;
63         mTClass = tClass;
64     }
65 
ofInteger(SettingsManager manager, String scope, String key)66     public static SettingObserver<Integer> ofInteger(SettingsManager manager,
67             String scope, String key) {
68         return new SettingObserver<>(manager, scope, key,
69                 Integer.class);
70     }
71 
ofString(SettingsManager manager, String scope, String key)72     public static SettingObserver<String> ofString(SettingsManager manager,
73             String scope, String key) {
74         return new SettingObserver<>(manager, scope, key,
75                 String.class);
76     }
77 
ofBoolean(SettingsManager manager, String scope, String key)78     public static SettingObserver<Boolean> ofBoolean(SettingsManager manager,
79             String scope, String key) {
80         return new SettingObserver<>(manager, scope, key,
81                 Boolean.class);
82     }
83 
84     @CheckReturnValue
85     @Nonnull
86     @Override
addCallback(@onnull Runnable callback, @Nonnull Executor executor)87     public SafeCloseable addCallback(@Nonnull Runnable callback, @Nonnull Executor executor) {
88         Listener listener = new Listener(callback, executor);
89         mSettingsManager.addListener(listener);
90         return listener;
91     }
92 
93     @Nonnull
94     @Override
95     @SuppressWarnings("unchecked")
get()96     public T get() {
97         if (mTClass.equals(Integer.class)) {
98             return (T) Integer.valueOf(mSettingsManager.getInteger(mScope, mKey));
99         } else if (mTClass.equals(String.class)) {
100             Object string = mSettingsManager.getString(mScope, mKey);
101             if (string == null) {
102                 return null;
103             } else {
104                 return (T) string;
105             }
106         } else if (mTClass.equals(Boolean.class)) {
107             return (T) Boolean.valueOf(mSettingsManager.getBoolean(mScope, mKey));
108         } else {
109             // Impossible branch
110             throw new IllegalStateException("T must be one of {Integer, Boolean, String}");
111         }
112     }
113 }
114