/*
* Copyright (C) 2014 Jason M. Heim
*
* 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.jasonmheim.rollout.action;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.SharedPreferences;
import android.location.Location;
import android.os.RemoteException;
import android.util.Log;
import com.google.common.base.Objects;
import com.jasonmheim.rollout.Constants;
import com.jasonmheim.rollout.settings.Settings;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* Manages the current action that the user is doing.
*/
@Singleton
public class ActionManager {
static final String ACTION_KEY = "ActionManagerKey";
static final String DESTINATION_KEY = "ActionManagerDestinationKey";
private final ContentResolver contentResolver;
private final Settings preferences;
private final SharedPreferences sharedPreferences;
@Inject
ActionManager(
ContentResolver contentResolver,
Settings preferences,
SharedPreferences sharedPreferences) {
this.contentResolver = contentResolver;
this.preferences = preferences;
this.sharedPreferences = sharedPreferences;
}
/**
* Equivalent to {@link #setAction(int, String)} with a null {@code destinationName}.
*/
public void setAction(int action) {
this.setAction(action, null);
}
/**
* Sets the current {@code action} such as {@link Constants#ACTION_IDLE} as well as an optional
* {@code destinationName} such as {@link Constants#DESTINATION_NAME_HOME}. Note that setting the
* destination name only has an effect if the action is {@link Constants#ACTION_RIDE}; otherwise
* it is ignored.
* <p>
* Setting the action may have a number of side effects. The priority of notifications may change,
* as well as their content depending on what the user is doing. The frequency that station data
* and current location will be updated may also change.
*/
public void setAction(int action, String destinationName) {
int oldAction = sharedPreferences.getInt(ACTION_KEY, -1);
String oldDestinationName = sharedPreferences.getString(DESTINATION_KEY, null);
if (oldAction != action || !Objects.equal(oldDestinationName, destinationName)) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putInt(ACTION_KEY, action);
if (destinationName == null) {
editor.remove(DESTINATION_KEY);
} else {
editor.putString(DESTINATION_KEY, destinationName);
}
editor.apply();
onActionChanged();
}
}
public int getAction() {
return sharedPreferences.getInt(ACTION_KEY, Constants.ACTION_IDLE);
}
public String getDestinationName() {
return sharedPreferences.getString(DESTINATION_KEY, null);
}
/**
* If there is a current destination, this attempts to ascertain its {@link Location}. If the
* destination is not set, or the location cold not be computed, this returns {@code null}.
*/
public Location getDestination() {
String destinationName = getDestinationName();
if (destinationName == null) {
return null;
} else if (destinationName.equals(Constants.DESTINATION_NAME_HOME)) {
return preferences.getHomeDestination();
} else if (destinationName.equals(Constants.DESTINATION_NAME_WORK)) {
return preferences.getWorkDestination();
}
return null;
}
/**
* Returns a human readable description of the current action, which may also include destination
* information.
*/
public String getActionDisplayName() {
// TODO: Extract string resources with formatting and such. Will need getString() dependency
switch (getAction()) {
case Constants.ACTION_SEARCH:
return "Searching for a bike";
case Constants.ACTION_SILENCE:
return "Silenced";
case Constants.ACTION_IDLE:
return "Idle";
case Constants.ACTION_RIDE:
if (sharedPreferences.contains(DESTINATION_KEY)) {
return "Riding to " + sharedPreferences.getString(DESTINATION_KEY, "Unknown");
}
return "Roaming on a bike";
}
return "Current action unknown";
}
/**
* This method should only be invoked at application startup; it ensures that the core content
* provider is bootstrapped with the current action and that station data sync is activated.
*/
public void initialize() {
ContentResolver.setSyncAutomatically(Constants.ACCOUNT, Constants.AUTHORITY, true);
ContentResolver.setIsSyncable(Constants.ACCOUNT, Constants.AUTHORITY, 1);
// TODO: remember why I thought this was necessary and document it :-P
onActionChanged();
}
private void onActionChanged() {
// TODO: Switch this to use the ACTION_URI; drop the content values.
ContentValues contentValues = new ContentValues();
contentValues.put(Constants.UPDATE_KEY_ACTION, true);
ContentProviderClient contentProviderClient =
contentResolver.acquireContentProviderClient(Constants.STATION_URI);
try {
contentProviderClient.update(Constants.STATION_URI, contentValues, null, null);
} catch (RemoteException ex) {
Log.e("Rollout", "Failed to update after new action");
} finally {
contentProviderClient.release();
}
}
}