Widgets refactor

This commit is contained in:
serso 2016-01-06 14:33:13 +01:00
parent 6e63000928
commit 39d50574aa
20 changed files with 273 additions and 729 deletions

View File

@ -139,14 +139,6 @@
</intent-filter>
</activity>
<activity
android:name=".widget.CalculatorWidgetConfigurationActivity"
android:theme="@style/cpp_metro_blue_theme">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<!-- ONSCREEN CONFIG -->
<activity
@ -201,82 +193,6 @@
android:resource="@xml/calculator_widget" />
</receiver>
<receiver
android:name=".widget.CalculatorWidgetProvider"
android:icon="@drawable/ic_launcher"
android:label="@string/c_app_widget_3x3_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="org.solovyev.android.calculator.INIT" />
<action android:name="org.solovyev.android.calculator.EDITOR_STATE_CHANGED" />
<action android:name="org.solovyev.android.calculator.DISPLAY_STATE_CHANGED" />
<action android:name="org.solovyev.android.calculator.BUTTON_PRESSED" />
<action android:name="org.solovyev.android.calculator.THEME_CHANGED" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/calculator_widget_info_3x3" />
</receiver>
<receiver
android:name=".widget.CalculatorWidgetProvider3x4"
android:icon="@drawable/ic_launcher"
android:label="@string/c_app_widget_3x4_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="org.solovyev.android.calculator.INIT" />
<action android:name="org.solovyev.android.calculator.EDITOR_STATE_CHANGED" />
<action android:name="org.solovyev.android.calculator.DISPLAY_STATE_CHANGED" />
<action android:name="org.solovyev.android.calculator.BUTTON_PRESSED" />
<action android:name="org.solovyev.android.calculator.THEME_CHANGED" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/calculator_widget_info_3x4" />
</receiver>
<receiver
android:name=".widget.CalculatorWidgetProvider4x4"
android:icon="@drawable/ic_launcher"
android:label="@string/c_app_widget_4x4_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="org.solovyev.android.calculator.INIT" />
<action android:name="org.solovyev.android.calculator.EDITOR_STATE_CHANGED" />
<action android:name="org.solovyev.android.calculator.DISPLAY_STATE_CHANGED" />
<action android:name="org.solovyev.android.calculator.BUTTON_PRESSED" />
<action android:name="org.solovyev.android.calculator.THEME_CHANGED" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/calculator_widget_info_4x4" />
</receiver>
<receiver
android:name=".widget.CalculatorWidgetProvider4x5"
android:icon="@drawable/ic_launcher"
android:label="@string/c_app_widget_4x5_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="org.solovyev.android.calculator.INIT" />
<action android:name="org.solovyev.android.calculator.EDITOR_STATE_CHANGED" />
<action android:name="org.solovyev.android.calculator.DISPLAY_STATE_CHANGED" />
<action android:name="org.solovyev.android.calculator.BUTTON_PRESSED" />
<action android:name="org.solovyev.android.calculator.THEME_CHANGED" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/calculator_widget_info_4x5" />
</receiver>
<!-- ADMOB -->
<activity

View File

@ -23,29 +23,24 @@
package org.solovyev.android.calculator;
import android.app.Application;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Build;
import android.preference.PreferenceManager;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import org.solovyev.android.Android;
import org.solovyev.android.UiThreadExecutor;
import org.solovyev.android.Views;
import org.solovyev.android.calculator.ga.Ga;
import org.solovyev.android.calculator.language.Languages;
import org.solovyev.android.calculator.onscreen.CalculatorOnscreenService;
import org.solovyev.android.calculator.view.ScreenMetrics;
import org.solovyev.android.calculator.widget.*;
import org.solovyev.android.checkout.*;
import org.solovyev.android.plotter.Plot;
import org.solovyev.android.plotter.Plotter;
import org.solovyev.common.listeners.JEvent;
import org.solovyev.common.listeners.JEventListener;
import org.solovyev.common.listeners.JEventListeners;
@ -54,9 +49,7 @@ import org.solovyev.common.threads.DelayedExecutor;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;
/**
@ -72,8 +65,19 @@ import java.util.concurrent.Executor;
* Before first usage this class must be initialized by calling {@link App#init(android.app.Application)} method (for example, from {@link android.app.Application#onCreate()})
*/
public final class App {
public static final String TAG = "Calculator++";
@Nonnull
private static final List<Class<? extends BaseCalculatorWidgetProvider>> OLD_WIDGETS = Arrays.asList(CalculatorWidgetProvider.class, CalculatorWidgetProvider3x4.class, CalculatorWidgetProvider4x4.class, CalculatorWidgetProvider4x5.class);
public static String subTag(@Nonnull String subTag) {
return sub(TAG, subTag);
}
@NonNull
public static String sub(@Nonnull String tag, @Nonnull String subTag) {
return tag + "/" + subTag;
}
@Nonnull
private static final Products products = Products.create().add(ProductTypes.IN_APP, Arrays.asList("ad_free"));
@Nonnull
@ -145,21 +149,6 @@ public final class App {
App.broadcaster = new CalculatorBroadcaster(application, preferences);
App.vibrator = new Vibrator(application, preferences);
App.screenMetrics = new ScreenMetrics(application);
final List<Class<? extends AppWidgetProvider>> oldNotUsedWidgetClasses = findNotUsedWidgets(application);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
for (Class<? extends AppWidgetProvider> oldNotUsedWidgetClass : oldNotUsedWidgetClasses) {
Android.enableComponent(application, oldNotUsedWidgetClass, false);
}
} else {
// smaller widgets should be still used for smaller screens
if (oldNotUsedWidgetClasses.contains(CalculatorWidgetProvider4x5.class)) {
Android.enableComponent(application, CalculatorWidgetProvider4x5.class, false);
}
if (oldNotUsedWidgetClasses.contains(CalculatorWidgetProvider4x4.class)) {
Android.enableComponent(application, CalculatorWidgetProvider4x4.class, false);
}
}
App.languages.init(App.preferences);
App.initialized = true;
@ -168,21 +157,6 @@ public final class App {
}
}
@Nonnull
private static List<Class<? extends AppWidgetProvider>> findNotUsedWidgets(@Nonnull Application application) {
final List<Class<? extends AppWidgetProvider>> result = new ArrayList<>();
final AppWidgetManager widgetManager = AppWidgetManager.getInstance(application);
for (Class<? extends AppWidgetProvider> widgetClass : OLD_WIDGETS) {
final int ids[] = widgetManager.getAppWidgetIds(new ComponentName(application, widgetClass));
if (ids == null || ids.length == 0) {
result.add(widgetClass);
}
}
return result;
}
private static void checkInit() {
if (!initialized) {
throw new IllegalStateException("App should be initialized!");
@ -319,4 +293,9 @@ public final class App {
// Create and show the dialog.
dialogFragment.show(ft, fragmentTag);
}
@NonNull
public static String toColorString(@ColorInt int color) {
return Integer.toHexString(color).substring(2);
}
}

View File

@ -29,20 +29,16 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import org.solovyev.android.Android;
import jscl.math.Generic;
import org.solovyev.android.Activities;
import org.solovyev.android.calculator.about.CalculatorAboutActivity;
import org.solovyev.android.calculator.function.FunctionEditDialogFragment;
import org.solovyev.android.calculator.history.CalculatorHistoryActivity;
import org.solovyev.android.calculator.math.edit.CalculatorFunctionsActivity;
import org.solovyev.android.calculator.math.edit.CalculatorOperatorsActivity;
import org.solovyev.android.calculator.math.edit.CalculatorVarsActivity;
import org.solovyev.android.calculator.math.edit.CalculatorVarsFragment;
import org.solovyev.android.calculator.math.edit.VarEditDialogFragment;
import org.solovyev.android.calculator.math.edit.*;
import org.solovyev.android.calculator.matrix.CalculatorMatrixActivity;
import org.solovyev.android.calculator.plot.CalculatorPlotActivity;
import org.solovyev.android.calculator.plot.CalculatorPlotter;
@ -51,12 +47,9 @@ import org.solovyev.common.msg.Message;
import org.solovyev.common.msg.MessageType;
import org.solovyev.common.text.Strings;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.math.Generic;
import java.util.List;
/**
* User: serso
@ -74,7 +67,7 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener
public static void showHistory(@Nonnull final Context context, boolean detached) {
final Intent intent = new Intent(context, CalculatorHistoryActivity.class);
Android.addIntentFlags(intent, detached, context);
Activities.addIntentFlags(intent, detached, context);
context.startActivity(intent);
}
@ -84,7 +77,7 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener
public static void showSettings(@Nonnull final Context context, boolean detached) {
final Intent intent = new Intent(context, PreferencesActivity.class);
Android.addIntentFlags(intent, detached, context);
Activities.addIntentFlags(intent, detached, context);
context.startActivity(intent);
}
@ -98,7 +91,7 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener
public static void showFunctions(@Nonnull final Context context, boolean detached) {
final Intent intent = new Intent(context, CalculatorFunctionsActivity.class);
Android.addIntentFlags(intent, detached, context);
Activities.addIntentFlags(intent, detached, context);
context.startActivity(intent);
}
@ -108,7 +101,7 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener
public static void showOperators(@Nonnull final Context context, boolean detached) {
final Intent intent = new Intent(context, CalculatorOperatorsActivity.class);
Android.addIntentFlags(intent, detached, context);
Activities.addIntentFlags(intent, detached, context);
context.startActivity(intent);
}
@ -118,14 +111,14 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener
public static void showVars(@Nonnull final Context context, boolean detached) {
final Intent intent = new Intent(context, CalculatorVarsActivity.class);
Android.addIntentFlags(intent, detached, context);
Activities.addIntentFlags(intent, detached, context);
context.startActivity(intent);
}
public static void plotGraph(@Nonnull final Context context) {
final Intent intent = new Intent();
intent.setClass(context, CalculatorPlotActivity.class);
Android.addIntentFlags(intent, false, context);
Activities.addIntentFlags(intent, false, context);
context.startActivity(intent);
}
@ -136,12 +129,12 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener
final String varValue = viewState.getText();
if (!Strings.isEmpty(varValue)) {
if (CalculatorVarsFragment.isValidValue(varValue)) {
if (context instanceof ActionBarActivity) {
VarEditDialogFragment.showDialog(VarEditDialogFragment.Input.newFromValue(varValue), ((ActionBarActivity) context).getSupportFragmentManager());
if (context instanceof AppCompatActivity) {
VarEditDialogFragment.showDialog(VarEditDialogFragment.Input.newFromValue(varValue), ((AppCompatActivity) context).getSupportFragmentManager());
} else {
final Intent intent = new Intent(context, CalculatorVarsActivity.class);
intent.putExtra(CalculatorVarsFragment.CREATE_VAR_EXTRA_STRING, varValue);
Android.addIntentFlags(intent, false, context);
Activities.addIntentFlags(intent, false, context);
context.startActivity(intent);
}
} else {
@ -208,7 +201,7 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener
public static void likeButtonPressed(@Nonnull final Context context) {
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(context.getString(R.string.cpp_share_link)));
Android.addIntentFlags(intent, false, context);
Activities.addIntentFlags(intent, false, context);
context.startActivity(intent);
}
@ -250,7 +243,7 @@ public final class CalculatorActivityLauncher implements CalculatorEventListener
@Override
public void run() {
final Intent intent = new Intent(context, CalculatorMatrixActivity.class);
Android.addIntentFlags(intent, false, context);
Activities.addIntentFlags(intent, false, context);
context.startActivity(intent);
}
});

View File

@ -33,7 +33,6 @@ import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.RemoteViews;
import jscl.AngleUnit;
import jscl.NumeralBase;
import org.solovyev.android.Views;
@ -48,11 +47,6 @@ import org.solovyev.android.views.dragbutton.SimpleDragListener;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* User: serso
* Date: 9/28/12
* Time: 12:06 AM
*/
public final class CalculatorButtons {
private CalculatorButtons() {
@ -87,10 +81,6 @@ public final class CalculatorButtons {
}
}
public static void initMultiplicationButton(@Nonnull RemoteViews views) {
views.setTextViewText(R.id.cpp_button_multiplication, Locator.getInstance().getEngine().getMultiplicationSign());
}
public static void toggleEqualsButton(@Nullable SharedPreferences preferences,
@Nonnull Activity activity) {
@ -114,14 +104,6 @@ public final class CalculatorButtons {
}
}
/*
**********************************************************************
*
* STATIC CLASSES
*
**********************************************************************
*/
@Nonnull
private static CalculatorKeyboard getKeyboard() {
return Locator.getInstance().getKeyboard();

View File

@ -3,6 +3,7 @@ package org.solovyev.android.calculator;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
import javax.annotation.Nonnull;
@ -22,14 +23,16 @@ public final class CalculatorReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (ACTION_BUTTON_PRESSED.equals(action)) {
final int buttonId = intent.getIntExtra(ACTION_BUTTON_ID_EXTRA, 0);
final CalculatorButton button = CalculatorButton.getById(buttonId);
if (button != null) {
button.onClick();
}
if (!TextUtils.equals(action, ACTION_BUTTON_PRESSED)) {
return;
}
final int buttonId = intent.getIntExtra(ACTION_BUTTON_ID_EXTRA, 0);
final CalculatorButton button = CalculatorButton.getById(buttonId);
if (button == null) {
return;
}
button.onClick();
}
}

View File

@ -26,35 +26,28 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.support.annotation.ColorRes;
import android.support.annotation.LayoutRes;
import android.support.annotation.StyleRes;
import android.util.SparseArray;
import android.view.ContextThemeWrapper;
import jscl.AngleUnit;
import jscl.NumeralBase;
import org.solovyev.android.Check;
import org.solovyev.android.calculator.language.Languages;
import org.solovyev.android.calculator.math.MathType;
import org.solovyev.android.calculator.model.AndroidCalculatorEngine;
import org.solovyev.android.calculator.preferences.PurchaseDialogActivity;
import org.solovyev.android.calculator.wizard.WizardActivity;
import org.solovyev.android.prefs.BooleanPreference;
import org.solovyev.android.prefs.IntegerPreference;
import org.solovyev.android.prefs.LongPreference;
import org.solovyev.android.prefs.NumberToStringPreference;
import org.solovyev.android.prefs.Preference;
import org.solovyev.android.prefs.StringPreference;
import org.solovyev.android.prefs.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.text.DecimalFormatSymbols;
import java.util.EnumMap;
import java.util.Locale;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.AngleUnit;
import jscl.NumeralBase;
import static org.solovyev.android.Android.isPhoneModel;
import static org.solovyev.android.DeviceModel.samsung_galaxy_s;
import static org.solovyev.android.DeviceModel.samsung_galaxy_s_2;
@ -156,7 +149,7 @@ public final class Preferences {
default_theme(0, 0, null),
metro_blue_theme(R.layout.onscreen_layout, R.layout.widget_layout, Gui.Theme.metro_blue_theme),
material_theme(R.layout.onscreen_layout_material, R.layout.widget_layout_material, Gui.Theme.material_theme),
material_light_theme(R.layout.onscreen_layout_material_light, R.layout.widget_layout_material_light, Gui.Theme.material_light_theme);
material_light_theme(R.layout.onscreen_layout_material_light, R.layout.widget_layout_material_light, Gui.Theme.material_light_theme, true);
@LayoutRes
private final int onscreenLayout;
@ -167,13 +160,20 @@ public final class Preferences {
@Nullable
private final Gui.Theme appTheme;
private final boolean light;
@Nonnull
private final Map<Gui.Theme, SimpleTheme> cache = new EnumMap<>(Gui.Theme.class);
SimpleTheme(int onscreenLayout, int widgetLayout, @Nullable Gui.Theme appTheme) {
this(onscreenLayout, widgetLayout, appTheme, false);
}
SimpleTheme(int onscreenLayout, int widgetLayout, @Nullable Gui.Theme appTheme, boolean light) {
this.onscreenLayout = onscreenLayout;
this.widgetLayout = widgetLayout;
this.appTheme = appTheme;
this.light = light;
}
public int getOnscreenLayout(@Nonnull Gui.Theme appTheme) {
@ -220,6 +220,14 @@ public final class Preferences {
public Gui.Theme getAppTheme() {
return appTheme;
}
@ColorRes
public int getDisplayTextColor(boolean error) {
if (error) {
return light ? R.color.cpp_text_inverse_error : R.color.cpp_text_error;
}
return light ? R.color.cpp_text_inverse : R.color.cpp_text;
}
}
public static class Widget {

View File

@ -22,20 +22,15 @@
package org.solovyev.android.calculator.view;
import org.solovyev.android.calculator.AbstractNumberBuilder;
import org.solovyev.android.calculator.CalculatorParseException;
import org.solovyev.android.calculator.LiteNumberBuilder;
import org.solovyev.android.calculator.Locator;
import org.solovyev.android.calculator.NumberBuilder;
import org.solovyev.android.calculator.*;
import org.solovyev.android.calculator.math.MathType;
import org.solovyev.android.calculator.text.TextProcessor;
import org.solovyev.android.calculator.text.TextProcessorEditorResult;
import org.solovyev.common.MutableObject;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Map;
/**
* User: serso
@ -227,6 +222,6 @@ public class TextHighlighter implements TextProcessor<TextProcessorEditorResult,
// int result = Color.rgb(BASE_COLOUR_RED_COMPONENT - offset, BASE_COLOUR_GREEN_COMPONENT - offset, BASE_COLOUR_BLUE_COMPONENT - offset);
int result = (0xFF << 24) | ((red + offset) << 16) | ((green + offset) << 8) | (blue + offset);
return "#" + Integer.toHexString(result).substring(2);
return "#" + App.toColorString(result);
}
}

View File

@ -1,208 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* 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.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.widget;
import android.annotation.TargetApi;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.text.Html;
import android.widget.RemoteViews;
import org.solovyev.android.calculator.App;
import org.solovyev.android.calculator.CalculatorButton;
import org.solovyev.android.calculator.CalculatorButtons;
import org.solovyev.android.calculator.CalculatorDisplayViewState;
import org.solovyev.android.calculator.CalculatorEditorViewState;
import org.solovyev.android.calculator.Locator;
import org.solovyev.android.calculator.Preferences;
import org.solovyev.android.calculator.R;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static android.content.Intent.ACTION_CONFIGURATION_CHANGED;
import static org.solovyev.android.calculator.CalculatorBroadcaster.ACTION_DISPLAY_STATE_CHANGED;
import static org.solovyev.android.calculator.CalculatorBroadcaster.ACTION_EDITOR_STATE_CHANGED;
import static org.solovyev.android.calculator.CalculatorBroadcaster.ACTION_THEME_CHANGED;
import static org.solovyev.android.calculator.CalculatorReceiver.newButtonClickedIntent;
/**
* User: Solovyev_S
* Date: 19.10.12
* Time: 16:18
*/
public abstract class BaseCalculatorWidgetProvider extends AppWidgetProvider {
private static final String TAG = "Calculator++ Widget";
private static final int WIDGET_CATEGORY_KEYGUARD = 2;
private static final String OPTION_APPWIDGET_HOST_CATEGORY = "appWidgetCategory";
private static final String ACTION_APPWIDGET_OPTIONS_CHANGED = "android.appwidget.action.APPWIDGET_UPDATE_OPTIONS";
@Nullable
private String cursorColor;
protected BaseCalculatorWidgetProvider() {
}
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
getCursorColor(context);
}
@Nonnull
private String getCursorColor(@Nonnull Context context) {
if (cursorColor == null) {
cursorColor = Integer.toHexString(context.getResources().getColor(R.color.cpp_widget_cursor)).substring(2);
}
return cursorColor;
}
@Override
public void onUpdate(@Nonnull Context context,
@Nonnull AppWidgetManager appWidgetManager,
@Nonnull int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
updateWidget(context, appWidgetManager, appWidgetIds);
}
public void updateState(@Nonnull Context context) {
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
final int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, getComponentClass()));
updateWidget(context, appWidgetManager, appWidgetIds);
}
@Nonnull
protected Class<? extends BaseCalculatorWidgetProvider> getComponentClass() {
return this.getClass();
}
private void updateWidget(@Nonnull Context context,
@Nonnull AppWidgetManager appWidgetManager,
@Nonnull int[] appWidgetIds) {
final CalculatorEditorViewState editorState = Locator.getInstance().getEditor().getViewState();
final CalculatorDisplayViewState displayState = Locator.getInstance().getDisplay().getViewState();
final Resources resources = context.getResources();
final Preferences.SimpleTheme theme = App.getWidgetTheme().resolveThemeFor(App.getTheme());
for (int appWidgetId : appWidgetIds) {
final RemoteViews views = new RemoteViews(context.getPackageName(), getLayout(appWidgetManager, appWidgetId, resources, theme));
for (CalculatorButton button : CalculatorButton.values()) {
final PendingIntent pendingIntent = PendingIntent.getBroadcast(context, button.getButtonId(), newButtonClickedIntent(context, button), PendingIntent.FLAG_UPDATE_CURRENT);
if (pendingIntent != null) {
views.setOnClickPendingIntent(button.getButtonId(), pendingIntent);
}
}
updateEditorState(context, views, editorState);
updateDisplayState(context, views, displayState, theme);
CalculatorButtons.initMultiplicationButton(views);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
private int getLayout(@Nonnull AppWidgetManager appWidgetManager, int appWidgetId, @Nonnull Resources resources, @Nonnull Preferences.SimpleTheme theme) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
return getLayoutJellyBean(appWidgetManager, appWidgetId, resources, theme);
}
return theme.getWidgetLayout(App.getTheme());
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private int getLayoutJellyBean(@Nonnull AppWidgetManager appWidgetManager, int appWidgetId, Resources resources, @Nonnull Preferences.SimpleTheme theme) {
final Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId);
if (options != null) {
// Get the value of OPTION_APPWIDGET_HOST_CATEGORY
final int category = options.getInt(OPTION_APPWIDGET_HOST_CATEGORY, -1);
if (category != -1) {
// If the value is WIDGET_CATEGORY_KEYGUARD, it's a lockscreen widget
final boolean keyguard = category == WIDGET_CATEGORY_KEYGUARD;
if (keyguard) {
final int minHeightDp = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, -1);
final int minHeight = resources.getDimensionPixelSize(R.dimen.min_expanded_height_lock_screen);
final boolean expanded = (minHeightDp >= minHeight / resources.getDisplayMetrics().density);
if (expanded) {
return R.layout.widget_layout_lockscreen;
} else {
return R.layout.widget_layout_lockscreen_collapsed;
}
}
}
}
return theme.getWidgetLayout(App.getTheme());
}
@Override
public void onReceive(@Nonnull Context context, @Nonnull Intent intent) {
super.onReceive(context, intent);
final String action = intent.getAction();
if (ACTION_CONFIGURATION_CHANGED.equals(action)) {
updateState(context);
} else if (ACTION_EDITOR_STATE_CHANGED.equals(action)) {
updateState(context);
} else if (ACTION_DISPLAY_STATE_CHANGED.equals(action)) {
updateState(context);
} else if (ACTION_APPWIDGET_OPTIONS_CHANGED.equals(action)) {
updateState(context);
} else if (ACTION_THEME_CHANGED.equals(action)) {
updateState(context);
}
}
private void updateDisplayState(@Nonnull Context context, @Nonnull RemoteViews views, @Nonnull CalculatorDisplayViewState displayState, @Nonnull Preferences.SimpleTheme theme) {
final Resources resources = context.getResources();
if (displayState.isValid()) {
views.setTextViewText(R.id.calculator_display, displayState.getText());
views.setTextColor(R.id.calculator_display, resources.getColor(theme == Preferences.SimpleTheme.material_light_theme ? R.color.cpp_text_inverse : R.color.cpp_text));
} else {
views.setTextColor(R.id.calculator_display, resources.getColor(theme == Preferences.SimpleTheme.material_light_theme ? R.color.cpp_text_inverse_error : R.color.cpp_text_error));
}
}
private void updateEditorState(@Nonnull Context context, @Nonnull RemoteViews views, @Nonnull CalculatorEditorViewState editorState) {
final CharSequence text = editorState.getTextAsCharSequence();
CharSequence newText = text;
int selection = editorState.getSelection();
if (selection >= 0 && selection <= text.length()) {
// inject cursor
newText = Html.fromHtml(text.subSequence(0, selection) + "<font color=\"#" + getCursorColor(context) + "\">|</font>" + text.subSequence(selection, text.length()));
}
Locator.getInstance().getNotifier().showDebugMessage(TAG, "New editor state: " + text);
views.setTextViewText(R.id.calculator_editor, newText);
}
}

View File

@ -1,4 +1,203 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* 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.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.widget;
public class CalculatorWidget extends BaseCalculatorWidgetProvider {
import android.annotation.TargetApi;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.content.ContextCompat;
import android.text.Html;
import android.text.TextUtils;
import android.widget.RemoteViews;
import org.solovyev.android.Views;
import org.solovyev.android.calculator.*;
import org.solovyev.android.calculator.Preferences.SimpleTheme;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static android.appwidget.AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT;
import static android.content.Intent.ACTION_CONFIGURATION_CHANGED;
import static android.os.Build.VERSION_CODES.JELLY_BEAN;
import static org.solovyev.android.calculator.CalculatorBroadcaster.*;
import static org.solovyev.android.calculator.CalculatorReceiver.newButtonClickedIntent;
public class CalculatorWidget extends AppWidgetProvider {
private static final String TAG = App.subTag("Widget");
private static final int WIDGET_CATEGORY_KEYGUARD = 2;
private static final String OPTION_APPWIDGET_HOST_CATEGORY = "appWidgetCategory";
private static final String ACTION_APPWIDGET_OPTIONS_CHANGED = "android.appwidget.action.APPWIDGET_UPDATE_OPTIONS";
@Nullable
private String cursorColor;
public CalculatorWidget() {
}
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
initCursorColor(context);
}
@Nonnull
private String getCursorColor(@Nonnull Context context) {
return initCursorColor(context);
}
@Nonnull
private String initCursorColor(@Nonnull Context context) {
if (cursorColor == null) {
cursorColor = App.toColorString(ContextCompat.getColor(context, R.color.cpp_widget_cursor));
}
return cursorColor;
}
@Override
public void onUpdate(@Nonnull Context context,
@Nonnull AppWidgetManager appWidgetManager,
@Nonnull int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
updateWidget(context, appWidgetManager, appWidgetIds);
}
public void updateState(@Nonnull Context context) {
final AppWidgetManager manager = AppWidgetManager.getInstance(context);
final int[] widgetIds = manager.getAppWidgetIds(new ComponentName(context, CalculatorWidget.class));
updateWidget(context, manager, widgetIds);
}
private void updateWidget(@Nonnull Context context,
@Nonnull AppWidgetManager manager,
@Nonnull int[] widgetIds) {
final CalculatorEditorViewState editorState = Locator.getInstance().getEditor().getViewState();
final CalculatorDisplayViewState displayState = Locator.getInstance().getDisplay().getViewState();
final Resources resources = context.getResources();
final SimpleTheme theme = App.getWidgetTheme().resolveThemeFor(App.getTheme());
for (int widgetId : widgetIds) {
final RemoteViews views = new RemoteViews(context.getPackageName(), getLayout(manager, widgetId, resources, theme));
for (CalculatorButton button : CalculatorButton.values()) {
final PendingIntent intent = PendingIntent.getBroadcast(context, button.getButtonId(), newButtonClickedIntent(context, button), PendingIntent.FLAG_UPDATE_CURRENT);
if (intent != null) {
views.setOnClickPendingIntent(button.getButtonId(), intent);
}
}
updateEditorState(context, views, editorState);
updateDisplayState(context, views, displayState, theme);
views.setTextViewText(R.id.cpp_button_multiplication, Locator.getInstance().getEngine().getMultiplicationSign());
manager.updateAppWidget(widgetId, views);
}
}
private int getLayout(@Nonnull AppWidgetManager manager, int widgetId, @Nonnull Resources resources, @Nonnull SimpleTheme theme) {
if (Build.VERSION.SDK_INT >= JELLY_BEAN) {
return getLayoutJellyBean(manager, widgetId, resources, theme);
}
return getDefaultLayout(theme);
}
private int getDefaultLayout(@Nonnull SimpleTheme theme) {
return theme.getWidgetLayout(App.getTheme());
}
@TargetApi(JELLY_BEAN)
private int getLayoutJellyBean(@Nonnull AppWidgetManager manager, int widgetId, Resources resources, @Nonnull SimpleTheme theme) {
final Bundle options = manager.getAppWidgetOptions(widgetId);
if (options == null) {
return getDefaultLayout(theme);
}
final int category = options.getInt(OPTION_APPWIDGET_HOST_CATEGORY, -1);
if (category == -1) {
return getDefaultLayout(theme);
}
final boolean keyguard = category == WIDGET_CATEGORY_KEYGUARD;
if (!keyguard) {
return getDefaultLayout(theme);
}
final int widgetMinHeight = Views.toPixels(resources.getDisplayMetrics(), options.getInt(OPTION_APPWIDGET_MIN_HEIGHT, 0));
final int lockScreenMinHeight = resources.getDimensionPixelSize(R.dimen.min_expanded_height_lock_screen);
final boolean expanded = widgetMinHeight >= lockScreenMinHeight;
if (expanded) {
return R.layout.widget_layout_lockscreen;
} else {
return R.layout.widget_layout_lockscreen_collapsed;
}
}
@Override
public void onReceive(@Nonnull Context context, @Nonnull Intent intent) {
super.onReceive(context, intent);
final String action = intent.getAction();
if (TextUtils.isEmpty(action)) {
return;
}
switch (action) {
case ACTION_CONFIGURATION_CHANGED:
case ACTION_EDITOR_STATE_CHANGED:
case ACTION_DISPLAY_STATE_CHANGED:
case ACTION_APPWIDGET_OPTIONS_CHANGED:
case ACTION_THEME_CHANGED:
updateState(context);
break;
}
}
private void updateDisplayState(@Nonnull Context context, @Nonnull RemoteViews views, @Nonnull CalculatorDisplayViewState displayState, @Nonnull SimpleTheme theme) {
final boolean error = !displayState.isValid();
if (!error) {
views.setTextViewText(R.id.calculator_display, displayState.getText());
}
views.setTextColor(R.id.calculator_display, ContextCompat.getColor(context, theme.getDisplayTextColor(error)));
}
private void updateEditorState(@Nonnull Context context, @Nonnull RemoteViews views, @Nonnull CalculatorEditorViewState editorState) {
final CharSequence text = editorState.getTextAsCharSequence();
CharSequence newText = text;
int selection = editorState.getSelection();
if (selection >= 0 && selection <= text.length()) {
// inject cursor
newText = Html.fromHtml(text.subSequence(0, selection) + "<font color=\"#" + getCursorColor(context) + "\">|</font>" + text.subSequence(selection, text.length()));
}
Locator.getInstance().getNotifier().showDebugMessage(TAG, "New editor state: " + text);
views.setTextViewText(R.id.calculator_editor, newText);
}
}

View File

@ -1,33 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* 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.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.widget;
import android.app.Activity;
/**
* User: Solovyev_S
* Date: 19.10.12
* Time: 16:20
*/
public class CalculatorWidgetConfigurationActivity extends Activity {
}

View File

@ -1,31 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* 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.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.widget;
/**
* User: serso
* Date: 11/18/12
* Time: 1:00 PM
*/
public class CalculatorWidgetProvider extends BaseCalculatorWidgetProvider {
}

View File

@ -1,31 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* 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.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.widget;
/**
* User: serso
* Date: 11/18/12
* Time: 1:01 PM
*/
public class CalculatorWidgetProvider3x4 extends BaseCalculatorWidgetProvider {
}

View File

@ -1,31 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* 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.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.widget;
/**
* User: serso
* Date: 11/18/12
* Time: 1:01 PM
*/
public class CalculatorWidgetProvider4x4 extends BaseCalculatorWidgetProvider {
}

View File

@ -1,31 +0,0 @@
/*
* Copyright 2013 serso aka se.solovyev
*
* 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.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.widget;
/**
* User: serso
* Date: 11/18/12
* Time: 7:43 PM
*/
public class CalculatorWidgetProvider4x5 extends BaseCalculatorWidgetProvider {
}

View File

@ -35,6 +35,8 @@
<item name="cpp_button_period" type="id" />
<item name="cpp_button_round_brackets" type="id" />
<item name="cpp_button_settings" type="id" />
<item name="cpp_button_settings_widget" type="id" />
<item name="cpp_button_settings_onscreen" type="id" />
<item name="cpp_button_like" type="id" />
<item name="cpp_button_left" type="id" />
<item name="cpp_button_right" type="id" />

View File

@ -1,34 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2013 serso aka se.solovyev
~
~ 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.
~
~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Contact details
~
~ Email: se.solovyev@gmail.com
~ Site: http://se.solovyev.org
-->
<appwidget-provider xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
a:initialKeyguardLayout="@layout/widget_layout_lockscreen"
a:initialLayout="@layout/widget_layout"
a:minHeight="180dp"
a:minWidth="180dp"
a:previewImage="@drawable/widget_preview"
a:resizeMode="horizontal|vertical"
a:widgetCategory="home_screen|keyguard"
tools:ignore="UnusedAttribute" />

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2013 serso aka se.solovyev
~
~ 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.
~
~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Contact details
~
~ Email: se.solovyev@gmail.com
~ Site: http://se.solovyev.org
-->
<appwidget-provider xmlns:a="http://schemas.android.com/apk/res/android"
a:initialKeyguardLayout="@layout/widget_layout_lockscreen"
a:initialLayout="@layout/widget_layout"
a:minHeight="180dp"
a:minWidth="180dp"
a:previewImage="@drawable/widget_preview"
a:resizeMode="horizontal|vertical"
a:widgetCategory="home_screen|keyguard" />

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2013 serso aka se.solovyev
~
~ 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.
~
~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Contact details
~
~ Email: se.solovyev@gmail.com
~ Site: http://se.solovyev.org
-->
<appwidget-provider xmlns:a="http://schemas.android.com/apk/res/android"
a:initialKeyguardLayout="@layout/widget_layout_lockscreen"
a:initialLayout="@layout/widget_layout"
a:minHeight="250dp"
a:minWidth="180dp"
a:previewImage="@drawable/widget_preview"
a:resizeMode="horizontal|vertical"
a:widgetCategory="home_screen|keyguard" />

View File

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2013 serso aka se.solovyev
~
~ 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.
~
~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Contact details
~
~ Email: se.solovyev@gmail.com
~ Site: http://se.solovyev.org
-->
<appwidget-provider xmlns:a="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
a:initialKeyguardLayout="@layout/widget_layout_lockscreen"
a:initialLayout="@layout/widget_layout"
a:minHeight="250dp"
a:minResizeHeight="180dp"
a:minResizeWidth="180dp"
a:minWidth="250dp"
a:previewImage="@drawable/widget_preview"
a:resizeMode="horizontal|vertical"
a:widgetCategory="home_screen|keyguard"
tools:ignore="UnusedAttribute" />

View File

@ -1,34 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2013 serso aka se.solovyev
~
~ 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.
~
~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~ Contact details
~
~ Email: se.solovyev@gmail.com
~ Site: http://se.solovyev.org
-->
<appwidget-provider xmlns:a="http://schemas.android.com/apk/res/android"
a:initialKeyguardLayout="@layout/widget_layout_lockscreen"
a:initialLayout="@layout/widget_layout"
a:minHeight="320dp"
a:minResizeHeight="180dp"
a:minResizeWidth="180dp"
a:minWidth="250dp"
a:previewImage="@drawable/widget_preview"
a:resizeMode="horizontal|vertical"
a:widgetCategory="home_screen|keyguard" />