Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser.webapps; | 5 package org.chromium.chrome.browser.webapps; |
| 6 | 6 |
| 7 import android.content.Context; | 7 import android.content.Context; |
| 8 import android.content.SharedPreferences; | 8 import android.content.SharedPreferences; |
| 9 import android.content.pm.PackageManager; | 9 import android.content.pm.PackageManager; |
| 10 import android.content.pm.PackageManager.NameNotFoundException; | 10 import android.content.pm.PackageManager.NameNotFoundException; |
| 11 import android.os.AsyncTask; | 11 import android.os.AsyncTask; |
| 12 | 12 |
| 13 import org.chromium.base.ContextUtils; | |
| 13 import org.chromium.base.ThreadUtils; | 14 import org.chromium.base.ThreadUtils; |
| 14 import org.chromium.base.VisibleForTesting; | 15 import org.chromium.base.VisibleForTesting; |
| 15 import org.chromium.base.annotations.CalledByNative; | 16 import org.chromium.base.annotations.CalledByNative; |
| 16 import org.chromium.chrome.browser.browsing_data.UrlFilter; | 17 import org.chromium.chrome.browser.browsing_data.UrlFilter; |
| 17 import org.chromium.chrome.browser.browsing_data.UrlFilterBridge; | 18 import org.chromium.chrome.browser.browsing_data.UrlFilterBridge; |
| 18 | 19 |
| 19 import java.util.Collections; | 20 import java.util.Collections; |
| 20 import java.util.HashSet; | 21 import java.util.HashSet; |
| 21 import java.util.Set; | 22 import java.util.Set; |
| 22 import java.util.concurrent.TimeUnit; | 23 import java.util.concurrent.TimeUnit; |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 51 | 52 |
| 52 /** | 53 /** |
| 53 * Called when a retrieval of the stored WebappDataStorage occurs. The stora ge parameter will | 54 * Called when a retrieval of the stored WebappDataStorage occurs. The stora ge parameter will |
| 54 * be null if the web app queried for was not in the registry. | 55 * be null if the web app queried for was not in the registry. |
| 55 */ | 56 */ |
| 56 public interface FetchWebappDataStorageCallback { | 57 public interface FetchWebappDataStorageCallback { |
| 57 void onWebappDataStorageRetrieved(WebappDataStorage storage); | 58 void onWebappDataStorageRetrieved(WebappDataStorage storage); |
| 58 } | 59 } |
| 59 | 60 |
| 60 /** | 61 /** |
| 61 * Registers the existence of a web app, creates the SharedPreference for it , and runs the | 62 * Registers the existence of a web app, creates a SharedPreference entry fo r it, and runs the |
| 62 * supplied callback (if not null) on the UI thread with the resulting Webap pDataStorage object. | 63 * supplied callback (if not null) on the UI thread with the resulting Webap pDataStorage object. |
| 63 * @param context Context to open the registry with. | |
| 64 * @param webappId The id of the web app to register. | 64 * @param webappId The id of the web app to register. |
| 65 * @param callback The callback to run with the WebappDataStorage argument. | 65 * @param callback The callback to run with the WebappDataStorage argument. |
| 66 * @return The storage object for the web app. | 66 * @return The storage object for the web app. |
| 67 */ | 67 */ |
| 68 public static void registerWebapp(final Context context, final String webapp Id, | 68 public static void registerWebapp(final String webappId, |
| 69 final FetchWebappDataStorageCallback callback) { | 69 final FetchWebappDataStorageCallback callback) { |
| 70 new AsyncTask<Void, Void, WebappDataStorage>() { | 70 new AsyncTask<Void, Void, WebappDataStorage>() { |
| 71 @Override | 71 @Override |
| 72 protected final WebappDataStorage doInBackground(Void... nothing) { | 72 protected final WebappDataStorage doInBackground(Void... nothing) { |
| 73 Context context = ContextUtils.getApplicationContext(); | |
| 73 SharedPreferences preferences = openSharedPreferences(context); | 74 SharedPreferences preferences = openSharedPreferences(context); |
|
Peter Wen
2016/09/21 14:58:41
Same as above, openSharedPreferences doesn't need
dominickn
2016/09/22 03:47:00
Done.
| |
| 74 // The set returned by getRegisteredWebappIds must be treated as immutable, so we | 75 // The set returned by getRegisteredWebappIds must be treated as immutable, so we |
| 75 // make a copy to edit and save. | 76 // make a copy to edit and save. |
| 76 Set<String> webapps = new HashSet<>(getRegisteredWebappIds(prefe rences)); | 77 Set<String> webapps = new HashSet<>(getRegisteredWebappIds(prefe rences)); |
| 77 boolean added = webapps.add(webappId); | 78 boolean added = webapps.add(webappId); |
| 78 assert added; | 79 assert added; |
| 79 | 80 |
| 80 preferences.edit().putStringSet(KEY_WEBAPP_SET, webapps).apply() ; | 81 preferences.edit().putStringSet(KEY_WEBAPP_SET, webapps).apply() ; |
| 81 | 82 |
| 82 // Create the WebappDataStorage and update the last used time, s o we can guarantee | 83 // Create the WebappDataStorage and update the last used time, s o we can guarantee |
| 83 // that a web app which appears in the registry will have a | 84 // that a web app which appears in the registry will have a |
| 84 // last used time != WebappDataStorage.LAST_USED_INVALID. | 85 // last used time != WebappDataStorage.LAST_USED_INVALID. |
| 85 WebappDataStorage storage = new WebappDataStorage(context, webap pId); | 86 WebappDataStorage storage = new WebappDataStorage(context, webap pId); |
|
Peter Wen
2016/09/21 14:58:41
Since WebappDataStorage doesn't need context, no n
dominickn
2016/09/22 03:47:00
Done.
| |
| 86 storage.updateLastUsedTime(); | 87 storage.updateLastUsedTime(); |
| 87 return storage; | 88 return storage; |
| 88 } | 89 } |
| 89 | 90 |
| 90 @Override | 91 @Override |
| 91 protected final void onPostExecute(WebappDataStorage storage) { | 92 protected final void onPostExecute(WebappDataStorage storage) { |
| 92 if (callback != null) callback.onWebappDataStorageRetrieved(stor age); | 93 if (callback != null) callback.onWebappDataStorageRetrieved(stor age); |
| 93 } | 94 } |
| 94 }.execute(); | 95 }.execute(); |
| 95 } | 96 } |
| 96 | 97 |
| 97 /** | 98 /** |
| 98 * Runs the callback, supplying the WebappDataStorage object for webappId, o r null if the web | 99 * Runs the callback, supplying the WebappDataStorage object for webappId, o r null if the web |
| 99 * app has not been registered. | 100 * app has not been registered. |
| 100 * @param context Context to open the registry with. | |
| 101 * @param webappId The id of the web app to register. | 101 * @param webappId The id of the web app to register. |
| 102 * @return The storage object for the web app, or null if webappId is not re gistered. | 102 * @return The storage object for the web app, or null if webappId is not re gistered. |
| 103 */ | 103 */ |
| 104 public static void getWebappDataStorage(final Context context, final String webappId, | 104 public static void getWebappDataStorage(final String webappId, |
| 105 final FetchWebappDataStorageCallback callback) { | 105 final FetchWebappDataStorageCallback callback) { |
| 106 new AsyncTask<Void, Void, WebappDataStorage>() { | 106 new AsyncTask<Void, Void, WebappDataStorage>() { |
| 107 @Override | 107 @Override |
| 108 protected final WebappDataStorage doInBackground(Void... nothing) { | 108 protected final WebappDataStorage doInBackground(Void... nothing) { |
| 109 Context context = ContextUtils.getApplicationContext(); | |
| 109 SharedPreferences preferences = openSharedPreferences(context); | 110 SharedPreferences preferences = openSharedPreferences(context); |
| 110 if (getRegisteredWebappIds(preferences).contains(webappId)) { | 111 if (getRegisteredWebappIds(preferences).contains(webappId)) { |
| 111 WebappDataStorage storage = WebappDataStorage.open(context, webappId); | 112 WebappDataStorage storage = WebappDataStorage.open(context, webappId); |
| 112 return storage; | 113 return storage; |
| 113 } | 114 } |
| 114 return null; | 115 return null; |
| 115 } | 116 } |
| 116 | 117 |
| 117 @Override | 118 @Override |
| 118 protected final void onPostExecute(WebappDataStorage storage) { | 119 protected final void onPostExecute(WebappDataStorage storage) { |
| 119 assert callback != null; | 120 assert callback != null; |
| 120 callback.onWebappDataStorageRetrieved(storage); | 121 callback.onWebappDataStorageRetrieved(storage); |
| 121 } | 122 } |
| 122 }.execute(); | 123 }.execute(); |
| 123 } | 124 } |
| 124 | 125 |
| 125 /** | 126 /** |
| 126 * Runs the callback, supplying the WebappDataStorage object whose scope mos t closely matches | 127 * Runs the callback, supplying the WebappDataStorage object whose scope mos t closely matches |
| 127 * the provided URL, or null if a matching web app cannot be found. The most closely matching | 128 * the provided URL, or null if a matching web app cannot be found. The most closely matching |
| 128 * scope is the longest scope which has the same prefix as the URL to open. | 129 * scope is the longest scope which has the same prefix as the URL to open. |
| 129 * @param context Context to open the registry with. | |
| 130 * @param url The URL to search for. | 130 * @param url The URL to search for. |
| 131 * @return The storage object for the web app, or null if webappId is not re gistered. | 131 * @return The storage object for the web app, or null if webappId is not re gistered. |
| 132 */ | 132 */ |
| 133 public static void getWebappDataStorageForUrl(final Context context, final S tring url, | 133 public static void getWebappDataStorageForUrl(final String url, |
| 134 final FetchWebappDataStorageCallback callback) { | 134 final FetchWebappDataStorageCallback callback) { |
| 135 new AsyncTask<Void, Void, WebappDataStorage>() { | 135 new AsyncTask<Void, Void, WebappDataStorage>() { |
| 136 @Override | 136 @Override |
| 137 protected final WebappDataStorage doInBackground(Void... nothing) { | 137 protected final WebappDataStorage doInBackground(Void... nothing) { |
| 138 Context context = ContextUtils.getApplicationContext(); | |
| 138 SharedPreferences preferences = openSharedPreferences(context); | 139 SharedPreferences preferences = openSharedPreferences(context); |
| 139 WebappDataStorage bestMatch = null; | 140 WebappDataStorage bestMatch = null; |
| 140 int largestOverlap = 0; | 141 int largestOverlap = 0; |
| 141 for (String id : getRegisteredWebappIds(preferences)) { | 142 for (String id : getRegisteredWebappIds(preferences)) { |
| 142 WebappDataStorage storage = WebappDataStorage.open(context, id); | 143 WebappDataStorage storage = WebappDataStorage.open(context, id); |
| 143 String scope = storage.getScope(); | 144 String scope = storage.getScope(); |
| 144 if (url.startsWith(scope) && scope.length() > largestOverlap ) { | 145 if (url.startsWith(scope) && scope.length() > largestOverlap ) { |
| 145 bestMatch = storage; | 146 bestMatch = storage; |
| 146 largestOverlap = scope.length(); | 147 largestOverlap = scope.length(); |
| 147 } | 148 } |
| 148 } | 149 } |
| 149 return bestMatch; | 150 return bestMatch; |
| 150 } | 151 } |
| 151 | 152 |
| 152 protected final void onPostExecute(WebappDataStorage storage) { | 153 protected final void onPostExecute(WebappDataStorage storage) { |
| 153 assert callback != null; | 154 assert callback != null; |
| 154 callback.onWebappDataStorageRetrieved(storage); | 155 callback.onWebappDataStorageRetrieved(storage); |
| 155 } | 156 } |
| 156 }.execute(); | 157 }.execute(); |
| 157 } | 158 } |
| 158 | 159 |
| 159 /** | 160 /** |
| 160 * Asynchronously retrieves the list of web app IDs which this registry is a ware of. | 161 * Asynchronously retrieves the list of web app IDs which this registry is a ware of. |
| 161 * @param context Context to open the registry with. | |
| 162 * @param callback Called when the set has been retrieved. The set may be em pty. | 162 * @param callback Called when the set has been retrieved. The set may be em pty. |
| 163 */ | 163 */ |
| 164 @VisibleForTesting | 164 @VisibleForTesting |
| 165 public static void getRegisteredWebappIds(final Context context, final Fetch Callback callback) { | 165 public static void getRegisteredWebappIds(final FetchCallback callback) { |
| 166 new AsyncTask<Void, Void, Set<String>>() { | 166 new AsyncTask<Void, Void, Set<String>>() { |
| 167 @Override | 167 @Override |
| 168 protected final Set<String> doInBackground(Void... nothing) { | 168 protected final Set<String> doInBackground(Void... nothing) { |
| 169 return getRegisteredWebappIds(openSharedPreferences(context)); | 169 return getRegisteredWebappIds( |
| 170 openSharedPreferences(ContextUtils.getApplicationContext ())); | |
| 170 } | 171 } |
| 171 | 172 |
| 172 @Override | 173 @Override |
| 173 protected final void onPostExecute(Set<String> result) { | 174 protected final void onPostExecute(Set<String> result) { |
| 174 assert callback != null; | 175 assert callback != null; |
| 175 callback.onWebappIdsRetrieved(result); | 176 callback.onWebappIdsRetrieved(result); |
| 176 } | 177 } |
| 177 }.execute(); | 178 }.execute(); |
| 178 } | 179 } |
| 179 | 180 |
| 180 /** | 181 /** |
| 181 * 1. Deletes the data for all "old" web apps. | 182 * 1. Deletes the data for all "old" web apps. |
| 182 * "Old" web apps have not been opened by the user in the last 3 months, or have had their last | 183 * "Old" web apps have not been opened by the user in the last 3 months, or have had their last |
| 183 * used time set to 0 by the user clearing their history. Cleanup is run, at most, once a month. | 184 * used time set to 0 by the user clearing their history. Cleanup is run, at most, once a month. |
| 184 * 2. Deletes the data for all WebAPKs that have been uninstalled in the las t month. | 185 * 2. Deletes the data for all WebAPKs that have been uninstalled in the las t month. |
| 185 * | 186 * |
| 186 * @param context Context to open the registry with. | |
| 187 * @param currentTime The current time which will be checked to decide if th e task should be run | 187 * @param currentTime The current time which will be checked to decide if th e task should be run |
| 188 * and if a web app should be cleaned up. | 188 * and if a web app should be cleaned up. |
| 189 */ | 189 */ |
| 190 static void unregisterOldWebapps(final Context context, final long currentTi me) { | 190 static void unregisterOldWebapps(final long currentTime) { |
| 191 new AsyncTask<Void, Void, Void>() { | 191 new AsyncTask<Void, Void, Void>() { |
| 192 @Override | 192 @Override |
| 193 protected final Void doInBackground(Void... nothing) { | 193 protected final Void doInBackground(Void... nothing) { |
| 194 Context context = ContextUtils.getApplicationContext(); | |
| 194 SharedPreferences preferences = openSharedPreferences(context); | 195 SharedPreferences preferences = openSharedPreferences(context); |
| 195 long lastCleanup = preferences.getLong(KEY_LAST_CLEANUP, 0); | 196 long lastCleanup = preferences.getLong(KEY_LAST_CLEANUP, 0); |
| 196 if ((currentTime - lastCleanup) < FULL_CLEANUP_DURATION) return null; | 197 if ((currentTime - lastCleanup) < FULL_CLEANUP_DURATION) return null; |
| 197 | 198 |
| 198 Set<String> currentWebapps = getRegisteredWebappIds(preferences) ; | 199 Set<String> currentWebapps = getRegisteredWebappIds(preferences) ; |
| 199 Set<String> retainedWebapps = new HashSet<>(currentWebapps); | 200 Set<String> retainedWebapps = new HashSet<>(currentWebapps); |
| 200 PackageManager pm = context.getPackageManager(); | 201 PackageManager pm = context.getPackageManager(); |
| 201 for (String id : currentWebapps) { | 202 for (String id : currentWebapps) { |
| 202 WebappDataStorage storage = new WebappDataStorage(context, i d); | 203 WebappDataStorage storage = new WebappDataStorage(context, i d); |
| 203 String webApkPackage = storage.getWebApkPackageName(); | 204 String webApkPackage = storage.getWebApkPackageName(); |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 231 return false; | 232 return false; |
| 232 } | 233 } |
| 233 return true; | 234 return true; |
| 234 } | 235 } |
| 235 | 236 |
| 236 /** | 237 /** |
| 237 * Deletes the data of all web apps whose url matches |urlFilter|, as well a s the registry | 238 * Deletes the data of all web apps whose url matches |urlFilter|, as well a s the registry |
| 238 * tracking those web apps. | 239 * tracking those web apps. |
| 239 */ | 240 */ |
| 240 @VisibleForTesting | 241 @VisibleForTesting |
| 241 static void unregisterWebappsForUrls( | 242 static void unregisterWebappsForUrls(final UrlFilter urlFilter, final Runnab le callback) { |
| 242 final Context context, final UrlFilter urlFilter, final Runnable cal lback) { | |
| 243 new AsyncTask<Void, Void, Void>() { | 243 new AsyncTask<Void, Void, Void>() { |
| 244 @Override | 244 @Override |
| 245 protected final Void doInBackground(Void... nothing) { | 245 protected final Void doInBackground(Void... nothing) { |
| 246 Context context = ContextUtils.getApplicationContext(); | |
| 246 SharedPreferences preferences = openSharedPreferences(context); | 247 SharedPreferences preferences = openSharedPreferences(context); |
| 247 Set<String> registeredWebapps = | 248 Set<String> registeredWebapps = |
| 248 new HashSet<>(getRegisteredWebappIds(preferences)); | 249 new HashSet<>(getRegisteredWebappIds(preferences)); |
| 249 Set<String> webappsToUnregister = new HashSet<>(); | 250 Set<String> webappsToUnregister = new HashSet<>(); |
| 250 for (String id : registeredWebapps) { | 251 for (String id : registeredWebapps) { |
| 251 if (urlFilter.matchesUrl(WebappDataStorage.open(context, id) .getUrl())) { | 252 if (urlFilter.matchesUrl(WebappDataStorage.open(context, id) .getUrl())) { |
| 252 WebappDataStorage.deleteDataForWebapp(context, id); | 253 WebappDataStorage.deleteDataForWebapp(context, id); |
| 253 webappsToUnregister.add(id); | 254 webappsToUnregister.add(id); |
| 254 } | 255 } |
| 255 } | 256 } |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 270 @Override | 271 @Override |
| 271 protected final void onPostExecute(Void nothing) { | 272 protected final void onPostExecute(Void nothing) { |
| 272 assert callback != null; | 273 assert callback != null; |
| 273 callback.run(); | 274 callback.run(); |
| 274 } | 275 } |
| 275 }.execute(); | 276 }.execute(); |
| 276 } | 277 } |
| 277 | 278 |
| 278 @CalledByNative | 279 @CalledByNative |
| 279 static void unregisterWebappsForUrls( | 280 static void unregisterWebappsForUrls( |
| 280 Context context, final UrlFilterBridge urlFilter, final long callbac kPointer) { | 281 final UrlFilterBridge urlFilter, final long callbackPointer) { |
| 281 unregisterWebappsForUrls(context, urlFilter, new Runnable() { | 282 unregisterWebappsForUrls(urlFilter, new Runnable() { |
| 282 @Override | 283 @Override |
| 283 public void run() { | 284 public void run() { |
| 284 urlFilter.destroy(); | 285 urlFilter.destroy(); |
| 285 nativeOnWebappsUnregistered(callbackPointer); | 286 nativeOnWebappsUnregistered(callbackPointer); |
| 286 } | 287 } |
| 287 }); | 288 }); |
| 288 } | 289 } |
| 289 | 290 |
| 290 /** | 291 /** |
| 291 * Deletes the URL and scope, and sets the last used time to 0 for all web a pps whose url | 292 * Deletes the URL and scope, and sets the last used time to 0 for all web a pps whose url |
| 292 * matches |urlFilter|. | 293 * matches |urlFilter|. |
| 293 */ | 294 */ |
| 294 @VisibleForTesting | 295 @VisibleForTesting |
| 295 static void clearWebappHistoryForUrls( | 296 static void clearWebappHistoryForUrls(final UrlFilter urlFilter, final Runna ble callback) { |
| 296 final Context context, final UrlFilter urlFilter, final Runnable cal lback) { | |
| 297 new AsyncTask<Void, Void, Void>() { | 297 new AsyncTask<Void, Void, Void>() { |
| 298 @Override | 298 @Override |
| 299 protected final Void doInBackground(Void... nothing) { | 299 protected final Void doInBackground(Void... nothing) { |
| 300 Context context = ContextUtils.getApplicationContext(); | |
| 300 SharedPreferences preferences = openSharedPreferences(context); | 301 SharedPreferences preferences = openSharedPreferences(context); |
| 301 for (String id : getRegisteredWebappIds(preferences)) { | 302 for (String id : getRegisteredWebappIds(preferences)) { |
| 302 if (urlFilter.matchesUrl(WebappDataStorage.open(context, id) .getUrl())) { | 303 if (urlFilter.matchesUrl(WebappDataStorage.open(context, id) .getUrl())) { |
| 303 WebappDataStorage.clearHistory(context, id); | 304 WebappDataStorage.clearHistory(context, id); |
| 304 } | 305 } |
| 305 } | 306 } |
| 306 return null; | 307 return null; |
| 307 } | 308 } |
| 308 | 309 |
| 309 @Override | 310 @Override |
| 310 protected final void onPostExecute(Void nothing) { | 311 protected final void onPostExecute(Void nothing) { |
| 311 assert callback != null; | 312 assert callback != null; |
| 312 callback.run(); | 313 callback.run(); |
| 313 } | 314 } |
| 314 }.execute(); | 315 }.execute(); |
| 315 } | 316 } |
| 316 | 317 |
| 317 @CalledByNative | 318 @CalledByNative |
| 318 static void clearWebappHistoryForUrls( | 319 static void clearWebappHistoryForUrls( |
| 319 Context context, final UrlFilterBridge urlFilter, final long callbac kPointer) { | 320 final UrlFilterBridge urlFilter, final long callbackPointer) { |
| 320 clearWebappHistoryForUrls(context, urlFilter, new Runnable() { | 321 clearWebappHistoryForUrls(urlFilter, new Runnable() { |
| 321 @Override | 322 @Override |
| 322 public void run() { | 323 public void run() { |
| 323 urlFilter.destroy(); | 324 urlFilter.destroy(); |
| 324 nativeOnClearedWebappHistory(callbackPointer); | 325 nativeOnClearedWebappHistory(callbackPointer); |
| 325 } | 326 } |
| 326 }); | 327 }); |
| 327 } | 328 } |
| 328 | 329 |
| 329 private static SharedPreferences openSharedPreferences(Context context) { | 330 private static SharedPreferences openSharedPreferences(Context context) { |
| 330 return context.getSharedPreferences(REGISTRY_FILE_NAME, Context.MODE_PRI VATE); | 331 return context.getSharedPreferences(REGISTRY_FILE_NAME, Context.MODE_PRI VATE); |
| 331 } | 332 } |
| 332 | 333 |
| 333 private static Set<String> getRegisteredWebappIds(SharedPreferences preferen ces) { | 334 private static Set<String> getRegisteredWebappIds(SharedPreferences preferen ces) { |
| 334 // Wrap with unmodifiableSet to ensure it's never modified. See crbug.co m/568369. | 335 // Wrap with unmodifiableSet to ensure it's never modified. See crbug.co m/568369. |
| 335 return Collections.unmodifiableSet( | 336 return Collections.unmodifiableSet( |
| 336 preferences.getStringSet(KEY_WEBAPP_SET, Collections.<String>emp tySet())); | 337 preferences.getStringSet(KEY_WEBAPP_SET, Collections.<String>emp tySet())); |
| 337 } | 338 } |
| 338 | 339 |
| 339 private WebappRegistry() { | 340 private WebappRegistry() { |
| 340 } | 341 } |
| 341 | 342 |
| 342 private static native void nativeOnWebappsUnregistered(long callbackPointer) ; | 343 private static native void nativeOnWebappsUnregistered(long callbackPointer) ; |
| 343 private static native void nativeOnClearedWebappHistory(long callbackPointer ); | 344 private static native void nativeOnClearedWebappHistory(long callbackPointer ); |
| 344 } | 345 } |
| OLD | NEW |