/* * ____.____ __.____ ___ _____ * | | |/ _| | \ / _ \ ______ ______ * | | < | | / / /_\ \\____ \\____ \ * /\__| | | \| | / / | \ |_> > |_> > * \________|____|__ \______/ \____|__ / __/| __/ * \/ \/|__| |__| * * Copyright (c) 2014-2015 Paul "Marunjar" Pretsch * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/> */ package org.voidsink.anewjkuapp.update; import android.accounts.Account; import android.content.ContentProviderClient; import android.content.ContentProviderOperation; import android.content.ContentResolver; import android.content.Context; import android.content.SyncResult; import android.database.Cursor; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.util.Log; import org.voidsink.anewjkuapp.KusssContentContract; import org.voidsink.anewjkuapp.R; import org.voidsink.anewjkuapp.analytics.Analytics; import org.voidsink.anewjkuapp.kusss.Curriculum; import org.voidsink.anewjkuapp.kusss.KusssHandler; import org.voidsink.anewjkuapp.kusss.KusssHelper; import org.voidsink.anewjkuapp.notification.SyncNotification; import org.voidsink.anewjkuapp.utils.AppUtils; import org.voidsink.anewjkuapp.utils.Consts; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; public class ImportCurriculaTask implements Callable<Void> { private static final String TAG = ImportCurriculaTask.class.getSimpleName(); private ContentProviderClient mProvider; private boolean mReleaseProvider = false; private final Account mAccount; private SyncResult mSyncResult; private final Context mContext; private final ContentResolver mResolver; private boolean mShowProgress; private SyncNotification mUpdateNotification; public static final String[] CURRICULA_PROJECTION = new String[]{ KusssContentContract.Curricula.COL_ID, KusssContentContract.Curricula.COL_IS_STD, KusssContentContract.Curricula.COL_CURRICULUM_ID, KusssContentContract.Curricula.COL_TITLE, KusssContentContract.Curricula.COL_STEOP_DONE, KusssContentContract.Curricula.COL_ACTIVE_STATE, KusssContentContract.Curricula.COL_UNI, KusssContentContract.Curricula.COL_DT_START, KusssContentContract.Curricula.COL_DT_END}; public static final int COLUMN_CURRICULUM_ID = 0; public static final int COLUMN_CURRICULUM_IS_STD = 1; public static final int COLUMN_CURRICULUM_CURRICULUM_ID = 2; public static final int COLUMN_CURRICULUM_TITLE = 3; public static final int COLUMN_CURRICULUM_STEOP_DONE = 4; public static final int COLUMN_CURRICULUM_ACTIVE_STATE = 5; public static final int COLUMN_CURRICULUM_UNI = 6; public static final int COLUMN_CURRICULUM_DT_START = 7; public static final int COLUMN_CURRICULUM_DT_END = 8; public ImportCurriculaTask(Account account, Context context) { this(account, null, null, null, null, context); this.mProvider = context.getContentResolver() .acquireContentProviderClient( KusssContentContract.Course.CONTENT_URI); this.mReleaseProvider = true; this.mSyncResult = new SyncResult(); this.mShowProgress = true; } public ImportCurriculaTask(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult, Context context) { this.mAccount = account; this.mProvider = provider; this.mSyncResult = syncResult; this.mResolver = context.getContentResolver(); this.mContext = context; this.mShowProgress = (extras != null && extras.getBoolean(Consts.SYNC_SHOW_PROGRESS, false)); } private void updateNotify(String string) { if (mUpdateNotification != null) { mUpdateNotification.update(string); } } @Override public Void call() throws Exception { if (mProvider == null) { return null; } if (mShowProgress) { mUpdateNotification = new SyncNotification(mContext, R.string.notification_sync_curricula); mUpdateNotification.show(mContext.getString(R.string.notification_sync_curricula_loading)); } try { Log.d(TAG, "setup connection"); updateNotify(mContext.getString(R.string.notification_sync_connect)); if (KusssHandler.getInstance().isAvailable(mContext, AppUtils.getAccountAuthToken(mContext, mAccount), AppUtils.getAccountName(mContext, mAccount), AppUtils.getAccountPassword(mContext, mAccount))) { updateNotify(mContext.getString(R.string.notification_sync_curricula_loading)); Log.d(TAG, "load lvas"); List<Curriculum> curricula = KusssHandler.getInstance().getCurricula(mContext); if (curricula == null) { mSyncResult.stats.numParseExceptions++; } else { Map<String, Curriculum> curriculaMap = new HashMap<>(); for (Curriculum curriculum : curricula) { curriculaMap.put(KusssHelper.getCurriculumKey(curriculum.getCid(), curriculum.getDtStart()), curriculum); } Log.d(TAG, String.format("got %s lvas", curricula.size())); updateNotify(mContext.getString(R.string.notification_sync_curricula_updating)); ArrayList<ContentProviderOperation> batch = new ArrayList<>(); Uri curriculaUri = KusssContentContract.Curricula.CONTENT_URI; Cursor c = mProvider.query(curriculaUri, CURRICULA_PROJECTION, null, null, null); if (c == null) { Log.w(TAG, "selection failed"); } else { Log.d(TAG, "Found " + c.getCount() + " local entries. Computing merge solution..."); int _Id; String curriculumCid; Date curriculumDtStart; while (c.moveToNext()) { _Id = c.getInt(COLUMN_CURRICULUM_ID); curriculumCid = c.getString(COLUMN_CURRICULUM_CURRICULUM_ID); curriculumDtStart = new Date(c.getLong(COLUMN_CURRICULUM_DT_START)); Curriculum curriculum = curriculaMap.remove(KusssHelper.getCurriculumKey(curriculumCid, curriculumDtStart)); if (curriculum != null) { // Check to see if the entry needs to be // updated Uri existingUri = curriculaUri .buildUpon() .appendPath(Integer.toString(_Id)) .build(); Log.d(TAG, "Scheduling update: " + existingUri); batch.add(ContentProviderOperation .newUpdate( KusssContentContract .asEventSyncAdapter( existingUri, mAccount.name, mAccount.type)) .withValue( KusssContentContract.Curricula.COL_ID, Integer.toString(_Id)) .withValues(KusssHelper.getCurriculumContentValues(curriculum)) .build()); mSyncResult.stats.numUpdates++; } else { // delete } } c.close(); for (Curriculum curriculum : curriculaMap.values()) { batch.add(ContentProviderOperation .newInsert( KusssContentContract .asEventSyncAdapter( curriculaUri, mAccount.name, mAccount.type)) .withValues(KusssHelper.getCurriculumContentValues(curriculum)) .build()); Log.d(TAG, "Scheduling insert: " + curriculum.getCid() + " " + curriculum.getDtStart().toString()); mSyncResult.stats.numInserts++; } if (batch.size() > 0) { updateNotify(mContext.getString(R.string.notification_sync_curricula_saving)); Log.d(TAG, "Applying batch update"); mProvider.applyBatch(batch); Log.d(TAG, "Notify resolver"); mResolver .notifyChange( KusssContentContract.Curricula.CONTENT_CHANGED_URI, null, // No // local // observer false); // IMPORTANT: Do not // sync to // network } else { Log.w(TAG, "No batch operations found! Do nothing"); } } } KusssHandler.getInstance().logout(mContext); } else { mSyncResult.stats.numAuthExceptions++; } } catch (Exception e) { Analytics.sendException(mContext, e, true); Log.e(TAG, "import failed", e); } if (mUpdateNotification != null) { mUpdateNotification.cancel(); } if (mReleaseProvider) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { mProvider.close(); } else { mProvider.release(); } } return null; } }