Calculator overlay added
This commit is contained in:
parent
f772e254cc
commit
d59f7b8b50
@ -6,6 +6,9 @@
|
|||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
<uses-permission android:name="com.android.vending.BILLING"/>
|
<uses-permission android:name="com.android.vending.BILLING"/>
|
||||||
|
|
||||||
|
<!-- for overlay -->
|
||||||
|
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||||
|
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="8"/>
|
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="8"/>
|
||||||
|
|
||||||
@ -48,6 +51,22 @@
|
|||||||
<!-- settings must use action bar icon-->
|
<!-- settings must use action bar icon-->
|
||||||
<activity android:icon="@drawable/ab_icon" android:label="@string/c_settings" android:name=".plot.CalculatorPlotPreferenceActivity"/>
|
<activity android:icon="@drawable/ab_icon" android:label="@string/c_settings" android:name=".plot.CalculatorPlotPreferenceActivity"/>
|
||||||
|
|
||||||
|
<!-- OVERLAY CONFIG -->
|
||||||
|
|
||||||
|
<service android:name=".overlay.CalculatorOverlayService">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="org.solovyev.calculator.widget.EDITOR_STATE_CHANGED"/>
|
||||||
|
<action android:name="org.solovyev.calculator.widget.DISPLAY_STATE_CHANGED"/>
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<receiver android:name=".overlay.CalculatorOverlayBroadcastReceiver">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="org.solovyev.calculator.widget.EDITOR_STATE_CHANGED"/>
|
||||||
|
<action android:name="org.solovyev.calculator.widget.DISPLAY_STATE_CHANGED"/>
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
<!-- WIDGET CONFIG -->
|
<!-- WIDGET CONFIG -->
|
||||||
|
|
||||||
<receiver android:icon="@drawable/icon" android:label="@string/c_app_widget_3x3_name" android:name=".widget.CalculatorWidgetProvider">
|
<receiver android:icon="@drawable/icon" android:label="@string/c_app_widget_3x3_name" android:name=".widget.CalculatorWidgetProvider">
|
||||||
|
34
calculatorpp/res/layout/overlay_layout.xml
Normal file
34
calculatorpp/res/layout/overlay_layout.xml
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
|
||||||
|
a:orientation="vertical"
|
||||||
|
style="@style/cpp_widget_main_layout_style">
|
||||||
|
|
||||||
|
<include layout="@layout/widget_editor"
|
||||||
|
a:layout_weight="2"
|
||||||
|
a:layout_width="match_parent"
|
||||||
|
a:layout_height="0dp"/>
|
||||||
|
|
||||||
|
<LinearLayout a:layout_weight="1"
|
||||||
|
a:layout_width="match_parent"
|
||||||
|
a:layout_height="0dp">
|
||||||
|
|
||||||
|
<include layout="@layout/widget_equals_button"
|
||||||
|
a:layout_margin="@dimen/cpp_button_margin"
|
||||||
|
a:layout_weight="1"
|
||||||
|
a:layout_width="0dp"
|
||||||
|
a:layout_height="match_parent"/>
|
||||||
|
|
||||||
|
<include layout="@layout/widget_display"
|
||||||
|
a:layout_weight="5"
|
||||||
|
a:layout_width="0dp"
|
||||||
|
a:layout_height="wrap_content"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<include layout="@layout/widget_keyboard"
|
||||||
|
a:layout_weight="5"
|
||||||
|
a:layout_width="match_parent"
|
||||||
|
a:layout_height="0dp"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -86,6 +86,11 @@
|
|||||||
<item name="android:layout_width">match_parent</item>
|
<item name="android:layout_width">match_parent</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="cpp_overlay_main_layout_style" parent="cpp_default_main_layout_style">
|
||||||
|
<item name="android:layout_height">400dp</item>
|
||||||
|
<item name="android:layout_width">250dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="cpp_widget_main_layout_style" parent="cpp_default_main_layout_style">
|
<style name="cpp_widget_main_layout_style" parent="cpp_default_main_layout_style">
|
||||||
<item name="android:padding">1dp</item>
|
<item name="android:padding">1dp</item>
|
||||||
<item name="android:layout_margin">@dimen/cpp_widget_margin</item>
|
<item name="android:layout_margin">@dimen/cpp_widget_margin</item>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package org.solovyev.android.calculator;
|
package org.solovyev.android.calculator;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import net.robotmedia.billing.BillingController;
|
import net.robotmedia.billing.BillingController;
|
||||||
@ -12,6 +13,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.solovyev.android.ads.AdsController;
|
import org.solovyev.android.ads.AdsController;
|
||||||
import org.solovyev.android.calculator.history.AndroidCalculatorHistory;
|
import org.solovyev.android.calculator.history.AndroidCalculatorHistory;
|
||||||
import org.solovyev.android.calculator.model.AndroidCalculatorEngine;
|
import org.solovyev.android.calculator.model.AndroidCalculatorEngine;
|
||||||
|
import org.solovyev.android.calculator.overlay.CalculatorOverlayService;
|
||||||
import org.solovyev.android.calculator.widget.CalculatorWidgetHelper;
|
import org.solovyev.android.calculator.widget.CalculatorWidgetHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -100,6 +102,8 @@ public class CalculatorApplication extends android.app.Application {
|
|||||||
widgetHelper = new CalculatorWidgetHelper();
|
widgetHelper = new CalculatorWidgetHelper();
|
||||||
CalculatorLocatorImpl.getInstance().getCalculator().addCalculatorEventListener(widgetHelper);
|
CalculatorLocatorImpl.getInstance().getCalculator().addCalculatorEventListener(widgetHelper);
|
||||||
|
|
||||||
|
BillingDB.init(CalculatorApplication.this);
|
||||||
|
|
||||||
AdsController.getInstance().init(ADMOB_USER_ID, AD_FREE_PRODUCT_ID, new BillingController.IConfiguration() {
|
AdsController.getInstance().init(ADMOB_USER_ID, AD_FREE_PRODUCT_ID, new BillingController.IConfiguration() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -119,9 +123,10 @@ public class CalculatorApplication extends android.app.Application {
|
|||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
BillingDB.init(CalculatorApplication.this);
|
|
||||||
BillingController.checkBillingSupported(CalculatorApplication.this);
|
BillingController.checkBillingSupported(CalculatorApplication.this);
|
||||||
AdsController.getInstance().isAdFree(CalculatorApplication.this);
|
AdsController.getInstance().isAdFree(CalculatorApplication.this);
|
||||||
|
|
||||||
|
startService(new Intent(getApplicationContext(), CalculatorOverlayService.class));
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
|
|
||||||
|
@ -0,0 +1,90 @@
|
|||||||
|
package org.solovyev.android.calculator.external;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.solovyev.android.calculator.CalculatorDisplayViewState;
|
||||||
|
import org.solovyev.android.calculator.CalculatorEditorViewState;
|
||||||
|
import org.solovyev.android.calculator.CalculatorLocatorImpl;
|
||||||
|
import org.solovyev.common.MutableObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 11/20/12
|
||||||
|
* Time: 10:34 PM
|
||||||
|
*/
|
||||||
|
public class DefaultExternalCalculatorIntentHandler implements ExternalCalculatorIntentHandler {
|
||||||
|
|
||||||
|
private static final String TAG = ExternalCalculatorIntentHandler.class.getSimpleName();
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final MutableObject<Long> lastDisplayEventId = new MutableObject<Long>(0L);
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final MutableObject<Long> lastEditorEventId = new MutableObject<Long>(0L);
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final ExternalCalculatorStateUpdater stateUpdater;
|
||||||
|
|
||||||
|
public DefaultExternalCalculatorIntentHandler(@NotNull ExternalCalculatorStateUpdater stateUpdater) {
|
||||||
|
this.stateUpdater = stateUpdater;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onIntent(@NotNull Context context, @NotNull Intent intent) {
|
||||||
|
|
||||||
|
if (ExternalCalculatorHelper.EDITOR_STATE_CHANGED_ACTION.equals(intent.getAction())) {
|
||||||
|
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "Editor state changed broadcast received!");
|
||||||
|
|
||||||
|
final Long eventId = intent.getLongExtra(ExternalCalculatorHelper.EVENT_ID_EXTRA, 0L);
|
||||||
|
|
||||||
|
boolean updateEditor = false;
|
||||||
|
synchronized (lastEditorEventId) {
|
||||||
|
if (eventId > lastEditorEventId.getObject()) {
|
||||||
|
lastEditorEventId.setObject(eventId);
|
||||||
|
updateEditor = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateEditor) {
|
||||||
|
final Parcelable object = intent.getParcelableExtra(ExternalCalculatorHelper.EDITOR_STATE_EXTRA);
|
||||||
|
if (object instanceof CalculatorEditorViewState) {
|
||||||
|
onEditorStateChanged(context, (CalculatorEditorViewState) object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (ExternalCalculatorHelper.DISPLAY_STATE_CHANGED_ACTION.equals(intent.getAction())) {
|
||||||
|
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "Display state changed broadcast received!");
|
||||||
|
|
||||||
|
final Long eventId = intent.getLongExtra(ExternalCalculatorHelper.EVENT_ID_EXTRA, 0L);
|
||||||
|
boolean updateDisplay = false;
|
||||||
|
synchronized (lastDisplayEventId) {
|
||||||
|
if (eventId > lastDisplayEventId.getObject()) {
|
||||||
|
lastDisplayEventId.setObject(eventId);
|
||||||
|
updateDisplay = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateDisplay) {
|
||||||
|
final Parcelable object = intent.getParcelableExtra(ExternalCalculatorHelper.DISPLAY_STATE_EXTRA);
|
||||||
|
if (object instanceof CalculatorDisplayViewState) {
|
||||||
|
onDisplayStateChanged(context, (CalculatorDisplayViewState) object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateState(@NotNull Context context,
|
||||||
|
@NotNull CalculatorEditorViewState editorViewState,
|
||||||
|
@NotNull CalculatorDisplayViewState displayViewState) {
|
||||||
|
stateUpdater.updateState(context, editorViewState, displayViewState);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onDisplayStateChanged(@NotNull Context context, @NotNull CalculatorDisplayViewState displayViewState) {
|
||||||
|
updateState(context, CalculatorLocatorImpl.getInstance().getEditor().getViewState(), displayViewState);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void onEditorStateChanged(@NotNull Context context, @NotNull CalculatorEditorViewState editorViewState) {
|
||||||
|
updateState(context, editorViewState, CalculatorLocatorImpl.getInstance().getDisplay().getViewState());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
package org.solovyev.android.calculator.external;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.solovyev.android.calculator.*;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 11/20/12
|
||||||
|
* Time: 10:14 PM
|
||||||
|
*/
|
||||||
|
public class ExternalCalculatorHelper {
|
||||||
|
/*
|
||||||
|
**********************************************************************
|
||||||
|
*
|
||||||
|
* CONSTANTS
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
public static final String EVENT_ID_EXTRA = "eventId";
|
||||||
|
public static final String EDITOR_STATE_CHANGED_ACTION = "org.solovyev.calculator.widget.EDITOR_STATE_CHANGED";
|
||||||
|
public static final String EDITOR_STATE_EXTRA = "editorState";
|
||||||
|
public static final String DISPLAY_STATE_CHANGED_ACTION = "org.solovyev.calculator.widget.DISPLAY_STATE_CHANGED";
|
||||||
|
public static final String DISPLAY_STATE_EXTRA = "displayState";
|
||||||
|
|
||||||
|
private static final String TAG = ExternalCalculatorHelper.class.getSimpleName();
|
||||||
|
|
||||||
|
private static final Set<Class<?>> externalListeners = new HashSet<Class<?>>();
|
||||||
|
|
||||||
|
public static void onEditorStateChanged(@NotNull Context context,
|
||||||
|
@NotNull CalculatorEventData calculatorEventData,
|
||||||
|
@NotNull CalculatorEditorViewState editorViewState) {
|
||||||
|
|
||||||
|
for (Class<?> externalListener : externalListeners) {
|
||||||
|
final Intent intent = new Intent(EDITOR_STATE_CHANGED_ACTION);
|
||||||
|
intent.setClass(context, externalListener);
|
||||||
|
intent.putExtra(EVENT_ID_EXTRA, calculatorEventData.getEventId());
|
||||||
|
intent.putExtra(EDITOR_STATE_EXTRA, (Parcelable) new ParcelableCalculatorEditorViewState(editorViewState));
|
||||||
|
context.sendBroadcast(intent);
|
||||||
|
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "Editor state changed broadcast sent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void onDisplayStateChanged(@NotNull Context context,
|
||||||
|
@NotNull CalculatorEventData calculatorEventData,
|
||||||
|
@NotNull CalculatorDisplayViewState displayViewState) {
|
||||||
|
for (Class<?> externalListener : externalListeners) {
|
||||||
|
final Intent intent = new Intent(DISPLAY_STATE_CHANGED_ACTION);
|
||||||
|
intent.setClass(context, externalListener);
|
||||||
|
intent.putExtra(EVENT_ID_EXTRA, calculatorEventData.getEventId());
|
||||||
|
intent.putExtra(DISPLAY_STATE_EXTRA, (Parcelable) new ParcelableCalculatorDisplayViewState(displayViewState));
|
||||||
|
context.sendBroadcast(intent);
|
||||||
|
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "Display state changed broadcast sent");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addExternalListener(@NotNull Class<?> externalCalculatorClass) {
|
||||||
|
externalListeners.add(externalCalculatorClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean removeExternalListener(@NotNull Class<?> externalCalculatorClass) {
|
||||||
|
return externalListeners.remove(externalCalculatorClass);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package org.solovyev.android.calculator.external;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 11/20/12
|
||||||
|
* Time: 10:33 PM
|
||||||
|
*/
|
||||||
|
public interface ExternalCalculatorIntentHandler {
|
||||||
|
|
||||||
|
void onIntent(@NotNull Context context, @NotNull Intent intent);
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package org.solovyev.android.calculator.external;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.solovyev.android.calculator.CalculatorDisplayViewState;
|
||||||
|
import org.solovyev.android.calculator.CalculatorEditorViewState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 11/20/12
|
||||||
|
* Time: 10:42 PM
|
||||||
|
*/
|
||||||
|
public interface ExternalCalculatorStateUpdater {
|
||||||
|
|
||||||
|
void updateState(@NotNull Context context,
|
||||||
|
@NotNull CalculatorEditorViewState editorState,
|
||||||
|
@NotNull CalculatorDisplayViewState displayState);
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package org.solovyev.android.calculator.overlay;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 11/20/12
|
||||||
|
* Time: 11:05 PM
|
||||||
|
*/
|
||||||
|
public final class CalculatorOverlayBroadcastReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
|
public CalculatorOverlayBroadcastReceiver() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(@NotNull Context context,
|
||||||
|
@NotNull Intent intent) {
|
||||||
|
final Intent newIntent = new Intent(intent);
|
||||||
|
newIntent.setClass(context, CalculatorOverlayService.class);
|
||||||
|
context.startService(newIntent);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,163 @@
|
|||||||
|
package org.solovyev.android.calculator.overlay;
|
||||||
|
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.graphics.PixelFormat;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.text.Html;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.solovyev.android.calculator.CalculatorDisplayViewState;
|
||||||
|
import org.solovyev.android.calculator.CalculatorEditorViewState;
|
||||||
|
import org.solovyev.android.calculator.R;
|
||||||
|
import org.solovyev.android.calculator.external.DefaultExternalCalculatorIntentHandler;
|
||||||
|
import org.solovyev.android.calculator.external.ExternalCalculatorHelper;
|
||||||
|
import org.solovyev.android.calculator.external.ExternalCalculatorIntentHandler;
|
||||||
|
import org.solovyev.android.calculator.external.ExternalCalculatorStateUpdater;
|
||||||
|
import org.solovyev.android.calculator.widget.WidgetButton;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 11/20/12
|
||||||
|
* Time: 9:42 PM
|
||||||
|
*/
|
||||||
|
public class CalculatorOverlayService extends Service implements ExternalCalculatorStateUpdater {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private View view;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final ExternalCalculatorIntentHandler intentHandler = new DefaultExternalCalculatorIntentHandler(this);
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static String cursorColor;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
|
||||||
|
final LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
view = layoutInflater.inflate(R.layout.overlay_layout, null);
|
||||||
|
|
||||||
|
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
|
||||||
|
300,
|
||||||
|
450,
|
||||||
|
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
|
||||||
|
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL|WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
|
||||||
|
PixelFormat.TRANSLUCENT);
|
||||||
|
|
||||||
|
for (final WidgetButton widgetButton : WidgetButton.values()) {
|
||||||
|
final View button = view.findViewById(widgetButton.getButtonId());
|
||||||
|
if (button != null) {
|
||||||
|
button.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
widgetButton.onClick(CalculatorOverlayService.this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
|
||||||
|
wm.addView(view, params);
|
||||||
|
|
||||||
|
startCalculatorListening();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startCalculatorListening() {
|
||||||
|
ExternalCalculatorHelper.addExternalListener(getIntentListenerClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private Class<?> getIntentListenerClass() {
|
||||||
|
return CalculatorOverlayBroadcastReceiver.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopCalculatorListening() {
|
||||||
|
ExternalCalculatorHelper.removeExternalListener(getIntentListenerClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
stopCalculatorListening();
|
||||||
|
|
||||||
|
if (view != null) {
|
||||||
|
((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(view);
|
||||||
|
view = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateState(@NotNull Context context, @NotNull CalculatorEditorViewState editorState, @NotNull CalculatorDisplayViewState displayState) {
|
||||||
|
final View root = this.view;
|
||||||
|
if (root != null) {
|
||||||
|
updateDisplayState(context, root, displayState);
|
||||||
|
updateEditorState(context, root, editorState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void updateDisplayState(@NotNull Context context, @NotNull View root, @NotNull CalculatorDisplayViewState displayState) {
|
||||||
|
final TextView calculatorDisplayView = (TextView) root.findViewById(R.id.calculator_display);
|
||||||
|
if (calculatorDisplayView != null) {
|
||||||
|
if (displayState.isValid()) {
|
||||||
|
calculatorDisplayView.setText(displayState.getText());
|
||||||
|
calculatorDisplayView.setTextColor(context.getResources().getColor(R.color.cpp_default_text_color));
|
||||||
|
} else {
|
||||||
|
calculatorDisplayView.setTextColor(context.getResources().getColor(R.color.cpp_display_error_text_color));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void updateEditorState(@NotNull Context context, @NotNull View root, @NotNull CalculatorEditorViewState editorState) {
|
||||||
|
final TextView calculatorEditorView = (TextView) root.findViewById(R.id.calculator_editor);
|
||||||
|
|
||||||
|
if (calculatorEditorView != null) {
|
||||||
|
String text = editorState.getText();
|
||||||
|
|
||||||
|
CharSequence newText = text;
|
||||||
|
int selection = editorState.getSelection();
|
||||||
|
if (selection >= 0 && selection <= text.length()) {
|
||||||
|
// inject cursor
|
||||||
|
newText = Html.fromHtml(text.substring(0, selection) + "<font color=\"#" + getCursorColor(context) + "\">|</font>" + text.substring(selection));
|
||||||
|
}
|
||||||
|
calculatorEditorView.setText(newText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static String getCursorColor(@NotNull Context context) {
|
||||||
|
if (cursorColor == null) {
|
||||||
|
cursorColor = Integer.toHexString(context.getResources().getColor(R.color.cpp_widget_cursor_color)).substring(2);
|
||||||
|
}
|
||||||
|
return cursorColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart(Intent intent, int startId) {
|
||||||
|
super.onStart(intent, startId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
|
int result = super.onStartCommand(intent, flags, startId);
|
||||||
|
|
||||||
|
if ( intent != null ) {
|
||||||
|
intentHandler.onIntent(this, intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,41 +6,24 @@ import android.appwidget.AppWidgetProvider;
|
|||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Parcelable;
|
|
||||||
import android.text.Html;
|
import android.text.Html;
|
||||||
import android.widget.RemoteViews;
|
import android.widget.RemoteViews;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.solovyev.android.calculator.*;
|
import org.solovyev.android.calculator.*;
|
||||||
import org.solovyev.common.MutableObject;
|
import org.solovyev.android.calculator.external.ExternalCalculatorHelper;
|
||||||
|
import org.solovyev.android.calculator.external.ExternalCalculatorIntentHandler;
|
||||||
import java.util.ArrayList;
|
import org.solovyev.android.calculator.external.ExternalCalculatorStateUpdater;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User: Solovyev_S
|
* User: Solovyev_S
|
||||||
* Date: 19.10.12
|
* Date: 19.10.12
|
||||||
* Time: 16:18
|
* Time: 16:18
|
||||||
*/
|
*/
|
||||||
abstract class AbstractCalculatorWidgetProvider extends AppWidgetProvider {
|
abstract class AbstractCalculatorWidgetProvider extends AppWidgetProvider implements ExternalCalculatorStateUpdater {
|
||||||
|
|
||||||
/*
|
static final String BUTTON_ID_EXTRA = "buttonId";
|
||||||
**********************************************************************
|
static final String BUTTON_PRESSED_ACTION = "org.solovyev.calculator.widget.BUTTON_PRESSED";
|
||||||
*
|
|
||||||
* CONSTANTS
|
|
||||||
*
|
|
||||||
**********************************************************************
|
|
||||||
*/
|
|
||||||
private static final String EVENT_ID_EXTRA = "eventId";
|
|
||||||
|
|
||||||
private static final String BUTTON_ID_EXTRA = "buttonId";
|
|
||||||
private static final String BUTTON_PRESSED_ACTION = "org.solovyev.calculator.widget.BUTTON_PRESSED";
|
|
||||||
|
|
||||||
private static final String EDITOR_STATE_CHANGED_ACTION = "org.solovyev.calculator.widget.EDITOR_STATE_CHANGED";
|
|
||||||
private static final String EDITOR_STATE_EXTRA = "editorState";
|
|
||||||
|
|
||||||
private static final String DISPLAY_STATE_CHANGED_ACTION = "org.solovyev.calculator.widget.DISPLAY_STATE_CHANGED";
|
|
||||||
private static final String DISPLAY_STATE_EXTRA = "displayState";
|
|
||||||
|
|
||||||
private static final String TAG = "Calculator++ Widget";
|
private static final String TAG = "Calculator++ Widget";
|
||||||
|
|
||||||
@ -56,10 +39,8 @@ abstract class AbstractCalculatorWidgetProvider extends AppWidgetProvider {
|
|||||||
private String cursorColor;
|
private String cursorColor;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private final MutableObject<Long> lastDisplayEventId = new MutableObject<Long>(0L);
|
private ExternalCalculatorIntentHandler intentHandler = new CalculatorWidgetIntentHandler(this);
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private final MutableObject<Long> lastEditorEventId = new MutableObject<Long>(0L);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
@ -71,9 +52,8 @@ abstract class AbstractCalculatorWidgetProvider extends AppWidgetProvider {
|
|||||||
|
|
||||||
protected AbstractCalculatorWidgetProvider() {
|
protected AbstractCalculatorWidgetProvider() {
|
||||||
final Class<? extends AppWidgetProvider> componentClass = this.getComponentClass();
|
final Class<? extends AppWidgetProvider> componentClass = this.getComponentClass();
|
||||||
if (!knownAppWidgetProviderClasses.contains(componentClass)) {
|
|
||||||
knownAppWidgetProviderClasses.add(componentClass);
|
ExternalCalculatorHelper.addExternalListener(componentClass);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -108,7 +88,8 @@ abstract class AbstractCalculatorWidgetProvider extends AppWidgetProvider {
|
|||||||
updateWidget(context, appWidgetManager, appWidgetIds, CalculatorLocatorImpl.getInstance().getEditor().getViewState(), CalculatorLocatorImpl.getInstance().getDisplay().getViewState());
|
updateWidget(context, appWidgetManager, appWidgetIds, CalculatorLocatorImpl.getInstance().getEditor().getViewState(), CalculatorLocatorImpl.getInstance().getDisplay().getViewState());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateWidget(@NotNull Context context,
|
@Override
|
||||||
|
public void updateState(@NotNull Context context,
|
||||||
@NotNull CalculatorEditorViewState editorState,
|
@NotNull CalculatorEditorViewState editorState,
|
||||||
@NotNull CalculatorDisplayViewState displayState) {
|
@NotNull CalculatorDisplayViewState displayState) {
|
||||||
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
||||||
@ -153,53 +134,7 @@ abstract class AbstractCalculatorWidgetProvider extends AppWidgetProvider {
|
|||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
super.onReceive(context, intent);
|
super.onReceive(context, intent);
|
||||||
|
|
||||||
if (AbstractCalculatorWidgetProvider.BUTTON_PRESSED_ACTION.equals(intent.getAction())) {
|
this.intentHandler.onIntent(context, intent);
|
||||||
final int buttonId = intent.getIntExtra(AbstractCalculatorWidgetProvider.BUTTON_ID_EXTRA, 0);
|
|
||||||
|
|
||||||
final WidgetButton button = WidgetButton.getById(buttonId);
|
|
||||||
if (button != null) {
|
|
||||||
button.onClick(context);
|
|
||||||
}
|
|
||||||
} else if (EDITOR_STATE_CHANGED_ACTION.equals(intent.getAction())) {
|
|
||||||
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "Editor state changed broadcast received!");
|
|
||||||
|
|
||||||
final Long eventId = intent.getLongExtra(EVENT_ID_EXTRA, 0L);
|
|
||||||
|
|
||||||
boolean updateEditor = false;
|
|
||||||
synchronized (lastEditorEventId) {
|
|
||||||
if (eventId > lastEditorEventId.getObject()) {
|
|
||||||
lastEditorEventId.setObject(eventId);
|
|
||||||
updateEditor = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateEditor) {
|
|
||||||
final Parcelable object = intent.getParcelableExtra(EDITOR_STATE_EXTRA);
|
|
||||||
if (object instanceof CalculatorEditorViewState) {
|
|
||||||
updateWidget(context, (CalculatorEditorViewState) object, CalculatorLocatorImpl.getInstance().getDisplay().getViewState());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (DISPLAY_STATE_CHANGED_ACTION.equals(intent.getAction())) {
|
|
||||||
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "Display state changed broadcast received!");
|
|
||||||
|
|
||||||
final Long eventId = intent.getLongExtra(EVENT_ID_EXTRA, 0L);
|
|
||||||
boolean updateDisplay = false;
|
|
||||||
synchronized (lastDisplayEventId) {
|
|
||||||
if (eventId > lastDisplayEventId.getObject()) {
|
|
||||||
lastDisplayEventId.setObject(eventId);
|
|
||||||
updateDisplay = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (updateDisplay) {
|
|
||||||
final Parcelable object = intent.getParcelableExtra(DISPLAY_STATE_EXTRA);
|
|
||||||
if (object instanceof CalculatorDisplayViewState) {
|
|
||||||
updateWidget(context, CalculatorLocatorImpl.getInstance().getEditor().getViewState(), (CalculatorDisplayViewState) object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(intent.getAction())) {
|
|
||||||
updateWidget(context, CalculatorLocatorImpl.getInstance().getEditor().getViewState(), CalculatorLocatorImpl.getInstance().getDisplay().getViewState());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateDisplayState(@NotNull Context context, @NotNull RemoteViews views, @NotNull CalculatorDisplayViewState displayState) {
|
private void updateDisplayState(@NotNull Context context, @NotNull RemoteViews views, @NotNull CalculatorDisplayViewState displayState) {
|
||||||
@ -223,42 +158,4 @@ abstract class AbstractCalculatorWidgetProvider extends AppWidgetProvider {
|
|||||||
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "New editor state: " + text);
|
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "New editor state: " + text);
|
||||||
views.setTextViewText(R.id.calculator_editor, newText);
|
views.setTextViewText(R.id.calculator_editor, newText);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
**********************************************************************
|
|
||||||
*
|
|
||||||
* STATIC
|
|
||||||
*
|
|
||||||
**********************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
private static final List<Class<? extends AppWidgetProvider>> knownAppWidgetProviderClasses = new ArrayList<Class<? extends AppWidgetProvider>>();
|
|
||||||
|
|
||||||
public static void onEditorStateChanged(@NotNull Context context,
|
|
||||||
@NotNull CalculatorEventData calculatorEventData,
|
|
||||||
@NotNull CalculatorEditorViewState editorViewState) {
|
|
||||||
|
|
||||||
for (Class<? extends AppWidgetProvider> appWidgetProviderClass : knownAppWidgetProviderClasses) {
|
|
||||||
final Intent intent = new Intent(EDITOR_STATE_CHANGED_ACTION);
|
|
||||||
intent.setClass(context, appWidgetProviderClass);
|
|
||||||
intent.putExtra(EVENT_ID_EXTRA, calculatorEventData.getEventId());
|
|
||||||
intent.putExtra(EDITOR_STATE_EXTRA, (Parcelable) new ParcelableCalculatorEditorViewState(editorViewState));
|
|
||||||
context.sendBroadcast(intent);
|
|
||||||
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "Editor state changed broadcast sent");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void onDisplayStateChanged(@NotNull Context context,
|
|
||||||
@NotNull CalculatorEventData calculatorEventData,
|
|
||||||
@NotNull CalculatorDisplayViewState displayViewState) {
|
|
||||||
for (Class<? extends AppWidgetProvider> appWidgetProviderClass : knownAppWidgetProviderClasses) {
|
|
||||||
final Intent intent = new Intent(DISPLAY_STATE_CHANGED_ACTION);
|
|
||||||
intent.setClass(context, appWidgetProviderClass);
|
|
||||||
intent.putExtra(EVENT_ID_EXTRA, calculatorEventData.getEventId());
|
|
||||||
intent.putExtra(DISPLAY_STATE_EXTRA, (Parcelable)new ParcelableCalculatorDisplayViewState(displayViewState));
|
|
||||||
context.sendBroadcast(intent);
|
|
||||||
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "Display state changed broadcast sent");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package org.solovyev.android.calculator.widget;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.solovyev.android.calculator.*;
|
import org.solovyev.android.calculator.*;
|
||||||
|
import org.solovyev.android.calculator.external.ExternalCalculatorHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User: serso
|
* User: serso
|
||||||
@ -32,7 +33,7 @@ public class CalculatorWidgetHelper implements CalculatorEventListener {
|
|||||||
|
|
||||||
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "Editor state changed: " + newEditorState.getText());
|
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "Editor state changed: " + newEditorState.getText());
|
||||||
|
|
||||||
AbstractCalculatorWidgetProvider.onEditorStateChanged(CalculatorApplication.getInstance(), calculatorEventData, newEditorState);
|
ExternalCalculatorHelper.onEditorStateChanged(CalculatorApplication.getInstance(), calculatorEventData, newEditorState);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case display_state_changed:
|
case display_state_changed:
|
||||||
@ -41,7 +42,7 @@ public class CalculatorWidgetHelper implements CalculatorEventListener {
|
|||||||
|
|
||||||
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "Display state changed: " + newDisplayState.getText());
|
CalculatorLocatorImpl.getInstance().getNotifier().showDebugMessage(TAG, "Display state changed: " + newDisplayState.getText());
|
||||||
|
|
||||||
AbstractCalculatorWidgetProvider.onDisplayStateChanged(CalculatorApplication.getInstance(), calculatorEventData, newDisplayState);
|
ExternalCalculatorHelper.onDisplayStateChanged(CalculatorApplication.getInstance(), calculatorEventData, newDisplayState);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
package org.solovyev.android.calculator.widget;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.solovyev.android.calculator.CalculatorLocatorImpl;
|
||||||
|
import org.solovyev.android.calculator.external.DefaultExternalCalculatorIntentHandler;
|
||||||
|
import org.solovyev.android.calculator.external.ExternalCalculatorStateUpdater;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 11/20/12
|
||||||
|
* Time: 10:39 PM
|
||||||
|
*/
|
||||||
|
public class CalculatorWidgetIntentHandler extends DefaultExternalCalculatorIntentHandler {
|
||||||
|
|
||||||
|
public CalculatorWidgetIntentHandler(@NotNull ExternalCalculatorStateUpdater stateUpdater) {
|
||||||
|
super(stateUpdater);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onIntent(@NotNull Context context, @NotNull Intent intent) {
|
||||||
|
super.onIntent(context, intent);
|
||||||
|
|
||||||
|
if (AbstractCalculatorWidgetProvider.BUTTON_PRESSED_ACTION.equals(intent.getAction())) {
|
||||||
|
final int buttonId = intent.getIntExtra(AbstractCalculatorWidgetProvider.BUTTON_ID_EXTRA, 0);
|
||||||
|
|
||||||
|
final WidgetButton button = WidgetButton.getById(buttonId);
|
||||||
|
if (button != null) {
|
||||||
|
button.onClick(context);
|
||||||
|
}
|
||||||
|
} else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(intent.getAction())) {
|
||||||
|
updateState(context, CalculatorLocatorImpl.getInstance().getEditor().getViewState(), CalculatorLocatorImpl.getInstance().getDisplay().getViewState());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -15,7 +15,7 @@ import java.util.Map;
|
|||||||
* Date: 10/20/12
|
* Date: 10/20/12
|
||||||
* Time: 12:05 AM
|
* Time: 12:05 AM
|
||||||
*/
|
*/
|
||||||
enum WidgetButton {
|
public enum WidgetButton {
|
||||||
|
|
||||||
/*digits*/
|
/*digits*/
|
||||||
one(R.id.oneDigitButton, "1"),
|
one(R.id.oneDigitButton, "1"),
|
||||||
|
Loading…
Reference in New Issue
Block a user