Java tutorial
/* * Copyright (C) 2010 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 info.dc585.hpt.sa; import android.accounts.Account; import android.accounts.AccountManager; import android.content.*; import android.database.Cursor; import android.os.Bundle; import android.os.RemoteException; import android.text.TextUtils; import android.util.Log; import info.dc585.hpt.NetworkUtilities; import info.dc585.hpt.cp.HackerPointsContentProvider; import info.dc585.hpt.cp.TopHackerTable; import java.io.IOException; import java.util.ArrayList; import org.apache.http.ParseException; import org.apache.http.auth.AuthenticationException; import org.json.*; /** * SyncAdapter implementation for syncing sample SyncAdapter contacts to the platform ContactOperations provider. This sample shows a basic 2-way sync between the client and a sample server. It also * contains an example of how to update the contacts' status messages, which would be useful for a messaging or social networking client. */ public class SyncAdapter extends AbstractThreadedSyncAdapter { private static final String TAG = "HPT:SyncAdapter"; // private static final String SYNC_MARKER_KEY = "info.dc585.hpt.sa.marker"; private static final boolean NOTIFY_AUTH_FAILURE = true; private final AccountManager accountManager; private final Context mContext; public SyncAdapter(Context context, boolean autoInitialize) { super(context, autoInitialize); mContext = context; accountManager = AccountManager.get(context); } @Override public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { syncTopHackers(provider, syncResult); syncMe(provider, syncResult); syncFriends(provider, syncResult); } private void syncMe(ContentProviderClient provider, SyncResult syncResult) { } private void syncFriends(ContentProviderClient provider, SyncResult syncResult) { } private void syncTopHackers(ContentProviderClient provider, SyncResult syncResult) { try { Log.d(TAG, "Calling something to sync up hackerpoint db"); JSONArray hackers = NetworkUtilities.getTopHackers(); if (hackers == null) { Log.e(TAG, "somehow got null hackers, explode please"); syncResult.stats.numParseExceptions++; } if (hackers.length() == 0) { return; } Log.i(TAG, "Updateing content provider"); Log.i(TAG, "hackers.length():" + hackers.length()); for (int i = 0; i < hackers.length(); i++) { JSONObject jo = hackers.getJSONObject(i); String name = jo.getString("name"); String selection = TopHackerTable.COLUMN_NAME + " like ?"; String[] selectionArgs = { name }; String[] projection = { TopHackerTable.COLUMN_ID, TopHackerTable.COLUMN_NAME }; ContentValues values = new ContentValues(); // FIXME: Dear self, WTF would i trust network returned data without verifying limits ;) // TODO: See FIXME above. Cursor c = provider.query(HackerPointsContentProvider.HACKERS_URI, projection, selection, selectionArgs, null); if (c.getCount() == 0) { Log.d(TAG, "performing insert for new name:" + name); int points = jo.getInt("points"); values.put(TopHackerTable.COLUMN_POINTS, points); int pool = jo.getInt("pool"); values.put(TopHackerTable.COLUMN_POOL, pool); int internets = jo.getInt("internets"); values.put(TopHackerTable.COLUMN_INTERNETS, internets); String pictureURL = jo.getString("pictureURL"); values.put(TopHackerTable.COLUMN_PICTUREURL, pictureURL); values.put(TopHackerTable.COLUMN_NAME, name); values.put(TopHackerTable.COLUMN_UPDATE, System.currentTimeMillis()); provider.insert(HackerPointsContentProvider.HACKERS_URI, values); syncResult.stats.numInserts++; } else if (c.getCount() == 1) { Log.d(TAG, "performing update for name:" + name); if (name == null || name.isEmpty()) { Log.e(TAG, "null or empty name"); continue; } int points = jo.getInt("points"); values.put(TopHackerTable.COLUMN_POINTS, points); int pool = jo.getInt("pool"); values.put(TopHackerTable.COLUMN_POOL, pool); int internets = jo.getInt("internets"); values.put(TopHackerTable.COLUMN_INTERNETS, internets); String pictureURL = jo.getString("pictureURL"); values.put(TopHackerTable.COLUMN_PICTUREURL, pictureURL); int rows = provider.update(HackerPointsContentProvider.HACKERS_URI, values, selection, selectionArgs); Log.d(TAG, "Updated:" + rows + ": rows"); syncResult.stats.numUpdates += rows; } else { Log.e(TAG, "Cursor count was not 0 or 1 was:" + c.getCount()); continue; } } // Now run through both lists and figure out which one to delete. String[] projection = { TopHackerTable.COLUMN_NAME }; Cursor c = provider.query(HackerPointsContentProvider.HACKERS_URI, projection, null, null, null); if (c.getCount() == 0) { return; } ArrayList<String> goodNames = new ArrayList<String>(); ArrayList<String> rmNames = new ArrayList<String>(); for (int i = 0; i < hackers.length(); i++) { JSONObject jo = hackers.getJSONObject(i); String name = jo.getString("name"); goodNames.add(name); } while (c.moveToNext()) { int namec = c.getColumnIndex(TopHackerTable.COLUMN_NAME); String dbName = c.getString(namec); if (goodNames.contains(dbName) == false) { Log.d(TAG, "Adding name:" + dbName + ": to the delete list"); rmNames.add(dbName); } } for (String nextName : rmNames) { Log.d(TAG, "deleting name:" + nextName + ":"); // FIXME: use column name from Table class String where = " name = ? "; String[] whereArgs = { nextName }; int rows = provider.delete(HackerPointsContentProvider.HACKERS_URI, where, whereArgs); syncResult.stats.numDeletes += rows; } } catch (final AuthenticationException e) { Log.e(TAG, "AuthenticationException", e); } catch (final JSONException e) { Log.e(TAG, "JSONException", e); } catch (final IOException e) { Log.e(TAG, "IOException", e); } catch (final ParseException e) { Log.e(TAG, "ParseException", e); syncResult.stats.numParseExceptions++; } catch (final RemoteException e) { Log.e(TAG, "RemoteException", e); } } /** * This helper function fetches the last known high-water-mark we received from the server - or 0 if we've never synced. * * @param account the account we're syncing * @return the change high-water-mark */ private long getServerSyncMarker(Account account) { String markerString = accountManager.getUserData(account, SYNC_MARKER_KEY); if (!TextUtils.isEmpty(markerString)) { return Long.parseLong(markerString); } return 0; } /** * Save off the high-water-mark we receive back from the server. * * @param account The account we're syncing * @param marker The high-water-mark we want to save. */ private void setServerSyncMarker(Account account, long marker) { accountManager.setUserData(account, SYNC_MARKER_KEY, Long.toString(marker)); } }