blob: 4ff7e20da215d305b3f58cf5246fffd560d7de17 [file] [log] [blame]
/*
* Copyright (C) 2015 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 com.android.deskclock.uidata;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Typeface;
import android.support.annotation.DrawableRes;
import android.support.annotation.StringRes;
import com.android.deskclock.AlarmClockFragment;
import com.android.deskclock.ClockFragment;
import com.android.deskclock.R;
import com.android.deskclock.stopwatch.StopwatchFragment;
import com.android.deskclock.timer.TimerFragment;
import java.util.Calendar;
import static com.android.deskclock.Utils.enforceMainLooper;
/**
* All application-wide user interface data is accessible through this singleton.
*/
public final class UiDataModel {
/** Identifies each of the primary tabs within the application. */
public enum Tab {
ALARMS(AlarmClockFragment.class, R.drawable.ic_tab_alarm, R.string.menu_alarm),
CLOCKS(ClockFragment.class, R.drawable.ic_tab_clock, R.string.menu_clock),
TIMERS(TimerFragment.class, R.drawable.ic_tab_timer, R.string.menu_timer),
STOPWATCH(StopwatchFragment.class, R.drawable.ic_tab_stopwatch, R.string.menu_stopwatch);
private final String mFragmentClassName;
private final @DrawableRes int mIconResId;
private final @StringRes int mLabelResId;
Tab(Class fragmentClass, @DrawableRes int iconResId, @StringRes int labelResId) {
mFragmentClassName = fragmentClass.getName();
mIconResId = iconResId;
mLabelResId = labelResId;
}
public String getFragmentClassName() { return mFragmentClassName; }
public @DrawableRes int getIconResId() { return mIconResId; }
public @StringRes int getLabelResId() { return mLabelResId; }
}
/** The single instance of this data model that exists for the life of the application. */
private static final UiDataModel sUiDataModel = new UiDataModel();
public static UiDataModel getUiDataModel() {
return sUiDataModel;
}
private Context mContext;
/** The model from which tab data are fetched. */
private TabModel mTabModel;
/** The model from which formatted strings are fetched. */
private FormattedStringModel mFormattedStringModel;
/** The model from which timed callbacks originate. */
private PeriodicCallbackModel mPeriodicCallbackModel;
private UiDataModel() {}
/**
* The context may be set precisely once during the application life.
*/
public void init(Context context, SharedPreferences prefs) {
if (mContext != context) {
mContext = context.getApplicationContext();
mPeriodicCallbackModel = new PeriodicCallbackModel(mContext);
mFormattedStringModel = new FormattedStringModel(mContext);
mTabModel = new TabModel(prefs);
}
}
/**
* To display the alarm clock in this font, use the character {@link R.string#clock_emoji}.
*
* @return a special font containing a glyph that draws an alarm clock
*/
public Typeface getAlarmIconTypeface() {
return Typeface.createFromAsset(mContext.getAssets(), "fonts/clock.ttf");
}
//
// Formatted Strings
//
/**
* This method is intended to be used when formatting numbers occurs in a hotspot such as the
* update loop of a timer or stopwatch. It returns cached results when possible in order to
* provide speed and limit garbage to be collected by the virtual machine.
*
* @param value a positive integer to format as a String
* @return the {@code value} formatted as a String in the current locale
* @throws IllegalArgumentException if {@code value} is negative
*/
public String getFormattedNumber(int value) {
enforceMainLooper();
return mFormattedStringModel.getFormattedNumber(value);
}
/**
* This method is intended to be used when formatting numbers occurs in a hotspot such as the
* update loop of a timer or stopwatch. It returns cached results when possible in order to
* provide speed and limit garbage to be collected by the virtual machine.
*
* @param value a positive integer to format as a String
* @param length the length of the String; zeroes are padded to match this length
* @return the {@code value} formatted as a String in the current locale and padded to the
* requested {@code length}
* @throws IllegalArgumentException if {@code value} is negative
*/
public String getFormattedNumber(int value, int length) {
enforceMainLooper();
return mFormattedStringModel.getFormattedNumber(value, length);
}
/**
* This method is intended to be used when formatting numbers occurs in a hotspot such as the
* update loop of a timer or stopwatch. It returns cached results when possible in order to
* provide speed and limit garbage to be collected by the virtual machine.
*
* @param negative force a minus sign (-) onto the display, even if {@code value} is {@code 0}
* @param value a positive integer to format as a String
* @param length the length of the String; zeroes are padded to match this length. If
* {@code negative} is {@code true} the return value will contain a minus sign and a total
* length of {@code length + 1}.
* @return the {@code value} formatted as a String in the current locale and padded to the
* requested {@code length}
* @throws IllegalArgumentException if {@code value} is negative
*/
public String getFormattedNumber(boolean negative, int value, int length) {
enforceMainLooper();
return mFormattedStringModel.getFormattedNumber(negative, value, length);
}
/**
* @param calendarDay any of the following values
* <ul>
* <li>{@link Calendar#SUNDAY}</li>
* <li>{@link Calendar#MONDAY}</li>
* <li>{@link Calendar#TUESDAY}</li>
* <li>{@link Calendar#WEDNESDAY}</li>
* <li>{@link Calendar#THURSDAY}</li>
* <li>{@link Calendar#FRIDAY}</li>
* <li>{@link Calendar#SATURDAY}</li>
* </ul>
* @return single-character version of weekday name; e.g.: 'S', 'M', 'T', 'W', 'T', 'F', 'S'
*/
public String getShortWeekday(int calendarDay) {
enforceMainLooper();
return mFormattedStringModel.getShortWeekday(calendarDay);
}
/**
* @param calendarDay any of the following values
* <ul>
* <li>{@link Calendar#SUNDAY}</li>
* <li>{@link Calendar#MONDAY}</li>
* <li>{@link Calendar#TUESDAY}</li>
* <li>{@link Calendar#WEDNESDAY}</li>
* <li>{@link Calendar#THURSDAY}</li>
* <li>{@link Calendar#FRIDAY}</li>
* <li>{@link Calendar#SATURDAY}</li>
* </ul>
* @return full weekday name; e.g.: 'Sunday', 'Monday', 'Tuesday', etc.
*/
public String getLongWeekday(int calendarDay) {
enforceMainLooper();
return mFormattedStringModel.getLongWeekday(calendarDay);
}
//
// Animations
//
/**
* @return the duration in milliseconds of short animations
*/
public long getShortAnimationDuration() {
enforceMainLooper();
return mContext.getResources().getInteger(android.R.integer.config_shortAnimTime);
}
/**
* @return the duration in milliseconds of long animations
*/
public long getLongAnimationDuration() {
enforceMainLooper();
return mContext.getResources().getInteger(android.R.integer.config_longAnimTime);
}
//
// Tabs
//
/**
* @param tabListener to be notified when the selected tab changes
*/
public void addTabListener(TabListener tabListener) {
enforceMainLooper();
mTabModel.addTabListener(tabListener);
}
/**
* @param tabListener to no longer be notified when the selected tab changes
*/
public void removeTabListener(TabListener tabListener) {
enforceMainLooper();
mTabModel.removeTabListener(tabListener);
}
/**
* @return the number of tabs
*/
public int getTabCount() {
enforceMainLooper();
return mTabModel.getTabCount();
}
/**
* @param ordinal the ordinal of the tab
* @return the tab at the given {@code ordinal}
*/
public Tab getTab(int ordinal) {
enforceMainLooper();
return mTabModel.getTab(ordinal);
}
/**
* @param position the position of the tab in the user interface
* @return the tab at the given {@code ordinal}
*/
public Tab getTabAt(int position) {
enforceMainLooper();
return mTabModel.getTabAt(position);
}
/**
* @return an enumerated value indicating the currently selected primary tab
*/
public Tab getSelectedTab() {
enforceMainLooper();
return mTabModel.getSelectedTab();
}
/**
* @param tab an enumerated value indicating the newly selected primary tab
*/
public void setSelectedTab(Tab tab) {
enforceMainLooper();
mTabModel.setSelectedTab(tab);
}
/**
* @param tabScrollListener to be notified when the scroll position of the selected tab changes
*/
public void addTabScrollListener(TabScrollListener tabScrollListener) {
enforceMainLooper();
mTabModel.addTabScrollListener(tabScrollListener);
}
/**
* @param tabScrollListener to be notified when the scroll position of the selected tab changes
*/
public void removeTabScrollListener(TabScrollListener tabScrollListener) {
enforceMainLooper();
mTabModel.removeTabScrollListener(tabScrollListener);
}
/**
* Updates the scrolling state in the {@link UiDataModel} for this tab.
*
* @param tab an enumerated value indicating the tab reporting its vertical scroll position
* @param scrolledToTop {@code true} iff the vertical scroll position of the tab is at the top
*/
public void setTabScrolledToTop(Tab tab, boolean scrolledToTop) {
enforceMainLooper();
mTabModel.setTabScrolledToTop(tab, scrolledToTop);
}
/**
* @return {@code true} iff the content in the selected tab is currently scrolled to the top
*/
public boolean isSelectedTabScrolledToTop() {
enforceMainLooper();
return mTabModel.isTabScrolledToTop(getSelectedTab());
}
//
// Shortcut Ids
//
/**
* @param category which category of shortcut of which to get the id
* @param action the desired action to perform
* @return the id of the shortcut
*/
public String getShortcutId(@StringRes int category, @StringRes int action) {
if (category == R.string.category_stopwatch) {
return mContext.getString(category);
}
return mContext.getString(category) + "_" + mContext.getString(action);
}
//
// Timed Callbacks
//
/**
* @param runnable to be called every minute
* @param offset an offset applied to the minute to control when the callback occurs
*/
public void addMinuteCallback(Runnable runnable, long offset) {
enforceMainLooper();
mPeriodicCallbackModel.addMinuteCallback(runnable, offset);
}
/**
* @param runnable to be called every quarter-hour
* @param offset an offset applied to the quarter-hour to control when the callback occurs
*/
public void addQuarterHourCallback(Runnable runnable, long offset) {
enforceMainLooper();
mPeriodicCallbackModel.addQuarterHourCallback(runnable, offset);
}
/**
* @param runnable to be called every hour
* @param offset an offset applied to the hour to control when the callback occurs
*/
public void addHourCallback(Runnable runnable, long offset) {
enforceMainLooper();
mPeriodicCallbackModel.addHourCallback(runnable, offset);
}
/**
* @param runnable to be called every midnight
* @param offset an offset applied to the midnight to control when the callback occurs
*/
public void addMidnightCallback(Runnable runnable, long offset) {
enforceMainLooper();
mPeriodicCallbackModel.addMidnightCallback(runnable, offset);
}
/**
* @param runnable to no longer be called periodically
*/
public void removePeriodicCallback(Runnable runnable) {
enforceMainLooper();
mPeriodicCallbackModel.removePeriodicCallback(runnable);
}
}