Skip to content
This repository has been archived by the owner on Nov 8, 2023. It is now read-only.

Commit

Permalink
Telephony API extension v2
Browse files Browse the repository at this point in the history
Added new AndroidManifest permission:

android.permission.READ_PRECISE_PHONE_STATE

Added the following PhoneStateListeners and corresponding broadcast intents:

onPreciseCallStateChanged(PreciseCallState callState);
onPreciseDataConnectionStateChanged(PreciseDataConnectionState dataConnectionState);

broadcastPreciseCallStateChanged(int ringingCallState, int foregroundCallState, int backgroundCallState,
	int disconnectCause, int preciseDisconnectCause)
broadcastPreciseDataConnectionStateChanged(int state, int networkType, String apnType, String apn,
	String reason, LinkProperties linkProperties, String failCause)

Added TelephonyManager intent actions with their extras and constants:

public static final String ACTION_PRECISE_CALL_STATE_CHANGED = "android.intent.action.PRECISE_CALL_STATE";
public static final String ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED = "android.intent.action.PRECISE_DATA_CONNECTION_STATE_CHANGED";

public static final int PRECISE_CALL_STATE_*

Moved public static final int DISCONNECT_CAUSE_* from PreciseCallState.java to a new class DisconnectCause.java

Moved public static final int PRECISE_DISCONNECT_CAUSE_* from PreciseCallState.java to a new class PreciseDisconnectCause.java

Change-Id: If3b88c679507c529b746046c4a17cf6d9974bd09
  • Loading branch information
Antonio Marín Cerezuela committed Jan 10, 2014
1 parent de8c3cf commit c5ac15a
Show file tree
Hide file tree
Showing 14 changed files with 1,351 additions and 10 deletions.
8 changes: 8 additions & 0 deletions core/res/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,14 @@
android:label="@string/permlab_readPhoneState"
android:description="@string/permdesc_readPhoneState" />

<!-- Allows read only access to precise phone state.
@hide Pending API council approval -->
<permission android:name="android.permission.READ_PRECISE_PHONE_STATE"
android:permissionGroup="android.permission-group.PHONE_CALLS"
android:protectionLevel="dangerous"
android:label="@string/permlab_readPrecisePhoneState"
android:description="@string/permdesc_readPrecisePhoneState" />

<!-- Allows read access to privileged phone state.
@hide Used internally. -->
<permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
Expand Down
8 changes: 8 additions & 0 deletions core/res/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1638,6 +1638,14 @@
phone number and device IDs, whether a call is active, and the remote number
connected by a call.</string>

<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_readPrecisePhoneState">read precise phone states</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_readPrecisePhoneState">Allows the app to access the precise
phone states. This permission allows the app to determine the real
call status, whether a call is active or in the background, call fails,
precise data connection status and data connection fails.</string>

<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_wakeLock" product="tablet">prevent tablet from sleeping</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
Expand Down
179 changes: 169 additions & 10 deletions services/java/com/android/server/TelephonyRegistry.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
import android.telephony.SignalStrength;
import android.telephony.CellInfo;
import android.telephony.TelephonyManager;
import android.telephony.DisconnectCause;
import android.telephony.PreciseCallState;
import android.telephony.PreciseDataConnectionState;
import android.telephony.PreciseDisconnectCause;
import android.text.TextUtils;
import android.util.Slog;

Expand Down Expand Up @@ -125,13 +129,28 @@ public String toString() {

private List<CellInfo> mCellInfo = null;

private int mRingingCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;

private int mForegroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;

private int mBackgroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;

private PreciseCallState mPreciseCallState = new PreciseCallState();

private PreciseDataConnectionState mPreciseDataConnectionState =
new PreciseDataConnectionState();

static final int PHONE_STATE_PERMISSION_MASK =
PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |
PhoneStateListener.LISTEN_CALL_STATE |
PhoneStateListener.LISTEN_DATA_ACTIVITY |
PhoneStateListener.LISTEN_DATA_CONNECTION_STATE |
PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR;

static final int PRECISE_PHONE_STATE_PERMISSION_MASK =
PhoneStateListener.LISTEN_PRECISE_CALL_STATE |
PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE;

private static final int MSG_USER_SWITCHED = 1;

private final Handler mHandler = new Handler() {
Expand Down Expand Up @@ -305,6 +324,21 @@ public void listen(String pkgForDebug, IPhoneStateListener callback, int events,
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
try {
r.callback.onPreciseCallStateChanged(mPreciseCallState);
} catch (RemoteException ex) {
remove(r.binder);
}
}
if ((events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
try {
r.callback.onPreciseDataConnectionStateChanged(
mPreciseDataConnectionState);
} catch (RemoteException ex) {
remove(r.binder);
}
}
}
}
} else {
Expand Down Expand Up @@ -533,30 +567,47 @@ public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
}
handleRemoveListLocked();
}
mPreciseDataConnectionState = new PreciseDataConnectionState(state, networkType,
apnType, apn, reason, linkProperties, "");
for (Record r : mRecords) {
if ((r.events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
try {
r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
}
}
handleRemoveListLocked();
}
broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
apnType, linkProperties, linkCapabilities, roaming);
broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn, reason,
linkProperties, "");
}

public void notifyDataConnectionFailed(String reason, String apnType) {
if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
return;
}
/*
* This is commented out because there is no onDataConnectionFailed callback
* in PhoneStateListener. There should be.
synchronized (mRecords) {
mDataConnectionFailedReason = reason;
final int N = mRecords.size();
for (int i=N-1; i>=0; i--) {
Record r = mRecords.get(i);
if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_FAILED) != 0) {
// XXX
mPreciseDataConnectionState = new PreciseDataConnectionState(
TelephonyManager.DATA_UNKNOWN,TelephonyManager.NETWORK_TYPE_UNKNOWN,
apnType, "", reason, null, "");
for (Record r : mRecords) {
if ((r.events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
try {
r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
}
}
handleRemoveListLocked();
}
*/
broadcastDataConnectionFailed(reason, apnType);
broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, "", reason, null, "");
}

public void notifyCellLocation(Bundle cellLocation) {
Expand Down Expand Up @@ -602,6 +653,81 @@ public void notifyOtaspChanged(int otaspMode) {
}
}

public void notifyPreciseCallState(int ringingCallState, int foregroundCallState,
int backgroundCallState) {
if (!checkNotifyPermission("notifyPreciseCallState()")) {
return;
}
synchronized (mRecords) {
mRingingCallState = ringingCallState;
mForegroundCallState = foregroundCallState;
mBackgroundCallState = backgroundCallState;
mPreciseCallState = new PreciseCallState(ringingCallState, foregroundCallState,
backgroundCallState,
DisconnectCause.NOT_VALID,
PreciseDisconnectCause.NOT_VALID);
for (Record r : mRecords) {
if ((r.events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
try {
r.callback.onPreciseCallStateChanged(mPreciseCallState);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
}
}
handleRemoveListLocked();
}
broadcastPreciseCallStateChanged(ringingCallState, foregroundCallState, backgroundCallState,
DisconnectCause.NOT_VALID,
PreciseDisconnectCause.NOT_VALID);
}

public void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause) {
if (!checkNotifyPermission("notifyDisconnectCause()")) {
return;
}
synchronized (mRecords) {
mPreciseCallState = new PreciseCallState(mRingingCallState, mForegroundCallState,
mBackgroundCallState, disconnectCause, preciseDisconnectCause);
for (Record r : mRecords) {
if ((r.events & PhoneStateListener.LISTEN_PRECISE_CALL_STATE) != 0) {
try {
r.callback.onPreciseCallStateChanged(mPreciseCallState);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
}
}
handleRemoveListLocked();
}
broadcastPreciseCallStateChanged(mRingingCallState, mForegroundCallState,
mBackgroundCallState, disconnectCause, preciseDisconnectCause);
}

public void notifyPreciseDataConnectionFailed(String reason, String apnType,
String apn, String failCause) {
if (!checkNotifyPermission("notifyPreciseDataConnectionFailed()")) {
return;
}
synchronized (mRecords) {
mPreciseDataConnectionState = new PreciseDataConnectionState(
TelephonyManager.DATA_UNKNOWN, TelephonyManager.NETWORK_TYPE_UNKNOWN,
apnType, apn, reason, null, failCause);
for (Record r : mRecords) {
if ((r.events & PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) != 0) {
try {
r.callback.onPreciseDataConnectionStateChanged(mPreciseDataConnectionState);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
}
}
handleRemoveListLocked();
}
broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN,
TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, apn, reason, null, failCause);
}

@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
Expand Down Expand Up @@ -738,6 +864,33 @@ private void broadcastDataConnectionFailed(String reason, String apnType) {
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}

private void broadcastPreciseCallStateChanged(int ringingCallState, int foregroundCallState,
int backgroundCallState, int disconnectCause, int preciseDisconnectCause) {
Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_CALL_STATE_CHANGED);
intent.putExtra(TelephonyManager.EXTRA_RINGING_CALL_STATE, ringingCallState);
intent.putExtra(TelephonyManager.EXTRA_FOREGROUND_CALL_STATE, foregroundCallState);
intent.putExtra(TelephonyManager.EXTRA_BACKGROUND_CALL_STATE, backgroundCallState);
intent.putExtra(TelephonyManager.EXTRA_DISCONNECT_CAUSE, disconnectCause);
intent.putExtra(TelephonyManager.EXTRA_PRECISE_DISCONNECT_CAUSE, preciseDisconnectCause);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
android.Manifest.permission.READ_PRECISE_PHONE_STATE);
}

private void broadcastPreciseDataConnectionStateChanged(int state, int networkType,
String apnType, String apn, String reason, LinkProperties linkProperties, String failCause) {
Intent intent = new Intent(TelephonyManager.ACTION_PRECISE_DATA_CONNECTION_STATE_CHANGED);
intent.putExtra(PhoneConstants.STATE_KEY, state);
intent.putExtra(PhoneConstants.DATA_NETWORK_TYPE_KEY, networkType);
if (reason != null) intent.putExtra(PhoneConstants.STATE_CHANGE_REASON_KEY, reason);
if (apnType != null) intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
if (apn != null) intent.putExtra(PhoneConstants.DATA_APN_KEY, apn);
if (linkProperties != null) intent.putExtra(PhoneConstants.DATA_LINK_PROPERTIES_KEY, linkProperties);
if (failCause != null) intent.putExtra(PhoneConstants.DATA_FAILURE_CAUSE_KEY, failCause);

mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
android.Manifest.permission.READ_PRECISE_PHONE_STATE);
}

private boolean checkNotifyPermission(String method) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
== PackageManager.PERMISSION_GRANTED) {
Expand Down Expand Up @@ -766,6 +919,12 @@ private void checkListenerPermission(int events) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_PHONE_STATE, null);
}

if ((events & PRECISE_PHONE_STATE_PERMISSION_MASK) != 0) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_PRECISE_PHONE_STATE, null);

}
}

private void handleRemoveListLocked() {
Expand Down
108 changes: 108 additions & 0 deletions telephony/java/android/telephony/DisconnectCause.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* 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 android.telephony;

/**
* Contains disconnect call causes generated by the
* framework and the RIL.
*
* @hide
*/
public class DisconnectCause {

/** The disconnect cause is not valid (Not received a disconnect cause) */
public static final int NOT_VALID = -1;
/** Has not yet disconnected */
public static final int NOT_DISCONNECTED = 0;
/** An incoming call that was missed and never answered */
public static final int INCOMING_MISSED = 1;
/** Normal; Remote hangup*/
public static final int NORMAL = 2;
/** Normal; Local hangup */
public static final int LOCAL = 3;
/** Outgoing call to busy line */
public static final int BUSY = 4;
/** Outgoing call to congested network */
public static final int CONGESTION = 5;
/** Not presently used */
public static final int MMI = 6;
/** Invalid dial string */
public static final int INVALID_NUMBER = 7;
/** Cannot reach the peer */
public static final int NUMBER_UNREACHABLE = 8;
/** Cannot reach the server */
public static final int SERVER_UNREACHABLE = 9;
/** Invalid credentials */
public static final int INVALID_CREDENTIALS = 10;
/** Calling from out of network is not allowed */
public static final int OUT_OF_NETWORK = 11;
/** Server error */
public static final int SERVER_ERROR = 12;
/** Client timed out */
public static final int TIMED_OUT = 13;
/** Client went out of network range */
public static final int LOST_SIGNAL = 14;
/** GSM or CDMA ACM limit exceeded */
public static final int LIMIT_EXCEEDED = 15;
/** An incoming call that was rejected */
public static final int INCOMING_REJECTED = 16;
/** Radio is turned off explicitly */
public static final int POWER_OFF = 17;
/** Out of service */
public static final int OUT_OF_SERVICE = 18;
/** No ICC, ICC locked, or other ICC error */
public static final int ICC_ERROR = 19;
/** Call was blocked by call barring */
public static final int CALL_BARRED = 20;
/** Call was blocked by fixed dial number */
public static final int FDN_BLOCKED = 21;
/** Call was blocked by restricted all voice access */
public static final int CS_RESTRICTED = 22;
/** Call was blocked by restricted normal voice access */
public static final int CS_RESTRICTED_NORMAL = 23;
/** Call was blocked by restricted emergency voice access */
public static final int CS_RESTRICTED_EMERGENCY = 24;
/** Unassigned number */
public static final int UNOBTAINABLE_NUMBER = 25;
/** MS is locked until next power cycle */
public static final int CDMA_LOCKED_UNTIL_POWER_CYCLE = 26;
/** Drop call*/
public static final int CDMA_DROP = 27;
/** INTERCEPT order received, MS state idle entered */
public static final int CDMA_INTERCEPT = 28;
/** MS has been redirected, call is cancelled */
public static final int CDMA_REORDER = 29;
/** Service option rejection */
public static final int CDMA_SO_REJECT = 30;
/** Requested service is rejected, retry delay is set */
public static final int CDMA_RETRY_ORDER = 31;
/** Unable to obtain access to the CDMA system */
public static final int CDMA_ACCESS_FAILURE = 32;
/** Not a preempted call */
public static final int CDMA_PREEMPTED = 33;
/** Not an emergency call */
public static final int CDMA_NOT_EMERGENCY = 34;
/** Access Blocked by CDMA network */
public static final int CDMA_ACCESS_BLOCKED = 35;
/** Unknown error or not specified */
public static final int ERROR_UNSPECIFIED = 36;

/** Private constructor to avoid class instantiation. */
private DisconnectCause() {
// Do nothing.
}
}
Loading

0 comments on commit c5ac15a

Please sign in to comment.