/* * Copyright 2014 Google Inc. All rights reserved. * * 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 com.google.samples.apps.iosched.sync.userdata.util; import android.content.Context; import android.database.Cursor; import android.net.Uri; import com.google.common.base.Charsets; import com.google.gson.Gson; import com.google.samples.apps.iosched.provider.ScheduleContract; import com.google.samples.apps.iosched.sync.userdata.UserAction; import java.util.*; /** * Helper class to handle the format of the User Data that is stored into AppData. * TODO: Refactor. Class mixes util methods, Pojos and business logic. See b/27809362. */ public class UserDataHelper { /** * Returns a JSON string representation of the given UserData object. */ static public String toJsonString(UserData userData) { return new Gson().toJson(userData); } /** * Returns the JSON string representation of the given UserData object as a byte array. */ static public byte[] toByteArray(UserData userData) { return toJsonString(userData).getBytes(Charsets.UTF_8); } /** * Deserializes the UserData given as a JSON string into a {@link UserData} object. * TODO: put this in UserData. */ static public UserData fromString(String str) { if (str == null || str.isEmpty()) { return new UserData(); } return new Gson().fromJson(str, UserData.class); } /** * Creates a UserData object from the given List of user actions. */ static public UserData getUserData(List<UserAction> actions) { UserData userData = new UserData(); if (actions != null) { for (UserAction action : actions) { if (action.type == UserAction.TYPE.ADD_STAR) { if(userData.getStarredSessions() == null) { // TODO: Make this part of setter. Create lazily. userData.setStarredSessions(new HashMap<String, UserData.StarredSession>()); } userData.getStarredSessions().put(action.sessionId, new UserData.StarredSession(true, action.timestamp)); } else if (action.type == UserAction.TYPE.VIEW_VIDEO) { if(userData.getViewedVideoIds() == null) { userData.setViewedVideoIds(new HashSet<String>()); } userData.getViewedVideoIds().add(action.videoId); } else if (action.type == UserAction.TYPE.SUBMIT_FEEDBACK) { if(userData.getFeedbackSubmittedSessionIds() == null) { userData.setFeedbackSubmittedSessionIds(new HashSet<String>()); } userData.getFeedbackSubmittedSessionIds().add(action.sessionId); } else if (action.type == UserAction.TYPE.REMOVE_STAR) { userData.getStarredSessions().put(action.sessionId, new UserData.StarredSession(false, action.timestamp)); } } } return userData; } /** * Reads the data from the {@code column} of the content's {@code queryUri} and returns it as an * Array. */ static private Set<String> getColumnContentAsArray(Context context, Uri queryUri, String column){ Cursor cursor = context.getContentResolver().query(queryUri, new String[]{column}, null, null, null); Set<String> columnValues = new HashSet<>(); try { if (cursor != null && cursor.moveToFirst()) { do { columnValues.add(cursor.getString(0)); } while (cursor.moveToNext()); } } finally { if (cursor != null) { cursor.close(); } } return columnValues; } /** * Reads the data from columns of the content's {@code queryUri} and returns it as a Map. */ static private Map<String, UserData.StarredSession> getColumnContentAsMap(Context context, Uri queryUri, String sessionIdColumn, String inScheduleColumn, String timestampColumn) { Cursor cursor = context.getContentResolver().query(queryUri, new String[]{sessionIdColumn, inScheduleColumn, timestampColumn}, null, null, null); Map<String, UserData.StarredSession> sessionValues = new HashMap<>(); try { if (cursor != null && cursor.moveToFirst()) { do { sessionValues.put(cursor.getString(cursor.getColumnIndex(sessionIdColumn)), new UserData.StarredSession(true, cursor.getLong(cursor.getColumnIndex(timestampColumn)))); } while (cursor.moveToNext()); } } finally { if (cursor != null) { cursor.close(); } } return sessionValues; } /** * Returns the User Data that's on the device's local DB. */ static public UserData getLocalUserData(Context context) { UserData userData = new UserData(); userData.setStarredSessions(getColumnContentAsMap(context, ScheduleContract.MySchedule.CONTENT_URI, ScheduleContract.MySchedule.SESSION_ID, ScheduleContract.MySchedule.MY_SCHEDULE_IN_SCHEDULE, ScheduleContract.MySchedule.MY_SCHEDULE_TIMESTAMP)); // Get Viewed Videos. userData.setViewedVideoIds(getColumnContentAsArray(context, ScheduleContract.MyViewedVideos.CONTENT_URI, ScheduleContract.MyViewedVideos.VIDEO_ID)); // Get Feedback Submitted Sessions. userData.setFeedbackSubmittedSessionIds(getColumnContentAsArray(context, ScheduleContract.MyFeedbackSubmitted.CONTENT_URI, ScheduleContract.MyFeedbackSubmitted.SESSION_ID)); return userData; } /** * Writes the given user data into the device's local DB. */ static public void setLocalUserData(Context context, UserData userData, String accountName) { // TODO: throw if null. Callers should ensure the data is not null. See b/27809502. if (userData == null) { return; } // first clear all stars. context.getContentResolver().delete(ScheduleContract.MySchedule.CONTENT_URI, ScheduleContract.MySchedule.MY_SCHEDULE_ACCOUNT_NAME +" = ?", new String[]{accountName}); // Now add the ones in sessionIds. ArrayList<UserAction> actions = new ArrayList<>(); if (userData.getStarredSessions() != null) { for (Map.Entry<String, UserData.StarredSession> entry : userData.getStarredSessions().entrySet()) { UserAction action = new UserAction(); action.type = entry.getValue().isInSchedule() ? UserAction.TYPE.ADD_STAR: UserAction.TYPE.REMOVE_STAR; action.sessionId = entry.getKey(); action.timestamp = entry.getValue().getTimestamp(); actions.add(action); } } // first clear all viewed videos. context.getContentResolver().delete(ScheduleContract.MyViewedVideos.CONTENT_URI, ScheduleContract.MyViewedVideos.MY_VIEWED_VIDEOS_ACCOUNT_NAME +" = ?", new String[]{accountName}); // Now add the viewed videos. if (userData.getViewedVideoIds() != null) { for (String videoId : userData.getViewedVideoIds()) { UserAction action = new UserAction(); action.type = UserAction.TYPE.VIEW_VIDEO; action.videoId = videoId; actions.add(action); } } // first clear all feedback submitted videos. context.getContentResolver().delete(ScheduleContract.MyFeedbackSubmitted.CONTENT_URI, ScheduleContract.MyFeedbackSubmitted.MY_FEEDBACK_SUBMITTED_ACCOUNT_NAME +" = ?", new String[]{accountName}); // Now add the feedback submitted videos. if (userData.getFeedbackSubmittedSessionIds() != null) { for (String sessionId : userData.getFeedbackSubmittedSessionIds()) { UserAction action = new UserAction(); action.type = UserAction.TYPE.SUBMIT_FEEDBACK; action.sessionId = sessionId; actions.add(action); } } UserActionHelper.updateContentProvider(context, actions, accountName); } }