summaryrefslogtreecommitdiffstats
path: root/mobile/android/services/src/main/java/org/mozilla/gecko/background/preferences/PreferenceManagerCompat.java
blob: 22c62e43185189f86ed8d8f1d99e14bd879f1083 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.mozilla.gecko.background.preferences;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.preference.Preference;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.util.Log;

public class PreferenceManagerCompat {

  private static final String TAG = PreferenceManagerCompat.class.getSimpleName();

  /**
   * Interface definition for a callback to be invoked when a {@link Preference} in the hierarchy
   * rooted at this {@link PreferenceScreen} is clicked.
   */
  interface OnPreferenceTreeClickListener {
    /**
     * Called when a preference in the tree rooted at this {@link PreferenceScreen} has been
     * clicked.
     *
     * @param preferenceScreen The {@link PreferenceScreen} that the preference is located in.
     * @param preference       The preference that was clicked.
     *
     * @return Whether the click was handled.
     */
    boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference);
  }

  static PreferenceManager newInstance(Activity activity, int firstRequestCode) {
    try {
      Constructor<PreferenceManager> c = PreferenceManager.class.getDeclaredConstructor(Activity.class, int.class);
      c.setAccessible(true);
      return c.newInstance(activity, firstRequestCode);
    } catch (Exception e) {
      Log.w(TAG, "Couldn't call constructor PreferenceManager by reflection", e);
    }
    return null;
  }

  /**
   * Sets the owning preference fragment
   */
  static void setFragment(PreferenceManager manager, PreferenceFragment fragment) {
    // stub
  }

  /**
   * Sets the callback to be invoked when a {@link Preference} in the hierarchy rooted at this
   * {@link PreferenceManager} is clicked.
   *
   * @param listener The callback to be invoked.
   */
  static void setOnPreferenceTreeClickListener(PreferenceManager manager, final OnPreferenceTreeClickListener listener) {
    try {
      Field onPreferenceTreeClickListener = PreferenceManager.class.getDeclaredField("mOnPreferenceTreeClickListener");
      onPreferenceTreeClickListener.setAccessible(true);
      if (listener != null) {
        Object proxy = Proxy.newProxyInstance(
          onPreferenceTreeClickListener.getType().getClassLoader(),
          new Class<?>[] { onPreferenceTreeClickListener.getType() },
          new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) {
              if (method.getName().equals("onPreferenceTreeClick")) {
                return listener.onPreferenceTreeClick((PreferenceScreen) args[0], (Preference) args[1]);
              } else {
                return null;
              }
            }
          });
        onPreferenceTreeClickListener.set(manager, proxy);
      } else {
        onPreferenceTreeClickListener.set(manager, null);
      }
    } catch (Exception e) {
      Log.w(TAG, "Couldn't set PreferenceManager.mOnPreferenceTreeClickListener by reflection", e);
    }
  }

  /**
   * Inflates a preference hierarchy from the preference hierarchies of {@link Activity Activities}
   * that match the given {@link Intent}. An {@link Activity} defines its preference hierarchy with
   * meta-data using the {@link #METADATA_KEY_PREFERENCES} key.
   * <p/>
   * If a preference hierarchy is given, the new preference hierarchies will be merged in.
   *
   * @param queryIntent     The intent to match activities.
   * @param rootPreferences Optional existing hierarchy to merge the new hierarchies into.
   *
   * @return The root hierarchy (if one was not provided, the new hierarchy's root).
   */
  static PreferenceScreen inflateFromIntent(PreferenceManager manager, Intent intent, PreferenceScreen screen) {
    try {
      Method m = PreferenceManager.class.getDeclaredMethod("inflateFromIntent", Intent.class, PreferenceScreen.class);
      m.setAccessible(true);
      PreferenceScreen prefScreen = (PreferenceScreen) m.invoke(manager, intent, screen);
      return prefScreen;
    } catch (Exception e) {
      Log.w(TAG, "Couldn't call PreferenceManager.inflateFromIntent by reflection", e);
    }
    return null;
  }

  /**
   * Inflates a preference hierarchy from XML. If a preference hierarchy is given, the new
   * preference hierarchies will be merged in.
   *
   * @param context         The context of the resource.
   * @param resId           The resource ID of the XML to inflate.
   * @param rootPreferences Optional existing hierarchy to merge the new hierarchies into.
   *
   * @return The root hierarchy (if one was not provided, the new hierarchy's root).
   *
   * @hide
   */
  static PreferenceScreen inflateFromResource(PreferenceManager manager, Activity activity, int resId, PreferenceScreen screen) {
    try {
      Method m = PreferenceManager.class.getDeclaredMethod("inflateFromResource", Context.class, int.class, PreferenceScreen.class);
      m.setAccessible(true);
      PreferenceScreen prefScreen = (PreferenceScreen) m.invoke(manager, activity, resId, screen);
      return prefScreen;
    } catch (Exception e) {
      Log.w(TAG, "Couldn't call PreferenceManager.inflateFromResource by reflection", e);
    }
    return null;
  }

  /**
   * Returns the root of the preference hierarchy managed by this class.
   *
   * @return The {@link PreferenceScreen} object that is at the root of the hierarchy.
   */
  static PreferenceScreen getPreferenceScreen(PreferenceManager manager) {
    try {
      Method m = PreferenceManager.class.getDeclaredMethod("getPreferenceScreen");
      m.setAccessible(true);
      return (PreferenceScreen) m.invoke(manager);
    } catch (Exception e) {
      Log.w(TAG, "Couldn't call PreferenceManager.getPreferenceScreen by reflection", e);
    }
    return null;
  }

  /**
   * Called by the {@link PreferenceManager} to dispatch a subactivity result.
   */
  static void dispatchActivityResult(PreferenceManager manager, int requestCode, int resultCode, Intent data) {
    try {
      Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityResult", int.class, int.class, Intent.class);
      m.setAccessible(true);
      m.invoke(manager, requestCode, resultCode, data);
    } catch (Exception e) {
      Log.w(TAG, "Couldn't call PreferenceManager.dispatchActivityResult by reflection", e);
    }
  }

  /**
   * Called by the {@link PreferenceManager} to dispatch the activity stop event.
   */
  static void dispatchActivityStop(PreferenceManager manager) {
    try {
      Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityStop");
      m.setAccessible(true);
      m.invoke(manager);
    } catch (Exception e) {
      Log.w(TAG, "Couldn't call PreferenceManager.dispatchActivityStop by reflection", e);
    }
  }

  /**
   * Called by the {@link PreferenceManager} to dispatch the activity destroy event.
   */
  static void dispatchActivityDestroy(PreferenceManager manager) {
    try {
      Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityDestroy");
      m.setAccessible(true);
      m.invoke(manager);
    } catch (Exception e) {
      Log.w(TAG, "Couldn't call PreferenceManager.dispatchActivityDestroy by reflection", e);
    }
  }

  /**
   * Sets the root of the preference hierarchy.
   *
   * @param preferenceScreen The root {@link PreferenceScreen} of the preference hierarchy.
   *
   * @return Whether the {@link PreferenceScreen} given is different than the previous.
   */
  static boolean setPreferences(PreferenceManager manager, PreferenceScreen screen) {
    try {
      Method m = PreferenceManager.class.getDeclaredMethod("setPreferences", PreferenceScreen.class);
      m.setAccessible(true);
      return ((Boolean) m.invoke(manager, screen));
    } catch (Exception e) {
      Log.w(TAG, "Couldn't call PreferenceManager.setPreferences by reflection", e);
    }
    return false;
  }

}