Calculator onscreen added
This commit is contained in:
parent
0a35201c80
commit
ddbb9b3bef
@ -6,7 +6,7 @@
|
|||||||
<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 -->
|
<!-- for onscreen calculator -->
|
||||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||||
|
|
||||||
|
|
||||||
@ -51,7 +51,7 @@
|
|||||||
<!-- 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 -->
|
<!-- ONSCREEN CONFIG -->
|
||||||
|
|
||||||
<activity android:launchMode="singleInstance"
|
<activity android:launchMode="singleInstance"
|
||||||
android:label="@string/c_app_name_on_screen"
|
android:label="@string/c_app_name_on_screen"
|
||||||
@ -64,14 +64,14 @@
|
|||||||
|
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<service android:name=".overlay.CalculatorOverlayService">
|
<service android:name=".onscreen.CalculatorOnscreenService">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="org.solovyev.calculator.widget.EDITOR_STATE_CHANGED"/>
|
<action android:name="org.solovyev.calculator.widget.EDITOR_STATE_CHANGED"/>
|
||||||
<action android:name="org.solovyev.calculator.widget.DISPLAY_STATE_CHANGED"/>
|
<action android:name="org.solovyev.calculator.widget.DISPLAY_STATE_CHANGED"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<receiver android:name=".overlay.CalculatorOverlayBroadcastReceiver">
|
<receiver android:name=".onscreen.CalculatorOnscreenBroadcastReceiver">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="org.solovyev.calculator.widget.EDITOR_STATE_CHANGED"/>
|
<action android:name="org.solovyev.calculator.widget.EDITOR_STATE_CHANGED"/>
|
||||||
<action android:name="org.solovyev.calculator.widget.DISPLAY_STATE_CHANGED"/>
|
<action android:name="org.solovyev.calculator.widget.DISPLAY_STATE_CHANGED"/>
|
||||||
|
32
calculatorpp/res/layout/onscreen_header.xml
Normal file
32
calculatorpp/res/layout/onscreen_header.xml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<RelativeLayout xmlns:a="http://schemas.android.com/apk/res/android"
|
||||||
|
a:layout_width="match_parent"
|
||||||
|
a:layout_height="30dp">
|
||||||
|
|
||||||
|
<LinearLayout a:id="@+id/onscreen_header_buttons"
|
||||||
|
a:layout_width="wrap_content"
|
||||||
|
a:layout_height="match_parent"
|
||||||
|
a:layout_alignParentRight="true">
|
||||||
|
|
||||||
|
<Button a:id="@+id/onscreen_fold_button"
|
||||||
|
style="@style/onscreen_header_button_style"
|
||||||
|
a:text="_"/>
|
||||||
|
|
||||||
|
<Button a:id="@+id/onscreen_minimize_button"
|
||||||
|
style="@style/onscreen_header_button_style"
|
||||||
|
a:text="_"/>
|
||||||
|
|
||||||
|
<Button a:id="@+id/onscreen_close_button"
|
||||||
|
style="@style/onscreen_header_button_style"
|
||||||
|
a:text="x"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView a:id="@+id/onscreen_title"
|
||||||
|
a:text="@string/c_app_name"
|
||||||
|
a:layout_width="match_parent"
|
||||||
|
a:layout_height="match_parent"
|
||||||
|
a:layout_toLeftOf="@id/onscreen_header_buttons"/>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
@ -4,9 +4,9 @@
|
|||||||
a:orientation="vertical"
|
a:orientation="vertical"
|
||||||
style="@style/cpp_widget_main_layout_style">
|
style="@style/cpp_widget_main_layout_style">
|
||||||
|
|
||||||
<include layout="@layout/overlay_header"/>
|
<include layout="@layout/onscreen_header"/>
|
||||||
|
|
||||||
<LinearLayout a:id="@+id/overlay_content"
|
<LinearLayout a:id="@+id/onscreen_content"
|
||||||
a:orientation="vertical"
|
a:orientation="vertical"
|
||||||
a:layout_width="match_parent"
|
a:layout_width="match_parent"
|
||||||
a:layout_height="match_parent">
|
a:layout_height="match_parent">
|
||||||
@ -39,6 +39,6 @@
|
|||||||
a:layout_height="0dp"/>
|
a:layout_height="0dp"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<include layout="@layout/overlay_footer"/>
|
<include layout="@layout/onscreen_footer"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
@ -1,36 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
|
|
||||||
<RelativeLayout xmlns:a="http://schemas.android.com/apk/res/android"
|
|
||||||
a:layout_width="match_parent"
|
|
||||||
a:layout_height="30dp">
|
|
||||||
|
|
||||||
<LinearLayout a:id="@+id/overlay_header_buttons"
|
|
||||||
a:layout_width="wrap_content"
|
|
||||||
a:layout_height="match_parent"
|
|
||||||
a:layout_alignParentRight="true">
|
|
||||||
|
|
||||||
<Button a:id="@+id/overlay_hide_button"
|
|
||||||
a:layout_width="wrap_content"
|
|
||||||
a:layout_height="match_parent"
|
|
||||||
a:layout_weight="0"
|
|
||||||
a:padding="6dp"
|
|
||||||
style="@style/widget_metro_control_button_style"
|
|
||||||
a:text="_"/>
|
|
||||||
|
|
||||||
<Button a:id="@+id/overlay_close_button"
|
|
||||||
a:layout_width="wrap_content"
|
|
||||||
a:layout_height="match_parent"
|
|
||||||
a:layout_weight="0"
|
|
||||||
a:padding="6dp"
|
|
||||||
style="@style/widget_metro_control_button_style"
|
|
||||||
a:text="x"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<TextView a:id="@+id/overlay_title"
|
|
||||||
a:text="@string/c_app_name"
|
|
||||||
a:layout_width="match_parent"
|
|
||||||
a:layout_height="match_parent"
|
|
||||||
a:layout_toLeftOf="@id/overlay_header_buttons"/>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
@ -269,5 +269,6 @@
|
|||||||
<string name="c_app_widget_3x4_name">Калькулятор++ Виджет (3x4)</string>
|
<string name="c_app_widget_3x4_name">Калькулятор++ Виджет (3x4)</string>
|
||||||
<string name="c_app_widget_4x4_name">Калькулятор++ Виджет (4x4)</string>
|
<string name="c_app_widget_4x4_name">Калькулятор++ Виджет (4x4)</string>
|
||||||
<string name="c_app_widget_4x5_name">Калькулятор++ Виджет (4x5)</string>
|
<string name="c_app_widget_4x5_name">Калькулятор++ Виджет (4x5)</string>
|
||||||
|
<string name="open_onscreen_calculator">Нажмите чтобы открыть калькулятор поверх всех приложений</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
@ -25,6 +25,8 @@
|
|||||||
<dimen name="cpp_widget_display_text_size">25sp</dimen>
|
<dimen name="cpp_widget_display_text_size">25sp</dimen>
|
||||||
<dimen name="cpp_widget_margin">6dp</dimen>
|
<dimen name="cpp_widget_margin">6dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="cpp_onscreen_header_button_text_size">10dp</dimen>
|
||||||
|
|
||||||
<!--only for not multipane-->
|
<!--only for not multipane-->
|
||||||
<dimen name="cpp_editor_padding">5dp</dimen>
|
<dimen name="cpp_editor_padding">5dp</dimen>
|
||||||
<dimen name="cpp_display_padding">3dp</dimen>
|
<dimen name="cpp_display_padding">3dp</dimen>
|
||||||
|
@ -270,5 +270,6 @@
|
|||||||
<string name="c_app_widget_3x4_name">Calculator++ Widget (3x4)</string>
|
<string name="c_app_widget_3x4_name">Calculator++ Widget (3x4)</string>
|
||||||
<string name="c_app_widget_4x4_name">Calculator++ Widget (4x4)</string>
|
<string name="c_app_widget_4x4_name">Calculator++ Widget (4x4)</string>
|
||||||
<string name="c_app_widget_4x5_name">Calculator++ Widget (4x5)</string>
|
<string name="c_app_widget_4x5_name">Calculator++ Widget (4x5)</string>
|
||||||
|
<string name="open_onscreen_calculator">Click to open on-screen calculator</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
@ -86,7 +86,7 @@
|
|||||||
<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">
|
<style name="cpp_onscreen_main_layout_style" parent="cpp_default_main_layout_style">
|
||||||
<item name="android:layout_height">400dp</item>
|
<item name="android:layout_height">400dp</item>
|
||||||
<item name="android:layout_width">250dp</item>
|
<item name="android:layout_width">250dp</item>
|
||||||
</style>
|
</style>
|
||||||
|
@ -12,6 +12,14 @@
|
|||||||
<item name="android:background">@drawable/metro_button_light</item>
|
<item name="android:background">@drawable/metro_button_light</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="onscreen_header_button_style" parent="metro_control_button_style">
|
||||||
|
<item name="android:layout_width">30dp</item>
|
||||||
|
<item name="android:layout_height">30dp</item>
|
||||||
|
<item name="android:layout_weight">0</item>
|
||||||
|
<item name="android:padding">0dp</item>
|
||||||
|
<item name="android:textSize">@dimen/cpp_onscreen_header_button_text_size</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="widget_metro_control_button_style" parent="metro_control_button_style">
|
<style name="widget_metro_control_button_style" parent="metro_control_button_style">
|
||||||
<item name="android:textSize">@dimen/cpp_widget_keyboard_button_text_size</item>
|
<item name="android:textSize">@dimen/cpp_widget_keyboard_button_text_size</item>
|
||||||
</style>
|
</style>
|
||||||
|
@ -3,7 +3,7 @@ package org.solovyev.android.calculator;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import org.solovyev.android.calculator.overlay.CalculatorOverlayService;
|
import org.solovyev.android.calculator.onscreen.CalculatorOnscreenService;
|
||||||
|
|
||||||
public class CalculatorOnScreenStartActivity extends Activity {
|
public class CalculatorOnScreenStartActivity extends Activity {
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ public class CalculatorOnScreenStartActivity extends Activity {
|
|||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
startService(new Intent(this, CalculatorOverlayService.class));
|
startService(new Intent(this, CalculatorOnscreenService.class));
|
||||||
|
|
||||||
this.finish();
|
this.finish();
|
||||||
}
|
}
|
||||||
|
@ -30,68 +30,69 @@ import java.util.Set;
|
|||||||
*/
|
*/
|
||||||
public class AndroidExternalListenersContainer implements CalculatorExternalListenersContainer, CalculatorEventListener {
|
public class AndroidExternalListenersContainer implements CalculatorExternalListenersContainer, CalculatorEventListener {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
*
|
*
|
||||||
* CONSTANTS
|
* 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 = "Calculator++ External Listener Helper";
|
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 final Set<Class<?>> externalListeners = new HashSet<Class<?>>();
|
private static final String TAG = "Calculator++ External Listener Helper";
|
||||||
|
|
||||||
@NotNull
|
private final Set<Class<?>> externalListeners = new HashSet<Class<?>>();
|
||||||
|
|
||||||
|
@NotNull
|
||||||
private final CalculatorEventHolder lastEvent = new CalculatorEventHolder(CalculatorUtils.createFirstEventDataId());
|
private final CalculatorEventHolder lastEvent = new CalculatorEventHolder(CalculatorUtils.createFirstEventDataId());
|
||||||
|
|
||||||
public AndroidExternalListenersContainer(@NotNull Calculator calculator) {
|
public AndroidExternalListenersContainer(@NotNull Calculator calculator) {
|
||||||
calculator.addCalculatorEventListener(this);
|
calculator.addCalculatorEventListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onEditorStateChanged(@NotNull Context context,
|
public void onEditorStateChanged(@NotNull Context context,
|
||||||
@NotNull CalculatorEventData calculatorEventData,
|
@NotNull CalculatorEventData calculatorEventData,
|
||||||
@NotNull CalculatorEditorViewState editorViewState) {
|
@NotNull CalculatorEditorViewState editorViewState) {
|
||||||
|
|
||||||
for (Class<?> externalListener : externalListeners) {
|
for (Class<?> externalListener : externalListeners) {
|
||||||
final Intent intent = new Intent(EDITOR_STATE_CHANGED_ACTION);
|
final Intent intent = new Intent(EDITOR_STATE_CHANGED_ACTION);
|
||||||
intent.setClass(context, externalListener);
|
intent.setClass(context, externalListener);
|
||||||
intent.putExtra(EVENT_ID_EXTRA, calculatorEventData.getEventId());
|
intent.putExtra(EVENT_ID_EXTRA, calculatorEventData.getEventId());
|
||||||
intent.putExtra(EDITOR_STATE_EXTRA, (Parcelable) new ParcelableCalculatorEditorViewState(editorViewState));
|
intent.putExtra(EDITOR_STATE_EXTRA, (Parcelable) new ParcelableCalculatorEditorViewState(editorViewState));
|
||||||
context.sendBroadcast(intent);
|
context.sendBroadcast(intent);
|
||||||
Locator.getInstance().getNotifier().showDebugMessage(TAG, "Editor state changed broadcast sent");
|
Locator.getInstance().getNotifier().showDebugMessage(TAG, "Editor state changed broadcast sent");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onDisplayStateChanged(@NotNull Context context,
|
private void onDisplayStateChanged(@NotNull Context context,
|
||||||
@NotNull CalculatorEventData calculatorEventData,
|
@NotNull CalculatorEventData calculatorEventData,
|
||||||
@NotNull CalculatorDisplayViewState displayViewState) {
|
@NotNull CalculatorDisplayViewState displayViewState) {
|
||||||
for (Class<?> externalListener : externalListeners) {
|
for (Class<?> externalListener : externalListeners) {
|
||||||
final Intent intent = new Intent(DISPLAY_STATE_CHANGED_ACTION);
|
final Intent intent = new Intent(DISPLAY_STATE_CHANGED_ACTION);
|
||||||
intent.setClass(context, externalListener);
|
intent.setClass(context, externalListener);
|
||||||
intent.putExtra(EVENT_ID_EXTRA, calculatorEventData.getEventId());
|
intent.putExtra(EVENT_ID_EXTRA, calculatorEventData.getEventId());
|
||||||
intent.putExtra(DISPLAY_STATE_EXTRA, (Parcelable) new ParcelableCalculatorDisplayViewState(displayViewState));
|
intent.putExtra(DISPLAY_STATE_EXTRA, (Parcelable) new ParcelableCalculatorDisplayViewState(displayViewState));
|
||||||
context.sendBroadcast(intent);
|
context.sendBroadcast(intent);
|
||||||
Locator.getInstance().getNotifier().showDebugMessage(TAG, "Display state changed broadcast sent");
|
Locator.getInstance().getNotifier().showDebugMessage(TAG, "Display state changed broadcast sent");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addExternalListener(@NotNull Class<?> externalCalculatorClass) {
|
public void addExternalListener(@NotNull Class<?> externalCalculatorClass) {
|
||||||
externalListeners.add(externalCalculatorClass);
|
externalListeners.add(externalCalculatorClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean removeExternalListener(@NotNull Class<?> externalCalculatorClass) {
|
public boolean removeExternalListener(@NotNull Class<?> externalCalculatorClass) {
|
||||||
return externalListeners.remove(externalCalculatorClass);
|
return externalListeners.remove(externalCalculatorClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) {
|
public void onCalculatorEvent(@NotNull CalculatorEventData calculatorEventData, @NotNull CalculatorEventType calculatorEventType, @Nullable Object data) {
|
||||||
final CalculatorEventHolder.Result result = lastEvent.apply(calculatorEventData);
|
final CalculatorEventHolder.Result result = lastEvent.apply(calculatorEventData);
|
||||||
if (result.isNewAfter()) {
|
if (result.isNewAfter()) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package org.solovyev.android.calculator.overlay;
|
package org.solovyev.android.calculator.onscreen;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -10,16 +10,16 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
* Date: 11/20/12
|
* Date: 11/20/12
|
||||||
* Time: 11:05 PM
|
* Time: 11:05 PM
|
||||||
*/
|
*/
|
||||||
public final class CalculatorOverlayBroadcastReceiver extends BroadcastReceiver {
|
public final class CalculatorOnscreenBroadcastReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
public CalculatorOverlayBroadcastReceiver() {
|
public CalculatorOnscreenBroadcastReceiver() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(@NotNull Context context,
|
public void onReceive(@NotNull Context context,
|
||||||
@NotNull Intent intent) {
|
@NotNull Intent intent) {
|
||||||
final Intent newIntent = new Intent(intent);
|
final Intent newIntent = new Intent(intent);
|
||||||
newIntent.setClass(context, CalculatorOverlayService.class);
|
newIntent.setClass(context, CalculatorOnscreenService.class);
|
||||||
context.startService(newIntent);
|
context.startService(newIntent);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,155 @@
|
|||||||
|
package org.solovyev.android.calculator.onscreen;
|
||||||
|
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.support.v4.app.NotificationCompat;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.solovyev.android.AndroidUtils;
|
||||||
|
import org.solovyev.android.calculator.CalculatorDisplayViewState;
|
||||||
|
import org.solovyev.android.calculator.CalculatorEditorViewState;
|
||||||
|
import org.solovyev.android.calculator.Locator;
|
||||||
|
import org.solovyev.android.calculator.R;
|
||||||
|
import org.solovyev.android.calculator.external.DefaultExternalCalculatorIntentHandler;
|
||||||
|
import org.solovyev.android.calculator.external.ExternalCalculatorIntentHandler;
|
||||||
|
import org.solovyev.android.calculator.external.ExternalCalculatorStateUpdater;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 11/20/12
|
||||||
|
* Time: 9:42 PM
|
||||||
|
*/
|
||||||
|
public class CalculatorOnscreenService extends Service implements ExternalCalculatorStateUpdater, OnscreenViewListener {
|
||||||
|
|
||||||
|
private static final int NOTIFICATION_ID = 9031988; // my birthday =)
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final ExternalCalculatorIntentHandler intentHandler = new DefaultExternalCalculatorIntentHandler(this);
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static String cursorColor;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private CalculatorOnscreenView view;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
|
||||||
|
final WindowManager wm = ((WindowManager) this.getSystemService(Context.WINDOW_SERVICE));
|
||||||
|
|
||||||
|
final DisplayMetrics dm = getResources().getDisplayMetrics();
|
||||||
|
|
||||||
|
final int displayWidth0 = 2 * wm.getDefaultDisplay().getWidth() / 3;
|
||||||
|
final int displayHeight0 = 2 * wm.getDefaultDisplay().getHeight() / 3;
|
||||||
|
|
||||||
|
final int displayWidth = Math.min(displayWidth0, displayHeight0);
|
||||||
|
final int displayHeight = Math.max(displayWidth0, displayHeight0);
|
||||||
|
|
||||||
|
final int width0 = Math.min(displayWidth, AndroidUtils.toPixels(dm, 300));
|
||||||
|
final int height0 = Math.min(displayHeight, AndroidUtils.toPixels(dm, 450));
|
||||||
|
|
||||||
|
final int width = Math.min(width0, height0);
|
||||||
|
final int height = Math.max(width0, height0);
|
||||||
|
|
||||||
|
view = CalculatorOnscreenView.newInstance(this, CalculatorOnscreenViewDef.newInstance(width, height, -1, -1), getCursorColor(this), this);
|
||||||
|
view.show();
|
||||||
|
|
||||||
|
startCalculatorListening();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startCalculatorListening() {
|
||||||
|
Locator.getInstance().getExternalListenersContainer().addExternalListener(getIntentListenerClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private Class<?> getIntentListenerClass() {
|
||||||
|
return CalculatorOnscreenBroadcastReceiver.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopCalculatorListening() {
|
||||||
|
Locator.getInstance().getExternalListenersContainer().removeExternalListener(getIntentListenerClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
stopCalculatorListening();
|
||||||
|
this.view.hide();
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateState(@NotNull Context context, @NotNull CalculatorEditorViewState editorState, @NotNull CalculatorDisplayViewState displayState) {
|
||||||
|
view.updateDisplayState(displayState);
|
||||||
|
view.updateEditorState(editorState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
|
||||||
|
hideNotification();
|
||||||
|
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hideNotification() {
|
||||||
|
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
nm.cancel(NOTIFICATION_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewMinimized() {
|
||||||
|
showNotification();
|
||||||
|
stopSelf();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewHidden() {
|
||||||
|
stopSelf();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showNotification() {
|
||||||
|
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
|
||||||
|
builder.setSmallIcon(R.drawable.kb_logo);
|
||||||
|
builder.setContentTitle(getText(R.string.c_app_name));
|
||||||
|
builder.setContentText(getString(R.string.open_onscreen_calculator));
|
||||||
|
|
||||||
|
final Intent intent = new Intent();
|
||||||
|
intent.setClass(this, getIntentListenerClass());
|
||||||
|
builder.setContentIntent(PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
|
||||||
|
|
||||||
|
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
nm.notify(NOTIFICATION_ID, builder.getNotification());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,393 @@
|
|||||||
|
package org.solovyev.android.calculator.onscreen;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.PixelFormat;
|
||||||
|
import android.text.Html;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
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.widget.WidgetButton;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 11/21/12
|
||||||
|
* Time: 9:03 PM
|
||||||
|
*/
|
||||||
|
public class CalculatorOnscreenView {
|
||||||
|
/*
|
||||||
|
**********************************************************************
|
||||||
|
*
|
||||||
|
* CONSTANTS
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
private static final String TAG = CalculatorOnscreenView.class.getSimpleName();
|
||||||
|
|
||||||
|
/*
|
||||||
|
**********************************************************************
|
||||||
|
*
|
||||||
|
* FIELDS
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private View root;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private View content;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private Context context;
|
||||||
|
|
||||||
|
private int width;
|
||||||
|
|
||||||
|
private int height;
|
||||||
|
|
||||||
|
private int unfoldedHeight;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private String cursorColor;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private OnscreenViewListener viewListener;
|
||||||
|
|
||||||
|
/*
|
||||||
|
**********************************************************************
|
||||||
|
*
|
||||||
|
* STATES
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
private boolean minimized = false;
|
||||||
|
|
||||||
|
private boolean attached = false;
|
||||||
|
|
||||||
|
private boolean folded = false;
|
||||||
|
|
||||||
|
private boolean initialized = false;
|
||||||
|
|
||||||
|
private boolean hidden = true;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
**********************************************************************
|
||||||
|
*
|
||||||
|
* CONSTRUCTORS
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
private CalculatorOnscreenView() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CalculatorOnscreenView newInstance(@NotNull Context context,
|
||||||
|
@NotNull CalculatorOnscreenViewDef def,
|
||||||
|
@NotNull String cursorColor,
|
||||||
|
@Nullable OnscreenViewListener viewListener) {
|
||||||
|
final CalculatorOnscreenView result = new CalculatorOnscreenView();
|
||||||
|
|
||||||
|
result.root = View.inflate(context, R.layout.onscreen_layout, null);
|
||||||
|
result.context = context;
|
||||||
|
result.width = def.getWidth();
|
||||||
|
result.height = def.getHeight();
|
||||||
|
result.cursorColor = cursorColor;
|
||||||
|
result.viewListener = viewListener;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
**********************************************************************
|
||||||
|
*
|
||||||
|
* METHODS
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
public void updateDisplayState(@NotNull CalculatorDisplayViewState displayState) {
|
||||||
|
checkInit();
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateEditorState(@NotNull CalculatorEditorViewState editorState) {
|
||||||
|
checkInit();
|
||||||
|
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=\"#" + cursorColor + "\">|</font>" + text.substring(selection));
|
||||||
|
}
|
||||||
|
calculatorEditorView.setText(newText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setHeight(int height) {
|
||||||
|
checkInit();
|
||||||
|
|
||||||
|
this.height = height;
|
||||||
|
|
||||||
|
final WindowManager.LayoutParams params = (WindowManager.LayoutParams) root.getLayoutParams();
|
||||||
|
|
||||||
|
params.height = height;
|
||||||
|
|
||||||
|
getWindowManager().updateViewLayout(root, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
**********************************************************************
|
||||||
|
*
|
||||||
|
* LIFECYCLE
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
|
||||||
|
if (!initialized) {
|
||||||
|
for (final WidgetButton widgetButton : WidgetButton.values()) {
|
||||||
|
final View button = root.findViewById(widgetButton.getButtonId());
|
||||||
|
if (button != null) {
|
||||||
|
button.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
widgetButton.onClick(context);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||||
|
|
||||||
|
content = root.findViewById(R.id.onscreen_content);
|
||||||
|
|
||||||
|
final View onscreenFoldButton = root.findViewById(R.id.onscreen_fold_button);
|
||||||
|
onscreenFoldButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (folded) {
|
||||||
|
unfold();
|
||||||
|
} else {
|
||||||
|
fold();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
final View onscreenHideButton = root.findViewById(R.id.onscreen_minimize_button);
|
||||||
|
onscreenHideButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
minimize();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
root.findViewById(R.id.onscreen_close_button).setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
final TextView onscreenTitleTextView = (TextView) root.findViewById(R.id.onscreen_title);
|
||||||
|
onscreenTitleTextView.setOnTouchListener(new WindowDragTouchListener(wm, root));
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkInit() {
|
||||||
|
if (!initialized) {
|
||||||
|
throw new IllegalStateException("init() must be called!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void show() {
|
||||||
|
if (hidden) {
|
||||||
|
init();
|
||||||
|
attach();
|
||||||
|
|
||||||
|
hidden = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void attach() {
|
||||||
|
checkInit();
|
||||||
|
|
||||||
|
final WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||||
|
if (!attached) {
|
||||||
|
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
|
||||||
|
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
|
||||||
|
PixelFormat.TRANSLUCENT);
|
||||||
|
|
||||||
|
wm.addView(root, params);
|
||||||
|
attached = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fold() {
|
||||||
|
if (!folded) {
|
||||||
|
final WindowManager.LayoutParams params = (WindowManager.LayoutParams) root.getLayoutParams();
|
||||||
|
unfoldedHeight = params.height;
|
||||||
|
int newHeight = root.findViewById(R.id.onscreen_close_button).getHeight();
|
||||||
|
content.setVisibility(View.GONE);
|
||||||
|
setHeight(newHeight);
|
||||||
|
folded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unfold() {
|
||||||
|
if (folded) {
|
||||||
|
content.setVisibility(View.VISIBLE);
|
||||||
|
setHeight(unfoldedHeight);
|
||||||
|
folded = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void detach() {
|
||||||
|
checkInit();
|
||||||
|
|
||||||
|
if (attached) {
|
||||||
|
getWindowManager().removeView(root);
|
||||||
|
attached = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void minimize() {
|
||||||
|
checkInit();
|
||||||
|
if (!minimized) {
|
||||||
|
detach();
|
||||||
|
|
||||||
|
if (viewListener != null) {
|
||||||
|
viewListener.onViewMinimized();
|
||||||
|
}
|
||||||
|
|
||||||
|
minimized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hide() {
|
||||||
|
checkInit();
|
||||||
|
|
||||||
|
if (!hidden) {
|
||||||
|
|
||||||
|
detach();
|
||||||
|
|
||||||
|
if (viewListener != null) {
|
||||||
|
viewListener.onViewHidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
hidden = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private WindowManager getWindowManager() {
|
||||||
|
return ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public CalculatorOnscreenViewDef getCalculatorOnscreenViewDef() {
|
||||||
|
final WindowManager.LayoutParams params = (WindowManager.LayoutParams) root.getLayoutParams();
|
||||||
|
return CalculatorOnscreenViewDef.newInstance(width, height, params.x, params.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
**********************************************************************
|
||||||
|
*
|
||||||
|
* STATIC
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
private static class WindowDragTouchListener implements View.OnTouchListener {
|
||||||
|
|
||||||
|
private final WindowManager wm;
|
||||||
|
|
||||||
|
private float x0;
|
||||||
|
|
||||||
|
private float y0;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final View view;
|
||||||
|
|
||||||
|
public WindowDragTouchListener(@NotNull WindowManager wm,
|
||||||
|
@NotNull View view) {
|
||||||
|
this.wm = wm;
|
||||||
|
this.view = view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouch(View v, MotionEvent event) {
|
||||||
|
|
||||||
|
//Log.d(TAG, "Action: " + event.getAction());
|
||||||
|
|
||||||
|
final float x1 = event.getX();
|
||||||
|
final float y1 = event.getY();
|
||||||
|
|
||||||
|
switch (event.getAction()) {
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
//Log.d(TAG, "0:" + toString(x0, y0) + ", 1: " + toString(x1, y1));
|
||||||
|
x0 = x1;
|
||||||
|
y0 = y1;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MotionEvent.ACTION_MOVE:
|
||||||
|
final float Δx = x1 - x0;
|
||||||
|
final float Δy = y1 - y0;
|
||||||
|
|
||||||
|
final WindowManager.LayoutParams params = (WindowManager.LayoutParams) view.getLayoutParams();
|
||||||
|
|
||||||
|
//Log.d(TAG, "0:" + toString(x0, y0) + ", 1: " + toString(x1, y1) + ", Δ: " + toString(Δx, Δy) + ", params: " + toString(params.x, params.y));
|
||||||
|
|
||||||
|
params.x = (int) (params.x + Δx);
|
||||||
|
params.y = (int) (params.y + Δy);
|
||||||
|
|
||||||
|
wm.updateViewLayout(view, params);
|
||||||
|
x0 = x1;
|
||||||
|
y0 = y1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static String toString(float x, float y) {
|
||||||
|
return "(" + formatFloat(x) + ", " + formatFloat(y) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String formatFloat(float value) {
|
||||||
|
if (value >= 0) {
|
||||||
|
return "+" + String.format("%.2f", value);
|
||||||
|
} else {
|
||||||
|
return String.format("%.2f", value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
package org.solovyev.android.calculator.onscreen;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 11/21/12
|
||||||
|
* Time: 10:55 PM
|
||||||
|
*/
|
||||||
|
public class CalculatorOnscreenViewDef {
|
||||||
|
|
||||||
|
private int width;
|
||||||
|
private int height;
|
||||||
|
private int x;
|
||||||
|
private int y;
|
||||||
|
|
||||||
|
private CalculatorOnscreenViewDef() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static CalculatorOnscreenViewDef newInstance(int width, int height, int x, int y) {
|
||||||
|
final CalculatorOnscreenViewDef result = new CalculatorOnscreenViewDef();
|
||||||
|
result.width = width;
|
||||||
|
result.height = height;
|
||||||
|
result.x = x;
|
||||||
|
result.y = y;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWidth(int width) {
|
||||||
|
this.width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeight(int height) {
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setX(int x) {
|
||||||
|
this.x = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setY(int y) {
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package org.solovyev.android.calculator.onscreen;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User: serso
|
||||||
|
* Date: 11/21/12
|
||||||
|
* Time: 9:45 PM
|
||||||
|
*/
|
||||||
|
public interface OnscreenViewListener {
|
||||||
|
|
||||||
|
// view minimized == view is in the action bar
|
||||||
|
void onViewMinimized();
|
||||||
|
|
||||||
|
// view hidden == view closed
|
||||||
|
void onViewHidden();
|
||||||
|
}
|
@ -1,253 +0,0 @@
|
|||||||
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.MotionEvent;
|
|
||||||
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.Locator;
|
|
||||||
import org.solovyev.android.calculator.R;
|
|
||||||
import org.solovyev.android.calculator.external.DefaultExternalCalculatorIntentHandler;
|
|
||||||
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 onscreenView;
|
|
||||||
|
|
||||||
@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 WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
|
|
||||||
|
|
||||||
final LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
||||||
onscreenView = layoutInflater.inflate(R.layout.overlay_layout, null);
|
|
||||||
|
|
||||||
for (final WidgetButton widgetButton : WidgetButton.values()) {
|
|
||||||
final View button = onscreenView.findViewById(widgetButton.getButtonId());
|
|
||||||
if (button != null) {
|
|
||||||
button.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
widgetButton.onClick(CalculatorOverlayService.this);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
final int initialWindowWidth = Math.max(wm.getDefaultDisplay().getWidth() / 2, 300);
|
|
||||||
final int initialWindowHeight = Math.max(wm.getDefaultDisplay().getHeight() / 2, 450);
|
|
||||||
|
|
||||||
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
|
|
||||||
initialWindowWidth,
|
|
||||||
initialWindowHeight,
|
|
||||||
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
|
|
||||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL|WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
|
|
||||||
PixelFormat.TRANSLUCENT);
|
|
||||||
|
|
||||||
final View overlayContent = onscreenView.findViewById(R.id.overlay_content);
|
|
||||||
final View overlayHideButton = onscreenView.findViewById(R.id.overlay_hide_button);
|
|
||||||
overlayHideButton.setOnClickListener(new View.OnClickListener() {
|
|
||||||
|
|
||||||
private boolean hidden = false;
|
|
||||||
|
|
||||||
private int windowHeight = initialWindowHeight;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
final WindowManager.LayoutParams params = (WindowManager.LayoutParams) onscreenView.getLayoutParams();
|
|
||||||
if (hidden) {
|
|
||||||
overlayContent.setVisibility(View.VISIBLE);
|
|
||||||
params.height = windowHeight;
|
|
||||||
} else {
|
|
||||||
windowHeight = params.height;
|
|
||||||
overlayContent.setVisibility(View.GONE);
|
|
||||||
params.height = overlayHideButton.getHeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
wm.updateViewLayout(onscreenView, params);
|
|
||||||
|
|
||||||
hidden = !hidden;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
onscreenView.findViewById(R.id.overlay_close_button).setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
stopService(new Intent(getApplicationContext(), CalculatorOverlayService.class));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
final TextView overlayTitleTextView = (TextView) onscreenView.findViewById(R.id.overlay_title);
|
|
||||||
overlayTitleTextView.setOnTouchListener(new View.OnTouchListener() {
|
|
||||||
|
|
||||||
private boolean move = true;
|
|
||||||
|
|
||||||
private float x0;
|
|
||||||
|
|
||||||
private float y0;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onTouch(View v, MotionEvent event) {
|
|
||||||
switch (event.getAction()) {
|
|
||||||
case MotionEvent.ACTION_DOWN:
|
|
||||||
case MotionEvent.ACTION_MOVE:
|
|
||||||
|
|
||||||
if (move) {
|
|
||||||
float xOffset = event.getX() - x0;
|
|
||||||
float yOffset = event.getY() - y0;
|
|
||||||
|
|
||||||
final WindowManager.LayoutParams params = (WindowManager.LayoutParams) onscreenView.getLayoutParams();
|
|
||||||
|
|
||||||
int newX = (int) (params.x + xOffset);
|
|
||||||
int newY = (int) (params.y + yOffset);
|
|
||||||
|
|
||||||
params.x = newX;
|
|
||||||
params.y = newY;
|
|
||||||
wm.updateViewLayout(onscreenView, params);
|
|
||||||
|
|
||||||
if (newX != params.x) {
|
|
||||||
x0 = event.getX();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newY != params.y) {
|
|
||||||
y0 = event.getY();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
move = true;
|
|
||||||
x0 = event.getX();
|
|
||||||
y0 = event.getY();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
move = false;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
wm.addView(onscreenView, params);
|
|
||||||
|
|
||||||
startCalculatorListening();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startCalculatorListening() {
|
|
||||||
Locator.getInstance().getExternalListenersContainer().addExternalListener(getIntentListenerClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private Class<?> getIntentListenerClass() {
|
|
||||||
return CalculatorOverlayBroadcastReceiver.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stopCalculatorListening() {
|
|
||||||
Locator.getInstance().getExternalListenersContainer().removeExternalListener(getIntentListenerClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
stopCalculatorListening();
|
|
||||||
|
|
||||||
if (onscreenView != null) {
|
|
||||||
((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(onscreenView);
|
|
||||||
onscreenView = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
super.onDestroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateState(@NotNull Context context, @NotNull CalculatorEditorViewState editorState, @NotNull CalculatorDisplayViewState displayState) {
|
|
||||||
final View root = this.onscreenView;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user