NavitTraff.java (navit-0.5.5) | : | NavitTraff.java (navit-0.5.6) | ||
---|---|---|---|---|
skipping to change at line 28 | skipping to change at line 28 | |||
*/ | */ | |||
package org.navitproject.navit; | package org.navitproject.navit; | |||
import android.Manifest; | import android.Manifest; | |||
import android.content.BroadcastReceiver; | import android.content.BroadcastReceiver; | |||
import android.content.ComponentName; | import android.content.ComponentName; | |||
import android.content.Context; | import android.content.Context; | |||
import android.content.Intent; | import android.content.Intent; | |||
import android.content.IntentFilter; | import android.content.IntentFilter; | |||
import android.content.IntentFilter.MalformedMimeTypeException; | ||||
import android.content.pm.PackageManager; | import android.content.pm.PackageManager; | |||
import android.content.pm.ResolveInfo; | import android.content.pm.ResolveInfo; | |||
import android.database.Cursor; | ||||
import android.net.Uri; | ||||
import android.os.Bundle; | ||||
import android.util.Log; | import android.util.Log; | |||
import java.util.HashMap; | ||||
import java.util.Iterator; | ||||
import java.util.List; | import java.util.List; | |||
import java.util.Map; | ||||
/** | /** | |||
* The TraFF receiver implementation. | * The TraFF receiver implementation. | |||
* | * | |||
* <p>This class registers the broadcast receiver for TraFF feeds, polls all reg istered sources once on creation, | * <p>This class registers the broadcast receiver for TraFF feeds, polls all reg istered sources once on creation, | |||
* receives TraFF feeds and forwards them to the traffic module for processing.< /p> | * receives TraFF feeds and forwards them to the traffic module for processing.< /p> | |||
*/ | */ | |||
public class NavitTraff extends BroadcastReceiver { | public class NavitTraff extends BroadcastReceiver { | |||
private static final String ACTION_TRAFF_GET_CAPABILITIES = "org.traffxml.tr | ||||
aff.GET_CAPABILITIES"; | ||||
private static final String ACTION_TRAFF_HEARTBEAT = "org.traffxml.traff.HEA | ||||
RTBEAT"; | ||||
private static final String ACTION_TRAFF_FEED = "org.traffxml.traff.FEED"; | private static final String ACTION_TRAFF_FEED = "org.traffxml.traff.FEED"; | |||
private static final String ACTION_TRAFF_POLL = "org.traffxml.traff.POLL"; | private static final String ACTION_TRAFF_POLL = "org.traffxml.traff.POLL"; | |||
private static final String ACTION_TRAFF_SUBSCRIBE = "org.traffxml.traff.SUB | ||||
SCRIBE"; | ||||
private static final String ACTION_TRAFF_SUBSCRIPTION_CHANGE = "org.traffxml | ||||
.traff.SUBSCRIPTION_CHANGE"; | ||||
private static final String ACTION_TRAFF_UNSUBSCRIBE = "org.traffxml.traff.U | ||||
NSUBSCRIBE"; | ||||
private static final String COLUMN_DATA = "data"; | ||||
private static final String CONTENT_SCHEMA = "content"; | ||||
private static final String[] ERROR_STRINGS = { | ||||
"unknown (0)", | ||||
"invalid request (1)", | ||||
"subscription rejected by the source (2)", | ||||
"requested area not covered (3)", | ||||
"requested area partially covered (4)", | ||||
"subscription ID not recognized by the source (5)", | ||||
"unknown (6)", | ||||
"source reported an internal error (7)" | ||||
}; | ||||
private static final String EXTRA_CAPABILITIES = "capabilities"; | ||||
private static final String EXTRA_FEED = "feed"; | private static final String EXTRA_FEED = "feed"; | |||
private static final String EXTRA_FILTER_LIST = "filter_list"; | ||||
private static final String EXTRA_PACKAGE = "package"; | ||||
private static final String EXTRA_SUBSCRIPTION_ID = "subscription_id"; | ||||
private static final String MIME_TYPE_TRAFF = "vnd.android.cursor.dir/org.tr | ||||
affxml.message"; | ||||
private static final int RESULT_OK = -1; | ||||
private static final int RESULT_INTERNAL_ERROR = 7; | ||||
private static final int RESULT_INVALID = 1; | ||||
private static final int RESULT_SUBSCRIPTION_REJECTED = 2; | ||||
private static final int RESULT_NOT_COVERED = 3; | ||||
private static final int RESULT_PARTIALLY_COVERED = 4; | ||||
private static final int RESULT_SUBSCRIPTION_UNKNOWN = 5; | ||||
private static final String TAG = "NavitTraff"; | ||||
private final long mCbid; | private final long mCbid; | |||
private final Context context; | ||||
/** Active subscriptions (key is the subscription ID, value is the package I | ||||
D). */ | ||||
private Map<String, String> subscriptions = new HashMap<String, String>(); | ||||
/** | /** | |||
* Forwards a newly received TraFF feed to the traffic module for processing . | * Forwards a newly received TraFF feed to the traffic module for processing . | |||
* | * | |||
* <p>This is called when a TraFF feed is received.</p> | * <p>This is called when a TraFF feed is received.</p> | |||
* | * | |||
* @param id The identifier for the native callback implementation | * @param id The identifier for the native callback implementation | |||
* @param feed The TraFF feed | * @param feed The TraFF feed | |||
*/ | */ | |||
public native void onFeedReceived(long id, String feed); | public native void onFeedReceived(long id, String feed); | |||
skipping to change at line 68 | skipping to change at line 110 | |||
* Creates a new {@code NavitTraff} instance. | * Creates a new {@code NavitTraff} instance. | |||
* | * | |||
* <p>Creating a new {@code NavitTraff} instance registers a broadcast recei ver for TraFF broadcasts and polls all | * <p>Creating a new {@code NavitTraff} instance registers a broadcast recei ver for TraFF broadcasts and polls all | |||
* registered sources once to ensure we have messages which were received by these sources before we started up.</p> | * registered sources once to ensure we have messages which were received by these sources before we started up.</p> | |||
* | * | |||
* @param context The context | * @param context The context | |||
* @param cbid The callback identifier for the native method to call upon re ceiving a feed | * @param cbid The callback identifier for the native method to call upon re ceiving a feed | |||
*/ | */ | |||
NavitTraff(Context context, long cbid) { | NavitTraff(Context context, long cbid) { | |||
this.mCbid = cbid; | this.mCbid = cbid; | |||
this.context = context.getApplicationContext(); | ||||
/* An intent filter for TraFF events. */ | /* An intent filter for TraFF 0.7 events. */ | |||
IntentFilter traffFilter = new IntentFilter(); | IntentFilter traffFilter07 = new IntentFilter(); | |||
traffFilter.addAction(ACTION_TRAFF_FEED); | traffFilter07.addAction(ACTION_TRAFF_FEED); | |||
traffFilter.addAction(ACTION_TRAFF_POLL); | ||||
/* An intent filter for TraFF 0.8 events. */ | ||||
IntentFilter traffFilter08 = new IntentFilter(); | ||||
traffFilter08.addAction(ACTION_TRAFF_FEED); | ||||
traffFilter08.addDataScheme(CONTENT_SCHEMA); | ||||
try { | ||||
traffFilter08.addDataType(MIME_TYPE_TRAFF); | ||||
} catch (MalformedMimeTypeException e) { | ||||
// as long as the constant is a well-formed MIME type, this exceptio | ||||
n never gets thrown | ||||
e.printStackTrace(); | ||||
} | ||||
context.registerReceiver(this, traffFilter); | this.context.registerReceiver(this, traffFilter07); | |||
/* TODO unregister receiver on exit */ | this.context.registerReceiver(this, traffFilter08); | |||
/* Broadcast a poll intent */ | /* Broadcast a poll intent to all TraFF 0.7-only receivers */ | |||
Intent outIntent = new Intent(ACTION_TRAFF_POLL); | Intent outIntent = new Intent(ACTION_TRAFF_POLL); | |||
PackageManager pm = context.getPackageManager(); | PackageManager pm = this.context.getPackageManager(); | |||
List<ResolveInfo> receivers = pm.queryBroadcastReceivers(outIntent, 0); | List<ResolveInfo> receivers07 = pm.queryBroadcastReceivers(outIntent, 0) | |||
if (receivers != null) { | ; | |||
for (ResolveInfo receiver : receivers) { | List<ResolveInfo> receivers08 = pm.queryBroadcastReceivers(new Intent(AC | |||
TION_TRAFF_GET_CAPABILITIES), 0); | ||||
if (receivers07 != null) { | ||||
/* get receivers which support only TraFF 0.7 and poll them */ | ||||
if (receivers08 != null) | ||||
receivers07.removeAll(receivers08); | ||||
for (ResolveInfo receiver : receivers07) { | ||||
ComponentName cn = new ComponentName(receiver.activityInfo.appli cationInfo.packageName, | ComponentName cn = new ComponentName(receiver.activityInfo.appli cationInfo.packageName, | |||
receiver.activityInfo.name); | receiver.activityInfo.name); | |||
outIntent = new Intent(ACTION_TRAFF_POLL); | outIntent = new Intent(ACTION_TRAFF_POLL); | |||
outIntent.setComponent(cn); | outIntent.setComponent(cn); | |||
context.sendBroadcast(outIntent, Manifest.permission.ACCESS_COAR | this.context.sendBroadcast(outIntent, Manifest.permission.ACCESS | |||
SE_LOCATION); | _COARSE_LOCATION); | |||
} | ||||
} | ||||
} | ||||
void close() { | ||||
for (Map.Entry<String, String> subscription : subscriptions.entrySet()) | ||||
{ | ||||
Bundle extras = new Bundle(); | ||||
extras.putString(EXTRA_SUBSCRIPTION_ID, subscription.getKey()); | ||||
sendTraffIntent(this.context, ACTION_TRAFF_UNSUBSCRIBE, null, extras | ||||
, subscription.getValue(), | ||||
Manifest.permission.ACCESS_COARSE_LOCATION, this); | ||||
} | ||||
this.context.unregisterReceiver(this); | ||||
} | ||||
void onFilterUpdate(String filterList) { | ||||
/* change existing subscriptions */ | ||||
for (Map.Entry<String, String> entry : subscriptions.entrySet()) { | ||||
Log.d(TAG, String.format("changing subscription %s (%s)", entry.getK | ||||
ey(), entry.getValue())); | ||||
Bundle extras = new Bundle(); | ||||
extras.putString(EXTRA_SUBSCRIPTION_ID, entry.getKey()); | ||||
extras.putString(EXTRA_FILTER_LIST, filterList); | ||||
sendTraffIntent(context, ACTION_TRAFF_SUBSCRIPTION_CHANGE, null, ext | ||||
ras, | ||||
entry.getValue(), | ||||
Manifest.permission.ACCESS_COARSE_LOCATION, this); | ||||
} | ||||
/* set up missing subscriptions */ | ||||
PackageManager pm = this.context.getPackageManager(); | ||||
List<ResolveInfo> receivers = pm.queryBroadcastReceivers(new Intent(ACTI | ||||
ON_TRAFF_GET_CAPABILITIES), 0); | ||||
if (receivers != null) { | ||||
/* filter out receivers to which we are already subscribed */ | ||||
Iterator<ResolveInfo> iter = receivers.iterator(); | ||||
while (iter.hasNext()) { | ||||
ResolveInfo receiver = iter.next(); | ||||
if (subscriptions.containsValue(receiver.activityInfo.applicatio | ||||
nInfo.packageName)) | ||||
iter.remove(); | ||||
} | ||||
for (ResolveInfo receiver : receivers) { | ||||
Log.d(TAG, "subscribing to " + receiver.activityInfo.application | ||||
Info.packageName); | ||||
Bundle extras = new Bundle(); | ||||
extras.putString(EXTRA_PACKAGE, context.getPackageName()); | ||||
extras.putString(EXTRA_FILTER_LIST, filterList); | ||||
sendTraffIntent(context, ACTION_TRAFF_SUBSCRIBE, null, extras, | ||||
receiver.activityInfo.applicationInfo.packageName, | ||||
Manifest.permission.ACCESS_COARSE_LOCATION, this); | ||||
} | } | |||
} | } | |||
} | } | |||
@Override | @Override | |||
public void onReceive(Context context, Intent intent) { | public void onReceive(Context context, Intent intent) { | |||
if ((intent != null) && (intent.getAction().equals(ACTION_TRAFF_FEED))) | if (intent != null) { | |||
{ | if (intent.getAction().equals(ACTION_TRAFF_FEED)) { | |||
String feed = intent.getStringExtra(EXTRA_FEED); | Uri uri = intent.getData(); | |||
if (feed == null) { | if (uri != null) { | |||
Log.w(this.getClass().getSimpleName(), "empty feed, ignoring"); | /* 0.8 feed */ | |||
} else { | String subscriptionId = intent.getStringExtra(EXTRA_SUBSCRIP | |||
onFeedReceived(mCbid, feed); | TION_ID); | |||
if (subscriptions.containsKey(subscriptionId)) | ||||
fetchMessages(context, uri); | ||||
else { | ||||
/* | ||||
* If we don’t recognize the subscription, skip processi | ||||
ng and unsubscribe. | ||||
* Note: if EXTRA_PACKAGE is not set, sendTraffIntent() | ||||
sends the request to every | ||||
* manifest-declared receiver which handles the request. | ||||
*/ | ||||
Log.d(TAG, | ||||
String.format("got a feed from %s for unknown su | ||||
bscription %s, URI %s; unsubscribing", | ||||
intent.getStringExtra(EXTRA_PACKAGE), subscripti | ||||
onId, uri)); | ||||
Bundle extras = new Bundle(); | ||||
extras.putString(EXTRA_SUBSCRIPTION_ID, subscriptionId); | ||||
sendTraffIntent(context, ACTION_TRAFF_UNSUBSCRIBE, null, | ||||
extras, | ||||
intent.getStringExtra(EXTRA_PACKAGE), | ||||
Manifest.permission.ACCESS_COARSE_LOCATION, this | ||||
); | ||||
} | ||||
} else { | ||||
/* 0.7 feed */ | ||||
String packageName = intent.getStringExtra(EXTRA_PACKAGE); | ||||
/* | ||||
* If the feed comes from a TraFF 0.8+ source and we are sub | ||||
scribed, skip it. | ||||
* As a side effect of the current implementation, if a “bil | ||||
ingual” TraFF 0.7/0.8 | ||||
* source sends a broadcast feed before we have subscribed t | ||||
o it, we would process | ||||
* the whole feed first, and then subscribe to a subset of t | ||||
hat data. | ||||
* If that turns out to be an issue, we would need to detect | ||||
TraFF 0.8-capable | ||||
* sources and discard broadcast feeds from them. | ||||
*/ | ||||
if ((packageName != null) && subscriptions.containsValue(pac | ||||
kageName)) | ||||
return; | ||||
String feed = intent.getStringExtra(EXTRA_FEED); | ||||
if (feed == null) { | ||||
Log.w(this.getClass().getSimpleName(), "empty feed, igno | ||||
ring"); | ||||
} else { | ||||
onFeedReceived(mCbid, feed); | ||||
} | ||||
} // uri != null | ||||
} else if (intent.getAction().equals(ACTION_TRAFF_SUBSCRIBE)) { | ||||
if (this.getResultCode() != RESULT_OK) { | ||||
Bundle extras = this.getResultExtras(true); | ||||
if (extras != null) | ||||
Log.e(this.getClass().getSimpleName(), String.format("su | ||||
bscription to %s failed, %s", | ||||
extras.getString(EXTRA_PACKAGE), formatTraffErro | ||||
r(this.getResultCode()))); | ||||
else | ||||
Log.e(this.getClass().getSimpleName(), String.format("su | ||||
bscription failed, %s", | ||||
formatTraffError(this.getResultCode()))); | ||||
return; | ||||
} | ||||
Bundle extras = this.getResultExtras(true); | ||||
String data = this.getResultData(); | ||||
String packageName = extras.getString(EXTRA_PACKAGE); | ||||
String subscriptionId = extras.getString(EXTRA_SUBSCRIPTION_ID); | ||||
if (subscriptionId == null) { | ||||
Log.e(this.getClass().getSimpleName(), | ||||
String.format("subscription to %s failed: no subscri | ||||
ption ID returned", packageName)); | ||||
return; | ||||
} else if (packageName == null) { | ||||
Log.e(this.getClass().getSimpleName(), "subscription failed: | ||||
no package name"); | ||||
return; | ||||
} else if (data == null) { | ||||
Log.w(this.getClass().getSimpleName(), | ||||
String.format("subscription to %s successful (ID: %s | ||||
) but no content URI was supplied. " | ||||
+ "This is an issue with the source and may | ||||
result in delayed message retrieval.", | ||||
packageName, subscriptionId)); | ||||
subscriptions.put(subscriptionId, packageName); | ||||
return; | ||||
} | ||||
Log.d(TAG, "subscription to " + packageName + " successful, ID: | ||||
" + subscriptionId); | ||||
subscriptions.put(subscriptionId, packageName); | ||||
fetchMessages(context, Uri.parse(data)); | ||||
} else if (intent.getAction().equals(ACTION_TRAFF_SUBSCRIPTION_CHANG | ||||
E)) { | ||||
if (this.getResultCode() != RESULT_OK) { | ||||
Bundle extras = this.getResultExtras(true); | ||||
if (extras != null) | ||||
Log.e(this.getClass().getSimpleName(), | ||||
String.format("subscription change for %s failed | ||||
: %s", | ||||
extras.getString(EXTRA_SUBSCRIPTION_ID), | ||||
formatTraffError(this.getResultCode()))) | ||||
; | ||||
else | ||||
Log.e(this.getClass().getSimpleName(), | ||||
String.format("subscription change failed: %s", | ||||
formatTraffError(this.getResultCode()))) | ||||
; | ||||
return; | ||||
} | ||||
Bundle extras = intent.getExtras(); | ||||
String data = this.getResultData(); | ||||
String subscriptionId = extras.getString(EXTRA_SUBSCRIPTION_ID); | ||||
if (subscriptionId == null) { | ||||
Log.w(this.getClass().getSimpleName(), | ||||
"subscription change successful but the source did n | ||||
ot specify the subscription ID. " | ||||
+ "This is an issue with the source and may | ||||
result in delayed message retrieval. " | ||||
+ "URI: " + data); | ||||
return; | ||||
} else if (data == null) { | ||||
Log.w(this.getClass().getSimpleName(), | ||||
String.format("subscription change for %s successful | ||||
but no content URI was supplied. " | ||||
+ "This is an issue with the source and may | ||||
result in delayed message retrieval.", | ||||
subscriptionId)); | ||||
return; | ||||
} else if (!subscriptions.containsKey(subscriptionId)) { | ||||
Log.e(this.getClass().getSimpleName(), | ||||
"subscription change failed: unknown subscription ID | ||||
" + subscriptionId); | ||||
return; | ||||
} | ||||
Log.d(TAG, "subscription change for " + subscriptionId + " succe | ||||
ssful"); | ||||
fetchMessages(context, Uri.parse(data)); | ||||
} else if (intent.getAction().equals(ACTION_TRAFF_UNSUBSCRIBE)) { | ||||
/* | ||||
* If we ever unsubscribe for reasons other than that we are shu | ||||
tting down or got a feed for | ||||
* a subscription we don’t recognize, or if we start keeping a p | ||||
ersistent list of | ||||
* subscriptions, we need to delete the subscription from our li | ||||
st. Until then, there is | ||||
* nothing to do here: either the subscription isn’t in the list | ||||
, or we are about to shut | ||||
* down and the whole list is about to get discarded. | ||||
*/ | ||||
} else if (intent.getAction().equals(ACTION_TRAFF_HEARTBEAT)) { | ||||
String subscriptionId = intent.getStringExtra(EXTRA_SUBSCRIPTION | ||||
_ID); | ||||
if (subscriptions.containsKey(subscriptionId)) { | ||||
Log.d(TAG, | ||||
String.format("got a heartbeat from %s for subscript | ||||
ion %s; sending result", | ||||
intent.getStringExtra(EXTRA_PACKAGE), subscriptionId | ||||
)); | ||||
this.setResult(RESULT_OK, null, null); | ||||
} else { | ||||
/* | ||||
* If we don’t recognize the subscription, skip reply and un | ||||
subscribe. | ||||
* Note: if EXTRA_PACKAGE is not set, sendTraffIntent() send | ||||
s the request to every | ||||
* manifest-declared receiver which handles the request. | ||||
*/ | ||||
Log.d(TAG, | ||||
String.format("got a heartbeat from %s for unknown s | ||||
ubscription %s; unsubscribing", | ||||
intent.getStringExtra(EXTRA_PACKAGE), subscriptionId | ||||
)); | ||||
Bundle extras = new Bundle(); | ||||
extras.putString(EXTRA_SUBSCRIPTION_ID, subscriptionId); | ||||
sendTraffIntent(context, ACTION_TRAFF_UNSUBSCRIBE, null, ext | ||||
ras, | ||||
intent.getStringExtra(EXTRA_PACKAGE), | ||||
Manifest.permission.ACCESS_COARSE_LOCATION, this); | ||||
} | ||||
} // intent.getAction() | ||||
} // intent != null | ||||
} | ||||
/** | ||||
* Fetches messages from a content provider. | ||||
* | ||||
* @param context The context to use for the content resolver | ||||
* @param uri The content provider URI | ||||
*/ | ||||
private void fetchMessages(Context context, Uri uri) { | ||||
try { | ||||
Cursor cursor = context.getContentResolver().query(uri, new String[] | ||||
{COLUMN_DATA}, null, null, null); | ||||
if (cursor == null) | ||||
return; | ||||
if (cursor.getCount() < 1) { | ||||
cursor.close(); | ||||
return; | ||||
} | } | |||
StringBuilder builder = new StringBuilder("<feed>\n"); | ||||
while (cursor.moveToNext()) | ||||
builder.append(cursor.getString(cursor.getColumnIndex(COLUMN_DAT | ||||
A))).append("\n"); | ||||
builder.append("</feed>"); | ||||
cursor.close(); | ||||
onFeedReceived(mCbid, builder.toString()); | ||||
} catch (Exception e) { | ||||
Log.w(TAG, String.format("Unable to fetch messages from %s", uri.toS | ||||
tring()), e); | ||||
e.printStackTrace(); | ||||
} | } | |||
} | } | |||
/** | ||||
* Sends a TraFF intent to a source. This encapsulates most of the low-leve | ||||
l Android handling. | ||||
* | ||||
* <p>If the recipient specified in {@code packageName} declares multiple re | ||||
ceivers for the intent in its | ||||
* manifest, a separate intent will be delivered to each of them. The intent | ||||
will not be delivered to | ||||
* receivers registered at runtime. | ||||
* | ||||
* <p>All intents are sent as explicit ordered broadcasts. This means two th | ||||
ings: | ||||
* | ||||
* <p>Any app which declares a matching receiver in its manifest will be wok | ||||
en up to process the intent. | ||||
* This works even with certain Android 7 builds which restrict intent deliv | ||||
ery to apps which are not | ||||
* currently running. | ||||
* | ||||
* <p>It is safe for the recipient to unconditionally set result data. If th | ||||
e recipient does not set result | ||||
* data, the result will have a result code of {@link #RESULT_INTERNAL_ERROR | ||||
}, no data and no extras. | ||||
* | ||||
* @param context The context | ||||
* @param action The intent action. | ||||
* @param data The intent data (for TraFF, this is the content provider URI) | ||||
, or null | ||||
* @param extras The extras for the intent | ||||
* @param packageName The package name for the recipient, or null to deliver | ||||
the intent to all matching receivers | ||||
* @param receiverPermission A permission which the recipient must hold, or | ||||
null if not required | ||||
* @param resultReceiver A BroadcastReceiver which will receive the result f | ||||
or the intent | ||||
*/ | ||||
/* From traff-consumer-android, by the same author and re-licensed under GPL | ||||
2 for Navit */ | ||||
public static void sendTraffIntent(Context context, String action, Uri data, | ||||
Bundle extras, String packageName, | ||||
String receiverPermission, BroadcastReceiver resultReceiver) { | ||||
Intent outIntent = new Intent(action); | ||||
PackageManager pm = context.getPackageManager(); | ||||
List<ResolveInfo> receivers = pm.queryBroadcastReceivers(outIntent, 0); | ||||
if (receivers != null) | ||||
for (ResolveInfo receiver : receivers) { | ||||
if ((packageName != null) && !packageName.equals(receiver.activi | ||||
tyInfo.applicationInfo.packageName)) | ||||
continue; | ||||
ComponentName cn = new ComponentName(receiver.activityInfo.appli | ||||
cationInfo.packageName, | ||||
receiver.activityInfo.name); | ||||
outIntent = new Intent(action); | ||||
if (data != null) | ||||
outIntent.setData(data); | ||||
if (extras != null) | ||||
outIntent.putExtras(extras); | ||||
outIntent.setComponent(cn); | ||||
context.sendOrderedBroadcast(outIntent, | ||||
receiverPermission, | ||||
resultReceiver, | ||||
null, // scheduler, | ||||
RESULT_INTERNAL_ERROR, // initialCode, | ||||
null, // initialData, | ||||
null); | ||||
} | ||||
} | ||||
private static String formatTraffError(int code) { | ||||
if ((code < 0) || (code >= ERROR_STRINGS.length)) | ||||
return String.format("unknown (%d)", code); | ||||
else | ||||
return ERROR_STRINGS[code]; | ||||
} | ||||
} | } | |||
End of changes. 17 change blocks. | ||||
20 lines changed or deleted | 424 lines changed or added |