Merge branch 'call_notifications' of https://github.com/tomerf/Kore into tomerf-call_notifications
This commit is contained in:
commit
faab6b8163
|
@ -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"
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {}
|
||||
}
|
|
@ -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() {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue