Home | History | Annotate | Download | only in service
      1 /*
      2  * Copyright (C) 2014 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.omadm.service;
     18 
     19 import android.app.AlarmManager;
     20 import android.app.Notification;
     21 import android.app.NotificationManager;
     22 import android.app.PendingIntent;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.content.SharedPreferences;
     26 import android.os.Process;
     27 import android.content.pm.PackageManager;
     28 import android.util.Log;
     29 
     30 import java.io.File;
     31 
     32 final class DMHelper {
     33     private static final String TAG = "DMHelper";
     34     private static final boolean DBG = DMClientService.DBG;
     35 
     36     public static final String POSTPONED_DATA_PATH
     37             = "/data/data/com.android.omadm.service/shared_prefs/dmpostponed.dat";
     38 
     39     private static final String FOTA_APN_FILE_PATH
     40             = "/data/data/com.android.omadm.service/shared_prefs/fotaapnprefs.xml";
     41 
     42     public static final int UI_MODE_INFORMATIVE = 2;
     43 
     44     public static final int UI_MODE_CONFIRMATION = 3;
     45 
     46     public static final int NOTIFICATION_INFORMATIVE_ID = 0xcb01fa64;
     47 
     48     public static final int NOTIFICATION_CONFIRMATION_ID = 0xadc19b91;
     49 
     50 
     51     // -------  Constant VALUES -----------//
     52     // message lifetime (24 hours) in milliseconds
     53     private static final long MESSAGE_LIFETIME = 24 * 60 * 60 * 1000000000L; //nanoseconds
     54 
     55     // maximum number failures to attempt starting DM session
     56     public static final long MAX_SESSION_ATTEMPTS = 3;
     57 
     58     // time before attempt start DM session after a failure (in seconds)
     59     public static final int TIME_BETWEEN_SESSION_ATTEMPTS = 30 * 60; //seconds
     60 
     61     // time to check status after starting DM service; try to restart if service will die (in seconds)
     62     public static final int TIME_CHECK_STATUS_AFTER_STARTING_DM_SERVICE = 30 * 60; //seconds
     63 
     64     // time to check and repost notification in case if user cancel it; subscribe during posting notification (in seconds)
     65     public static final int TIME_CHECK_NOTIFICATION_AFTER_SUBSCRIPTION = 30 * 60; //seconds
     66 
     67     // time to check status after starting call and data monitoring service; try to restart if service will die (in seconds)
     68     public static final int TIME_CHECK_STATUS_AFTER_STARTING_MONITORING_SERVICE = 20 * 60; //seconds
     69 
     70 
     71     // -----  States ----//
     72     public static final String STATE_KEY = "dmmsgstate";
     73 
     74     public static final int STATE_IDLE = 0;                 // nothing there
     75 
     76     public static final int STATE_PENDING_MESSAGE = 1;      // message received and saved
     77 
     78     public static final int STATE_APPROVED_BY_USER = 2;     // message approved or silent
     79 
     80     public static final int STATE_SESSION_IN_PROGRESS = 3;  // DM session has been started
     81 
     82 
     83     // -----  Keys  ----//
     84     // shared properties name
     85     public static final String DM_PREFERENCES_KEY = "dmpostponed";
     86 
     87     // key to keep timestamp for the message in the shared properties. Also used as a request ID
     88     public static final String MESSAGE_TIMESTAMP_ID_KEY = "dm_msg_time_init";
     89 
     90     public static final String MESSAGE_SERVER_URL_KEY = "dm_server_url";
     91 
     92     public static final String MESSAGE_PROXY_HOSTNAME_KEY = "dm_proxy_hostname";
     93 
     94     // key to keep number attempts to start DM session
     95     public static final String DM_SESSION_ATTEMPTS_KEY = "dm_session_attempts";
     96 
     97     // key to keep uiMode
     98     public static final String DM_UI_MODE_KEY = "dm_ui_mode";
     99 
    100     // key for pending session type
    101     public static final String DM_SESSION_TYPE_KEY = "type";
    102 
    103     // ---- Key and States used for fota apn ----//
    104     // shared property name
    105     public static final String FOTA_APN_PREFERENCE_KEY = "fotaapnprefs";
    106 
    107     public static final String FOTA_APN_STATE_KEY = "fotapnstate";
    108 
    109     public static final String FOTA_ALERT_STRING_KEY = "fota_alert_string";
    110 
    111     public static final String FOTA_SERVER_ID_KEY = "fota_server_id";
    112 
    113     // initial APN monitor state
    114     public static final int FOTA_APN_STATE_INIT = 0; // no action needed for this
    115 
    116     // apn switch needed for NI session
    117     public static final int FOTA_APN_STATE_START_DM_SESSION = 1;
    118 
    119     // apn switch needed for FDM session
    120     public static final int FOTA_APN_STATE_REPORT_DM_SESSION = 2;
    121 
    122     // RPTD states used to decide when to stop using fota apn
    123     public static final int FOTA_APN_STATE_START_DM_SESSION_RPTD = 3;
    124     public static final int FOTA_APN_STATE_REPORT_DM_SESSION_RPTD = 4;
    125 
    126     // ---- Keys used for storing FDM MSG Values ----//
    127     public static final String LAWMO_RESULT_KEY = "lawmoResult";
    128 
    129     public static final String FOTA_RESULT_KEY = "fotaResult";
    130 
    131     public static final String PKG_URI_KEY = "pkgURI";
    132 
    133     public static final String ALERT_TYPE_KEY = "alertType";
    134 
    135     public static final String CORRELATOR_KEY = "correlator";
    136 
    137     public static final String SERVER_ID_KEY = "serverID";
    138 
    139     // --- Key used for storing hostname override for Sprint ---//
    140     public static final String SERVER_HOSTNAME_OVERRIDE_KEY = "serverHostname";
    141 
    142     //--- Keys used for storing imei ---//
    143     public static final String IMEI_PREFERENCE_KEY = "imeivalue";
    144 
    145     public static final String IMEI_VALUE_KEY = "imei";
    146 
    147     //--- Keys used for storing AKEY ---//
    148     public static final String AKEY_PREFERENCE_KEY = "akeyvalue";
    149 
    150     public static final String AKEY_VALUE_KEY = "akey";
    151 
    152     private static boolean sfirstTriggerReceived = false;
    153 
    154     // private constructor
    155     private DMHelper() {}
    156 
    157     // Subscribing for the Timer Alert
    158     public static void subscribeForTimeAlert(Context context, int seconds) {
    159         cancelTimeAlert(context);
    160 
    161         logd("subscribeForTimeAlert ...");
    162 
    163         Intent intent = new Intent(context, DMIntentReceiver.class);
    164         intent.setAction(DMIntent.ACTION_TIMER_ALERT);
    165         PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
    166 
    167         long wakeupTime = System.currentTimeMillis() + (seconds * 1000L);
    168 
    169         // Schedule the alarm
    170         AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    171         am.set(AlarmManager.RTC_WAKEUP, wakeupTime, sender);
    172         logd("subscribeForTimeAlert for " + seconds + " seconds done!");
    173     }
    174 
    175     // Canceling subscription for time alert
    176     private static void cancelTimeAlert(Context context) {
    177         logd("cancelTimeAlarm ...");
    178 
    179         Intent intent = new Intent(context, DMIntentReceiver.class);
    180         intent.setAction(DMIntent.ACTION_TIMER_ALERT);
    181         PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, 0);
    182 
    183         AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    184         am.cancel(sender);
    185         logd("cancelTimeAlarm done!");
    186     }
    187 
    188     // post confirmation notification when UI mode required user interaction
    189     public static void postConfirmationNotification(Context context) {
    190         NotificationManager mNotificationManager = (NotificationManager) context
    191                 .getSystemService(Context.NOTIFICATION_SERVICE);
    192 
    193         CharSequence text = context.getText(
    194                 R.string.dm_session_confirmation_notification_message)
    195                 .toString();
    196 
    197         Intent provisioning = new Intent(context, DMSessionConfirmAlertActivity.class);
    198 
    199         PendingIntent contentIntent = PendingIntent.getActivity(context, 0, provisioning, 0);
    200 
    201         Notification notification = new Notification.Builder(context)
    202                 .setSmallIcon(R.drawable.alert_dialog_icon)
    203                 .setTicker(text)
    204                 .setWhen(System.currentTimeMillis())
    205                 .setContentTitle(
    206                         context.getText(R.string.dm_session_confirmation_notification_label))
    207                 .setContentText(text)
    208                 .setContentIntent(contentIntent)
    209                 .setColor(context.getResources().getColor(
    210                         com.android.internal.R.color.system_notification_accent_color))
    211                 .build();
    212 
    213         mNotificationManager.notify(NOTIFICATION_CONFIRMATION_ID,
    214                 notification);
    215     }
    216 
    217     // post informative notification when UI mode required to inform users
    218     private static void postInformativeNotification(Context context, int titleId, int textId) {
    219         NotificationManager mNotificationManager = (NotificationManager) context
    220                 .getSystemService(Context.NOTIFICATION_SERVICE);
    221 
    222         CharSequence text = context.getText(textId);
    223 
    224         Intent provisioning = new Intent(context, DMIntentReceiver.class);
    225         provisioning.setAction(DMIntent.ACTION_CLOSE_NOTIFICATION_INFO);
    226 
    227         PendingIntent contentIntent = PendingIntent.getBroadcast(context, 0, provisioning, 0);
    228 
    229         Notification notification = new Notification.Builder(context)
    230                 .setSmallIcon(R.drawable.alert_dialog_icon)
    231                 .setTicker(text)
    232                 .setWhen(System.currentTimeMillis())
    233                 .setContentTitle(context.getText(titleId))
    234                 .setContentText(text)
    235                 .setContentIntent(contentIntent)
    236                 .setColor(context.getResources().getColor(
    237                         com.android.internal.R.color.system_notification_accent_color))
    238                 .build();
    239 
    240         mNotificationManager.notify(NOTIFICATION_INFORMATIVE_ID, notification);
    241     }
    242 
    243     // post informative notification when UI mode required to inform users
    244     public static void postInformativeNotification_message1(Context context) {
    245         postInformativeNotification(context,
    246                 R.string.dm_session_information_notification_label,
    247                 R.string.dm_session_information_notification_message1);
    248     }
    249 
    250     //post informative notification when UI mode required to inform users
    251     public static void postInformativeNotification_message2_success(Context context) {
    252         postInformativeNotification(context,
    253                 R.string.dm_session_information_notification_label,
    254                 R.string.dm_session_information_notification_message2_success);
    255     }
    256 
    257     //post informative notification when UI mode required to inform users
    258     public static void postInformativeNotification_message2_fail(Context context) {
    259         postInformativeNotification(context,
    260                 R.string.dm_session_information_notification_label,
    261                 R.string.dm_session_information_notification_message2_fail);
    262     }
    263 
    264     //clear notification
    265     public static void cancelNotification(Context context, int notificationId) {
    266         NotificationManager nm = (NotificationManager) context
    267                 .getSystemService(Context.NOTIFICATION_SERVICE);
    268         nm.cancel(notificationId);
    269     }
    270 
    271 
    272     //remove message and all from shared properties
    273     private static void clearSharedPreferences(Context context) {
    274         SharedPreferences p = context.getSharedPreferences(DM_PREFERENCES_KEY, 0);
    275         SharedPreferences.Editor ed = p.edit();
    276         ed.clear();
    277         ed.apply();
    278 
    279         //remove file with message
    280         File file = new File(POSTPONED_DATA_PATH);
    281         if (file.exists()) {
    282             file.delete();
    283         }
    284     }
    285 
    286     // set Sprint server URL
    287     public static void setServerUrl(Context context, String url) {
    288         logd("setServerUrl: " + url);
    289         SharedPreferences p = context.getSharedPreferences(SERVER_HOSTNAME_OVERRIDE_KEY, 0);
    290         p.edit().putString(MESSAGE_SERVER_URL_KEY, url).apply();
    291     }
    292 
    293     // set Sprint proxy hostname
    294     public static void setProxyHostname(Context context, String hostname) {
    295         logd("setProxyHostname: " + hostname);
    296         SharedPreferences p = context.getSharedPreferences(SERVER_HOSTNAME_OVERRIDE_KEY, 0);
    297         p.edit().putString(MESSAGE_PROXY_HOSTNAME_KEY, hostname).apply();
    298     }
    299 
    300     // get Sprint server URL
    301     public static String getServerUrl(Context context) {
    302         SharedPreferences p = context.getSharedPreferences(SERVER_HOSTNAME_OVERRIDE_KEY, 0);
    303         String url = p.getString(MESSAGE_SERVER_URL_KEY, null);
    304         logd("getServerUrl: " + url);
    305         return url;
    306     }
    307 
    308     // get Sprint proxy hostname
    309     public static String getProxyHostname(Context context) {
    310         SharedPreferences p = context.getSharedPreferences(SERVER_HOSTNAME_OVERRIDE_KEY, 0);
    311         String hostname = p.getString(MESSAGE_PROXY_HOSTNAME_KEY, null);
    312         logd("getProxyHostname: " + hostname);
    313         return hostname;
    314     }
    315 
    316     // check if message is expired; compares current time with the timestamp
    317     // for the message and its lifetime
    318     public static boolean isMessageExpired(Context context) {
    319         // get message timestamp from preferences
    320         SharedPreferences p = context.getSharedPreferences(DM_PREFERENCES_KEY, 0);
    321         long messageTimestamp = p.getLong(MESSAGE_TIMESTAMP_ID_KEY, -1);
    322         logd("isMessageExpired: messageTimestamp is " + messageTimestamp);
    323 
    324         return messageTimestamp == -1 || System.nanoTime() > (messageTimestamp
    325                 + MESSAGE_LIFETIME);
    326     }
    327 
    328     // clean all...  shared preferences, notifications, time alerts....
    329     public static void cleanAllResources(Context context) {
    330         logd("Inside cleanAllResources");
    331         clearSharedPreferences(context);
    332         // Not canceling informative notification since otherwise it disappears very quickly (as
    333         // soon as DM session ends which is just a few seconds)
    334         // cancelNotification(context, NOTIFICATION_INFORMATIVE_ID);
    335         cancelNotification(context, NOTIFICATION_CONFIRMATION_ID);
    336         cancelTimeAlert(context);
    337     }
    338 
    339     // remove message and all from shared properties for fota apn
    340     private static void clearFotaApnSharedPreferences(Context context) {
    341         logd("Inside clearFotaApnSharedPreferences");
    342         SharedPreferences p = context.getSharedPreferences(
    343                 FOTA_APN_PREFERENCE_KEY, 0);
    344         SharedPreferences.Editor ed = p.edit();
    345         ed.clear();
    346         ed.apply();
    347 
    348         //remove file with message
    349         File file = new File(FOTA_APN_FILE_PATH);
    350         if (file.exists()) {
    351             logd("fotaapnprefs.xml file deleted");
    352             // FIXME: don't ignore result of delete
    353             file.delete();
    354         }
    355     }
    356 
    357     public static boolean isRunningAsOwner() {
    358         return Process.myUserHandle().isOwner();
    359     }
    360 
    361     public static void cleanFotaApnResources(Context context) {
    362         if (DBG) logd("Inside cleanFotaApnResources");
    363         clearFotaApnSharedPreferences(context);
    364     }
    365 
    366     public static boolean disableIfSecondaryUser(Context context) {
    367         if (sfirstTriggerReceived == false) {
    368             sfirstTriggerReceived = true;
    369             if (!isRunningAsOwner()) {
    370                 PackageManager pm = context.getPackageManager();
    371                 logd("Disabling com.android.omadm.service for secondary user");
    372                 pm.setApplicationEnabledSetting("com.android.omadm.service",
    373                         PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0 );
    374                 return true;
    375             }
    376         }
    377         return false;
    378     }
    379 
    380     private static void logd(String msg) {
    381         Log.d(TAG, msg);
    382     }
    383 }
    384