• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.location;
18 
19 import java.io.UnsupportedEncodingException;
20 import java.util.concurrent.TimeUnit;
21 
22 import android.app.Notification;
23 import android.app.NotificationManager;
24 import android.content.BroadcastReceiver;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.location.LocationManager;
29 import android.location.INetInitiatedListener;
30 import android.os.SystemClock;
31 import android.telephony.TelephonyManager;
32 import android.telephony.PhoneNumberUtils;
33 import android.telephony.PhoneStateListener;
34 import android.os.RemoteException;
35 import android.os.UserHandle;
36 import android.util.Log;
37 
38 import com.android.internal.notification.SystemNotificationChannels;
39 import com.android.internal.R;
40 import com.android.internal.telephony.GsmAlphabet;
41 
42 /**
43  * A GPS Network-initiated Handler class used by LocationManager.
44  *
45  * {@hide}
46  */
47 public class GpsNetInitiatedHandler {
48 
49     private static final String TAG = "GpsNetInitiatedHandler";
50 
51     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
52 
53     // NI verify activity for bringing up UI (not used yet)
54     public static final String ACTION_NI_VERIFY = "android.intent.action.NETWORK_INITIATED_VERIFY";
55 
56     // string constants for defining data fields in NI Intent
57     public static final String NI_INTENT_KEY_NOTIF_ID = "notif_id";
58     public static final String NI_INTENT_KEY_TITLE = "title";
59     public static final String NI_INTENT_KEY_MESSAGE = "message";
60     public static final String NI_INTENT_KEY_TIMEOUT = "timeout";
61     public static final String NI_INTENT_KEY_DEFAULT_RESPONSE = "default_resp";
62 
63     // the extra command to send NI response to GnssLocationProvider
64     public static final String NI_RESPONSE_EXTRA_CMD = "send_ni_response";
65 
66     // the extra command parameter names in the Bundle
67     public static final String NI_EXTRA_CMD_NOTIF_ID = "notif_id";
68     public static final String NI_EXTRA_CMD_RESPONSE = "response";
69 
70     // these need to match GpsNiType constants in gps_ni.h
71     public static final int GPS_NI_TYPE_VOICE = 1;
72     public static final int GPS_NI_TYPE_UMTS_SUPL = 2;
73     public static final int GPS_NI_TYPE_UMTS_CTRL_PLANE = 3;
74     public static final int GPS_NI_TYPE_EMERGENCY_SUPL = 4;
75 
76     // these need to match GpsUserResponseType constants in gps_ni.h
77     public static final int GPS_NI_RESPONSE_ACCEPT = 1;
78     public static final int GPS_NI_RESPONSE_DENY = 2;
79     public static final int GPS_NI_RESPONSE_NORESP = 3;
80     public static final int GPS_NI_RESPONSE_IGNORE = 4;
81 
82     // these need to match GpsNiNotifyFlags constants in gps_ni.h
83     public static final int GPS_NI_NEED_NOTIFY = 0x0001;
84     public static final int GPS_NI_NEED_VERIFY = 0x0002;
85     public static final int GPS_NI_PRIVACY_OVERRIDE = 0x0004;
86 
87     // these need to match GpsNiEncodingType in gps_ni.h
88     public static final int GPS_ENC_NONE = 0;
89     public static final int GPS_ENC_SUPL_GSM_DEFAULT = 1;
90     public static final int GPS_ENC_SUPL_UTF8 = 2;
91     public static final int GPS_ENC_SUPL_UCS2 = 3;
92     public static final int GPS_ENC_UNKNOWN = -1;
93 
94     // Limit on SUPL NI emergency mode time extension after emergency sessions ends
95     private static final int MAX_EMERGENCY_MODE_EXTENSION_SECONDS = 300;  // 5 minute maximum
96 
97     private final Context mContext;
98     private final TelephonyManager mTelephonyManager;
99     private final PhoneStateListener mPhoneStateListener;
100 
101     // parent gps location provider
102     private final LocationManager mLocationManager;
103 
104     // configuration of notificaiton behavior
105     private boolean mPlaySounds = false;
106     private boolean mPopupImmediately = true;
107 
108     // read the SUPL_ES form gps.conf
109     private volatile boolean mIsSuplEsEnabled;
110 
111     // Set to true if the phone is having emergency call.
112     private volatile boolean mIsInEmergencyCall;
113 
114     // If Location function is enabled.
115     private volatile boolean mIsLocationEnabled = false;
116 
117     private final INetInitiatedListener mNetInitiatedListener;
118 
119     // Set to true if string from HAL is encoded as Hex, e.g., "3F0039"
120     static private boolean mIsHexInput = true;
121 
122     // End time of emergency call, and extension, if set
123     private volatile long mCallEndElapsedRealtimeMillis = 0;
124     private volatile long mEmergencyExtensionMillis = 0;
125 
126     public static class GpsNiNotification
127     {
128         public int notificationId;
129         public int niType;
130         public boolean needNotify;
131         public boolean needVerify;
132         public boolean privacyOverride;
133         public int timeout;
134         public int defaultResponse;
135         public String requestorId;
136         public String text;
137         public int requestorIdEncoding;
138         public int textEncoding;
139     };
140 
141     public static class GpsNiResponse {
142         /* User response, one of the values in GpsUserResponseType */
143         int userResponse;
144     };
145 
146     private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() {
147 
148         @Override public void onReceive(Context context, Intent intent) {
149             String action = intent.getAction();
150             if (action.equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
151                 String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
152                 /*
153                    Tracks the emergency call:
154                        mIsInEmergencyCall records if the phone is in emergency call or not. It will
155                        be set to true when the phone is having emergency call, and then will
156                        be set to false by mPhoneStateListener when the emergency call ends.
157                 */
158                 mIsInEmergencyCall = PhoneNumberUtils.isEmergencyNumber(phoneNumber);
159                 if (DEBUG) Log.v(TAG, "ACTION_NEW_OUTGOING_CALL - " + getInEmergency());
160             } else if (action.equals(LocationManager.MODE_CHANGED_ACTION)) {
161                 updateLocationMode();
162                 if (DEBUG) Log.d(TAG, "location enabled :" + getLocationEnabled());
163             }
164         }
165     };
166 
167     /**
168      * The notification that is shown when a network-initiated notification
169      * (and verification) event is received.
170      * <p>
171      * This is lazily created, so use {@link #setNINotification()}.
172      */
173     private Notification.Builder mNiNotificationBuilder;
174 
GpsNetInitiatedHandler(Context context, INetInitiatedListener netInitiatedListener, boolean isSuplEsEnabled)175     public GpsNetInitiatedHandler(Context context,
176                                   INetInitiatedListener netInitiatedListener,
177                                   boolean isSuplEsEnabled) {
178         mContext = context;
179 
180         if (netInitiatedListener == null) {
181             throw new IllegalArgumentException("netInitiatedListener is null");
182         } else {
183             mNetInitiatedListener = netInitiatedListener;
184         }
185 
186         setSuplEsEnabled(isSuplEsEnabled);
187         mLocationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
188         updateLocationMode();
189         mTelephonyManager =
190             (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
191 
192         mPhoneStateListener = new PhoneStateListener() {
193             @Override
194             public void onCallStateChanged(int state, String incomingNumber) {
195                 if (DEBUG) Log.d(TAG, "onCallStateChanged(): state is "+ state);
196                 // listening for emergency call ends
197                 if (state == TelephonyManager.CALL_STATE_IDLE) {
198                     if (mIsInEmergencyCall) {
199                         mCallEndElapsedRealtimeMillis = SystemClock.elapsedRealtime();
200                         mIsInEmergencyCall = false;
201                     }
202                 }
203             }
204         };
205         mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
206 
207         IntentFilter intentFilter = new IntentFilter();
208         intentFilter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);
209         intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION);
210         mContext.registerReceiver(mBroadcastReciever, intentFilter);
211     }
212 
setSuplEsEnabled(boolean isEnabled)213     public void setSuplEsEnabled(boolean isEnabled) {
214         mIsSuplEsEnabled = isEnabled;
215     }
216 
getSuplEsEnabled()217     public boolean getSuplEsEnabled() {
218         return mIsSuplEsEnabled;
219     }
220 
221     /**
222      * Updates Location enabler based on location setting.
223      */
updateLocationMode()224     public void updateLocationMode() {
225         mIsLocationEnabled = mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
226     }
227 
228     /**
229      * Checks if user agreed to use location.
230      */
getLocationEnabled()231     public boolean getLocationEnabled() {
232         return mIsLocationEnabled;
233     }
234 
235     /**
236      * Determines whether device is in user-initiated emergency session based on the following
237      * 1. If the user is making an emergency call, this is provided by actively
238      *    monitoring the outgoing phone number;
239      * 2. If the user has recently ended an emergency call, and the device is in a configured time
240      *    window after the end of that call.
241      * 3. If the device is in a emergency callback state, this is provided by querying
242      *    TelephonyManager.
243      * @return true if is considered in user initiated emergency mode for NI purposes
244      */
getInEmergency()245     public boolean getInEmergency() {
246         boolean isInEmergencyExtension =
247                 (mCallEndElapsedRealtimeMillis > 0)
248                 && ((SystemClock.elapsedRealtime() - mCallEndElapsedRealtimeMillis)
249                         < mEmergencyExtensionMillis);
250         boolean isInEmergencyCallback = mTelephonyManager.getEmergencyCallbackMode();
251         return mIsInEmergencyCall || isInEmergencyCallback || isInEmergencyExtension;
252     }
253 
setEmergencyExtensionSeconds(int emergencyExtensionSeconds)254     public void setEmergencyExtensionSeconds(int emergencyExtensionSeconds) {
255         if (emergencyExtensionSeconds > MAX_EMERGENCY_MODE_EXTENSION_SECONDS) {
256             Log.w(TAG, "emergencyExtensionSeconds " + emergencyExtensionSeconds
257                     + " too high, reset to " + MAX_EMERGENCY_MODE_EXTENSION_SECONDS);
258             emergencyExtensionSeconds = MAX_EMERGENCY_MODE_EXTENSION_SECONDS;
259         } else if (emergencyExtensionSeconds < 0) {
260             Log.w(TAG, "emergencyExtensionSeconds " + emergencyExtensionSeconds
261                     + " is negative, reset to zero.");
262             emergencyExtensionSeconds = 0;
263         }
264         mEmergencyExtensionMillis = TimeUnit.SECONDS.toMillis(emergencyExtensionSeconds);
265     }
266 
267 
268     // Handles NI events from HAL
handleNiNotification(GpsNiNotification notif)269     public void handleNiNotification(GpsNiNotification notif) {
270         if (DEBUG) Log.d(TAG, "in handleNiNotification () :"
271                         + " notificationId: " + notif.notificationId
272                         + " requestorId: " + notif.requestorId
273                         + " text: " + notif.text
274                         + " mIsSuplEsEnabled" + getSuplEsEnabled()
275                         + " mIsLocationEnabled" + getLocationEnabled());
276 
277         if (getSuplEsEnabled()) {
278             handleNiInEs(notif);
279         } else {
280             handleNi(notif);
281         }
282 
283         //////////////////////////////////////////////////////////////////////////
284         //   A note about timeout
285         //   According to the protocol, in the need_notify and need_verify case,
286         //   a default response should be sent when time out.
287         //
288         //   In some GPS hardware, the GPS driver (under HAL) can handle the timeout case
289         //   and this class GpsNetInitiatedHandler does not need to do anything.
290         //
291         //   However, the UI should at least close the dialog when timeout. Further,
292         //   for more general handling, timeout response should be added to the Handler here.
293         //
294     }
295 
296     // handle NI form HAL when SUPL_ES is disabled.
handleNi(GpsNiNotification notif)297     private void handleNi(GpsNiNotification notif) {
298         if (DEBUG) Log.d(TAG, "in handleNi () :"
299                         + " needNotify: " + notif.needNotify
300                         + " needVerify: " + notif.needVerify
301                         + " privacyOverride: " + notif.privacyOverride
302                         + " mPopupImmediately: " + mPopupImmediately
303                         + " mInEmergency: " + getInEmergency());
304 
305         if (!getLocationEnabled() && !getInEmergency()) {
306             // Location is currently disabled, ignore all NI requests.
307             try {
308                 mNetInitiatedListener.sendNiResponse(notif.notificationId,
309                                                      GPS_NI_RESPONSE_IGNORE);
310             } catch (RemoteException e) {
311                 Log.e(TAG, "RemoteException in sendNiResponse");
312             }
313         }
314         if (notif.needNotify) {
315         // If NI does not need verify or the dialog is not requested
316         // to pop up immediately, the dialog box will not pop up.
317             if (notif.needVerify && mPopupImmediately) {
318                 // Popup the dialog box now
319                 openNiDialog(notif);
320             } else {
321                 // Show the notification
322                 setNiNotification(notif);
323             }
324         }
325         // ACCEPT cases: 1. Notify, no verify; 2. no notify, no verify;
326         // 3. privacy override.
327         if (!notif.needVerify || notif.privacyOverride) {
328             try {
329                 mNetInitiatedListener.sendNiResponse(notif.notificationId,
330                                                      GPS_NI_RESPONSE_ACCEPT);
331             } catch (RemoteException e) {
332                 Log.e(TAG, "RemoteException in sendNiResponse");
333             }
334         }
335     }
336 
337     // handle NI from HAL when the SUPL_ES is enabled
handleNiInEs(GpsNiNotification notif)338     private void handleNiInEs(GpsNiNotification notif) {
339 
340         if (DEBUG) Log.d(TAG, "in handleNiInEs () :"
341                     + " niType: " + notif.niType
342                     + " notificationId: " + notif.notificationId);
343 
344         // UE is in emergency mode when in emergency call mode or in emergency call back mode
345         /*
346            1. When SUPL ES bit is off and UE is not in emergency mode:
347                   Call handleNi() to do legacy behaviour.
348            2. When SUPL ES bit is on and UE is in emergency mode:
349                   Call handleNi() to do acceptance behaviour.
350            3. When SUPL ES bit is off but UE is in emergency mode:
351                   Ignore the emergency SUPL INIT.
352            4. When SUPL ES bit is on but UE is not in emergency mode:
353                   Ignore the emergency SUPL INIT.
354         */
355         boolean isNiTypeES = (notif.niType == GPS_NI_TYPE_EMERGENCY_SUPL);
356         if (isNiTypeES != getInEmergency()) {
357             try {
358                 mNetInitiatedListener.sendNiResponse(notif.notificationId,
359                                                      GPS_NI_RESPONSE_IGNORE);
360             } catch (RemoteException e) {
361                 Log.e(TAG, "RemoteException in sendNiResponse");
362             }
363         } else {
364             handleNi(notif);
365         }
366     }
367 
368     // Sets the NI notification.
setNiNotification(GpsNiNotification notif)369     private synchronized void setNiNotification(GpsNiNotification notif) {
370         NotificationManager notificationManager = (NotificationManager) mContext
371                 .getSystemService(Context.NOTIFICATION_SERVICE);
372         if (notificationManager == null) {
373             return;
374         }
375 
376         String title = getNotifTitle(notif, mContext);
377         String message = getNotifMessage(notif, mContext);
378 
379         if (DEBUG) Log.d(TAG, "setNiNotification, notifyId: " + notif.notificationId +
380                 ", title: " + title +
381                 ", message: " + message);
382 
383         // Construct Notification
384         if (mNiNotificationBuilder == null) {
385             mNiNotificationBuilder = new Notification.Builder(mContext,
386                 SystemNotificationChannels.NETWORK_ALERTS)
387                     .setSmallIcon(com.android.internal.R.drawable.stat_sys_gps_on)
388                     .setWhen(0)
389                     .setOngoing(true)
390                     .setAutoCancel(true)
391                     .setColor(mContext.getColor(
392                             com.android.internal.R.color.system_notification_accent_color));
393         }
394 
395         if (mPlaySounds) {
396             mNiNotificationBuilder.setDefaults(Notification.DEFAULT_SOUND);
397         } else {
398             mNiNotificationBuilder.setDefaults(0);
399         }
400 
401         mNiNotificationBuilder.setTicker(getNotifTicker(notif, mContext))
402                 .setContentTitle(title)
403                 .setContentText(message);
404 
405         notificationManager.notifyAsUser(null, notif.notificationId, mNiNotificationBuilder.build(),
406                 UserHandle.ALL);
407     }
408 
409     // Opens the notification dialog and waits for user input
openNiDialog(GpsNiNotification notif)410     private void openNiDialog(GpsNiNotification notif)
411     {
412         Intent intent = getDlgIntent(notif);
413 
414         if (DEBUG) Log.d(TAG, "openNiDialog, notifyId: " + notif.notificationId +
415                 ", requestorId: " + notif.requestorId +
416                 ", text: " + notif.text);
417 
418         mContext.startActivity(intent);
419     }
420 
421     // Construct the intent for bringing up the dialog activity, which shows the
422     // notification and takes user input
getDlgIntent(GpsNiNotification notif)423     private Intent getDlgIntent(GpsNiNotification notif)
424     {
425         Intent intent = new Intent();
426         String title = getDialogTitle(notif, mContext);
427         String message = getDialogMessage(notif, mContext);
428 
429         // directly bring up the NI activity
430         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
431         intent.setClass(mContext, com.android.internal.app.NetInitiatedActivity.class);
432 
433         // put data in the intent
434         intent.putExtra(NI_INTENT_KEY_NOTIF_ID, notif.notificationId);
435         intent.putExtra(NI_INTENT_KEY_TITLE, title);
436         intent.putExtra(NI_INTENT_KEY_MESSAGE, message);
437         intent.putExtra(NI_INTENT_KEY_TIMEOUT, notif.timeout);
438         intent.putExtra(NI_INTENT_KEY_DEFAULT_RESPONSE, notif.defaultResponse);
439 
440         if (DEBUG) Log.d(TAG, "generateIntent, title: " + title + ", message: " + message +
441                 ", timeout: " + notif.timeout);
442 
443         return intent;
444     }
445 
446     // Converts a string (or Hex string) to a char array
stringToByteArray(String original, boolean isHex)447     static byte[] stringToByteArray(String original, boolean isHex)
448     {
449         int length = isHex ? original.length() / 2 : original.length();
450         byte[] output = new byte[length];
451         int i;
452 
453         if (isHex)
454         {
455             for (i = 0; i < length; i++)
456             {
457                 output[i] = (byte) Integer.parseInt(original.substring(i*2, i*2+2), 16);
458             }
459         }
460         else {
461             for (i = 0; i < length; i++)
462             {
463                 output[i] = (byte) original.charAt(i);
464             }
465         }
466 
467         return output;
468     }
469 
470     /**
471      * Unpacks an byte array containing 7-bit packed characters into a String.
472      *
473      * @param input a 7-bit packed char array
474      * @return the unpacked String
475      */
decodeGSMPackedString(byte[] input)476     static String decodeGSMPackedString(byte[] input)
477     {
478         final char PADDING_CHAR = 0x00;
479         int lengthBytes = input.length;
480         int lengthSeptets = (lengthBytes * 8) / 7;
481         String decoded;
482 
483         /* Special case where the last 7 bits in the last byte could hold a valid
484          * 7-bit character or a padding character. Drop the last 7-bit character
485          * if it is a padding character.
486          */
487         if (lengthBytes % 7 == 0) {
488             if (lengthBytes > 0) {
489                 if ((input[lengthBytes - 1] >> 1) == PADDING_CHAR) {
490                     lengthSeptets = lengthSeptets - 1;
491                 }
492             }
493         }
494 
495         decoded = GsmAlphabet.gsm7BitPackedToString(input, 0, lengthSeptets);
496 
497         // Return "" if decoding of GSM packed string fails
498         if (null == decoded) {
499             Log.e(TAG, "Decoding of GSM packed string failed");
500             decoded = "";
501         }
502 
503         return decoded;
504     }
505 
decodeUTF8String(byte[] input)506     static String decodeUTF8String(byte[] input)
507     {
508         String decoded = "";
509         try {
510             decoded = new String(input, "UTF-8");
511         }
512         catch (UnsupportedEncodingException e)
513         {
514             throw new AssertionError();
515         }
516         return decoded;
517     }
518 
decodeUCS2String(byte[] input)519     static String decodeUCS2String(byte[] input)
520     {
521         String decoded = "";
522         try {
523             decoded = new String(input, "UTF-16");
524         }
525         catch (UnsupportedEncodingException e)
526         {
527             throw new AssertionError();
528         }
529         return decoded;
530     }
531 
532     /** Decode NI string
533      *
534      * @param original   The text string to be decoded
535      * @param isHex      Specifies whether the content of the string has been encoded as a Hex string. Encoding
536      *                   a string as Hex can allow zeros inside the coded text.
537      * @param coding     Specifies the coding scheme of the string, such as GSM, UTF8, UCS2, etc. This coding scheme
538      *                      needs to match those used passed to HAL from the native GPS driver. Decoding is done according
539      *                   to the <code> coding </code>, after a Hex string is decoded. Generally, if the
540      *                   notification strings don't need further decoding, <code> coding </code> encoding can be
541      *                   set to -1, and <code> isHex </code> can be false.
542      * @return the decoded string
543      */
decodeString(String original, boolean isHex, int coding)544     static private String decodeString(String original, boolean isHex, int coding)
545     {
546         String decoded = original;
547         byte[] input = stringToByteArray(original, isHex);
548 
549         switch (coding) {
550         case GPS_ENC_NONE:
551             decoded = original;
552             break;
553 
554         case GPS_ENC_SUPL_GSM_DEFAULT:
555             decoded = decodeGSMPackedString(input);
556             break;
557 
558         case GPS_ENC_SUPL_UTF8:
559             decoded = decodeUTF8String(input);
560             break;
561 
562         case GPS_ENC_SUPL_UCS2:
563             decoded = decodeUCS2String(input);
564             break;
565 
566         case GPS_ENC_UNKNOWN:
567             decoded = original;
568             break;
569 
570         default:
571             Log.e(TAG, "Unknown encoding " + coding + " for NI text " + original);
572             break;
573         }
574         return decoded;
575     }
576 
577     // change this to configure notification display
getNotifTicker(GpsNiNotification notif, Context context)578     static private String getNotifTicker(GpsNiNotification notif, Context context)
579     {
580         String ticker = String.format(context.getString(R.string.gpsNotifTicker),
581                 decodeString(notif.requestorId, mIsHexInput, notif.requestorIdEncoding),
582                 decodeString(notif.text, mIsHexInput, notif.textEncoding));
583         return ticker;
584     }
585 
586     // change this to configure notification display
getNotifTitle(GpsNiNotification notif, Context context)587     static private String getNotifTitle(GpsNiNotification notif, Context context)
588     {
589         String title = String.format(context.getString(R.string.gpsNotifTitle));
590         return title;
591     }
592 
593     // change this to configure notification display
getNotifMessage(GpsNiNotification notif, Context context)594     static private String getNotifMessage(GpsNiNotification notif, Context context)
595     {
596         String message = String.format(context.getString(R.string.gpsNotifMessage),
597                 decodeString(notif.requestorId, mIsHexInput, notif.requestorIdEncoding),
598                 decodeString(notif.text, mIsHexInput, notif.textEncoding));
599         return message;
600     }
601 
602     // change this to configure dialog display (for verification)
getDialogTitle(GpsNiNotification notif, Context context)603     static public String getDialogTitle(GpsNiNotification notif, Context context)
604     {
605         return getNotifTitle(notif, context);
606     }
607 
608     // change this to configure dialog display (for verification)
getDialogMessage(GpsNiNotification notif, Context context)609     static private String getDialogMessage(GpsNiNotification notif, Context context)
610     {
611         return getNotifMessage(notif, context);
612     }
613 
614 }
615