Merge branch 'call_notifications' of https://github.com/tomerf/Kore into tomerf-call_notifications

This commit is contained in:
Synced Synapse 2016-05-20 10:24:58 +01:00
commit faab6b8163
8 changed files with 201 additions and 8 deletions

View File

@ -9,6 +9,7 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<application
android:allowBackup="true"

View File

@ -69,6 +69,10 @@ public class Settings {
public static final String KEY_PREF_SHOW_NOTIFICATION = "pref_show_notification";
public static final boolean DEFAULT_PREF_SHOW_NOTIFICATION = false;
// Pause during calls
public static final String KEY_PREF_PAUSE_DURING_CALLS = "pref_pause_during_calls";
public static final boolean DEFAULT_PREF_PAUSE_DURING_CALLS = false;
// Other keys used in preferences.xml
public static final String KEY_PREF_ABOUT = "pref_about";

View File

@ -64,15 +64,27 @@ public abstract class ApiMethod<T> {
* Constructor, sets up the necessary items to make the call later
*/
public ApiMethod() {
synchronized (this) {
this.id = (++lastId % 10000);
}
this(true);
}
/**
* Constructor, sets up the necessary items to make the call later
*/
public ApiMethod(boolean sendId) {
// Create the rpc request object with the common fields according to JSON RPC spec
jsonRequest = objectMapper.createObjectNode();
jsonRequest.put("jsonrpc", "2.0");
jsonRequest.put(METHOD_NODE, getMethodName());
jsonRequest.put(ID_NODE, id);
if(sendId) {
synchronized (this) {
this.id = (++lastId % 10000);
}
jsonRequest.put(ID_NODE, id);
}
else {
id = -1;
}
}
/**

View File

@ -116,7 +116,6 @@ public class Player {
}
}
/**
* Pauses or unpause playback and returns the new state
*/
@ -493,4 +492,29 @@ public class Player {
}
}
/**
* Send notification message to XBMC/Kodi
*/
public static final class Notification extends ApiMethod<String> {
public final static String METHOD_NAME = "GUI.ShowNotification";
/**
* Sends a text notification message to XBMC/Kodi
* @param title The title of the notification
* @param message The text message of the notification
*/
public Notification(String title, String message) {
super(false);
addParameterToRequest("title", title);
addParameterToRequest("message", message);
}
@Override
public String getMethodName() { return METHOD_NAME; }
@Override
public String resultFromJson(ObjectNode jsonObject) throws ApiException {
return jsonObject.get(RESULT_NODE).textValue();
}
}
}

View File

@ -0,0 +1,118 @@
/*
* Copyright 2016 Tomer Froumin. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.xbmc.kore.service;
import android.content.Context;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import org.xbmc.kore.R;
import org.xbmc.kore.host.HostConnectionObserver;
import org.xbmc.kore.host.HostManager;
import org.xbmc.kore.jsonrpc.method.Player;
import org.xbmc.kore.jsonrpc.type.ListType;
import org.xbmc.kore.jsonrpc.type.PlayerType;
import org.xbmc.kore.utils.LogUtils;
/**
* This listener handles changes to the phone state, such as receiving a
* call or hanging up, and synchronizes Kodi's currently playing state
* in order to prevent missing the movie (or what's playing) while the
* viewer is talking on the phone.
*
* The listener query Kodi's state on phone state changed event.
* When a call ends we only resume if it was paused by the listener.
*/
public class PauseCallService extends PhoneStateListener
implements HostConnectionObserver.PlayerEventsObserver {
public static final String TAG = LogUtils.makeLogTag(PauseCallService.class);
private Context context;
private int currentActivePlayerId = -1;
private boolean isPlaying = false;
private boolean shouldResume = false;
public PauseCallService(Context context) {
this.context = context;
}
@Override
public void onCallStateChanged(int state, String incomingNumber) {
// We won't create a new thread because the request to the host are
// already done in a separate thread. Just fire the request and forget
HostManager hostManager = HostManager.getInstance(context);
hostManager.getHostConnectionObserver().replyWithLastResult(this);
if (state == TelephonyManager.CALL_STATE_OFFHOOK && isPlaying) {
Player.PlayPause action = new Player.PlayPause(currentActivePlayerId);
action.execute(hostManager.getConnection(), null, null);
shouldResume = true;
} else if (state == TelephonyManager.CALL_STATE_IDLE && !isPlaying && shouldResume) {
Player.PlayPause action = new Player.PlayPause(currentActivePlayerId);
action.execute(hostManager.getConnection(), null, null);
shouldResume = false;
} else if (state == TelephonyManager.CALL_STATE_RINGING) {
Player.Notification action = new Player.Notification(
context.getResources().getString(R.string.pause_call_incoming_title),
context.getResources().getString(R.string.pause_call_incoming_message));
action.execute(hostManager.getConnection(), null, null);
}
}
@Override
public void playerOnPlay(PlayerType.GetActivePlayersReturnType getActivePlayerResult,
PlayerType.PropertyValue getPropertiesResult,
ListType.ItemsAll getItemResult) {
currentActivePlayerId = getActivePlayerResult.playerid;
isPlaying = true;
}
@Override
public void playerOnPause(PlayerType.GetActivePlayersReturnType getActivePlayerResult,
PlayerType.PropertyValue getPropertiesResult,
ListType.ItemsAll getItemResult) {
if(currentActivePlayerId != getActivePlayerResult.playerid) {
shouldResume = false;
}
currentActivePlayerId = getActivePlayerResult.playerid;
isPlaying = false;
}
@Override
public void playerOnStop() {
currentActivePlayerId = -1;
isPlaying = false;
shouldResume = false;
}
@Override
public void playerOnConnectionError(int errorCode, String description) {
playerOnStop();
}
@Override
public void playerNoResultsYet() {
playerOnStop();
}
@Override
public void systemOnQuit() {}
@Override
public void inputOnInputRequested(String title, String type, String value) {}
@Override
public void observerOnStopObserving() {}
}

View File

@ -15,6 +15,7 @@
*/
package org.xbmc.kore.ui;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Point;
@ -27,6 +28,8 @@ import android.support.v4.view.ViewPager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.Toolbar;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.Menu;
@ -38,9 +41,7 @@ import android.widget.Toast;
import org.xbmc.kore.R;
import org.xbmc.kore.Settings;
import org.xbmc.kore.eventclient.EventServerConnection;
import org.xbmc.kore.host.HostConnectionObserver;
import org.xbmc.kore.host.HostInfo;
import org.xbmc.kore.host.HostManager;
import org.xbmc.kore.jsonrpc.ApiCallback;
import org.xbmc.kore.jsonrpc.HostConnection;
@ -57,6 +58,7 @@ import org.xbmc.kore.jsonrpc.type.ListType;
import org.xbmc.kore.jsonrpc.type.PlayerType;
import org.xbmc.kore.jsonrpc.type.PlaylistType;
import org.xbmc.kore.service.NotificationService;
import org.xbmc.kore.service.PauseCallService;
import org.xbmc.kore.ui.hosts.AddHostActivity;
import org.xbmc.kore.ui.hosts.AddHostFragmentFinish;
import org.xbmc.kore.ui.views.CirclePageIndicator;
@ -97,6 +99,8 @@ public class RemoteActivity extends BaseActivity
private NavigationDrawerFragment navigationDrawerFragment;
private PauseCallService pauseCallService = null;
@InjectView(R.id.background_image) ImageView backgroundImage;
@InjectView(R.id.pager_indicator) CirclePageIndicator pageIndicator;
@InjectView(R.id.pager) ViewPager viewPager;
@ -621,12 +625,28 @@ public class RemoteActivity extends BaseActivity
// Check whether we should show a notification
boolean showNotification = PreferenceManager
.getDefaultSharedPreferences(this)
.getBoolean(Settings.KEY_PREF_SHOW_NOTIFICATION, Settings.DEFAULT_PREF_SHOW_NOTIFICATION);
.getBoolean(Settings.KEY_PREF_SHOW_NOTIFICATION,
Settings.DEFAULT_PREF_SHOW_NOTIFICATION);
if (showNotification) {
// Let's start the notification service
LogUtils.LOGD(TAG, "Starting notification service");
startService(new Intent(this, NotificationService.class));
}
// Check whether we should react to phone state changes
boolean shouldPause = PreferenceManager
.getDefaultSharedPreferences(this)
.getBoolean(Settings.KEY_PREF_USE_HARDWARE_VOLUME_KEYS,
Settings.DEFAULT_PREF_USE_HARDWARE_VOLUME_KEYS);
if (shouldPause) {
// Let's start the notification service
LogUtils.LOGD(TAG, "Starting phone state listener");
if(pauseCallService == null) {
pauseCallService = new PauseCallService(this);
((TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE)).listen(
pauseCallService, PhoneStateListener.LISTEN_CALL_STATE);
}
}
}
public void playerOnPause(PlayerType.GetActivePlayersReturnType getActivePlayerResult,
@ -640,6 +660,12 @@ public class RemoteActivity extends BaseActivity
setImageViewBackground(null);
}
lastImageUrl = null;
if(pauseCallService != null) {
((TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE)).listen(
pauseCallService, PhoneStateListener.LISTEN_NONE);
pauseCallService = null;
}
}
public void playerNoResultsYet() {

View File

@ -327,6 +327,7 @@
<string name="switch_to_remote">Switch to remote after media start</string>
<string name="keep_remote_above_lockscreen">Keep remote above lockscreen</string>
<string name="show_notification">Show notification while playing</string>
<string name="pause_during_calls">Pause playing while phone in a call</string>
<string name="use_hardware_volume_keys">Use volume keys to control volume</string>
<string name="vibrate_on_remote">Vibrate on remote button press</string>
<string name="nav_drawer_items">Side menu shortcuts</string>
@ -352,6 +353,8 @@
<!--<string name="purchase_thanks">Thanks for your support!</string>-->
<string name="play_on_kodi">Play on Kodi</string>
<string name="pause_call_incoming_title">Incoming call</string>
<string name="pause_call_incoming_message">Check your phone, someone is calling you</string>
<string name="error_getting_pvr_info">An error occurred while getting pvr info: %1$s</string>
<string name="might_not_have_pvr">An error occurred while getting channels info, probably because your media center doesn\'t have a tuner or it isn\'t configured.\n\nIf that\'s the case and you\'d like to remove this entry from the side menu, you can do it in the Settings.</string>

View File

@ -39,6 +39,11 @@
android:title="@string/show_notification"
android:defaultValue="false"/>
<CheckBoxPreference
android:key="pref_pause_during_calls"
android:title="@string/pause_during_calls"
android:defaultValue="false"/>
<CheckBoxPreference
android:key="pref_use_hardware_volume_keys"
android:title="@string/use_hardware_volume_keys"