1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 * in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the License
10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 * or implied. See the License for the specific language governing permissions and limitations under
12 * the License.
13 */
14
15package android.service.carrier;
16
17import android.annotation.CallSuper;
18import android.app.Service;
19import android.content.Intent;
20import android.os.IBinder;
21import android.os.PersistableBundle;
22import android.os.RemoteException;
23import android.os.ServiceManager;
24
25import com.android.internal.telephony.ITelephonyRegistry;
26
27/**
28 * A service that exposes carrier-specific functionality to the system.
29 * <p>
30 * To extend this class, you must declare the service in your manifest file to require the
31 * {@link android.Manifest.permission#BIND_CARRIER_SERVICES} permission and include an intent
32 * filter with the {@link #CARRIER_SERVICE_INTERFACE}. If the service should have a long-lived
33 * binding, set android.service.carrier.LONG_LIVED_BINDING to true in the service's metadata.
34 * For example:
35 * </p>
36 *
37 * <pre>{@code
38 * <service android:name=".MyCarrierService"
39 *       android:label="@string/service_name"
40 *       android:permission="android.permission.BIND_CARRIER_SERVICES">
41 *  <intent-filter>
42 *      <action android:name="android.service.carrier.CarrierService" />
43 *  </intent-filter>
44 *  <meta-data android:name="android.service.carrier.LONG_LIVED_BINDING"
45 *             android:value="true" />
46 * </service>
47 * }</pre>
48 */
49public abstract class CarrierService extends Service {
50
51    public static final String CARRIER_SERVICE_INTERFACE = "android.service.carrier.CarrierService";
52
53    private static ITelephonyRegistry sRegistry;
54
55    private final ICarrierService.Stub mStubWrapper;
56
57    public CarrierService() {
58        mStubWrapper = new ICarrierServiceWrapper();
59        if (sRegistry == null) {
60            sRegistry = ITelephonyRegistry.Stub.asInterface(
61                    ServiceManager.getService("telephony.registry"));
62        }
63    }
64
65    /**
66     * Override this method to set carrier configuration.
67     * <p>
68     * This method will be called by telephony services to get carrier-specific configuration
69     * values. The returned config will be saved by the system until,
70     * <ol>
71     * <li>The carrier app package is updated, or</li>
72     * <li>The carrier app requests a reload with
73     * {@link android.telephony.CarrierConfigManager#notifyConfigChangedForSubId
74     * notifyConfigChangedForSubId}.</li>
75     * </ol>
76     * This method can be called after a SIM card loads, which may be before or after boot.
77     * </p>
78     * <p>
79     * This method should not block for a long time. If expensive operations (e.g. network access)
80     * are required, this method can schedule the work and return null. Then, use
81     * {@link android.telephony.CarrierConfigManager#notifyConfigChangedForSubId
82     * notifyConfigChangedForSubId} to trigger a reload when the config is ready.
83     * </p>
84     * <p>
85     * Implementations should use the keys defined in {@link android.telephony.CarrierConfigManager
86     * CarrierConfigManager}. Any configuration values not set in the returned {@link
87     * PersistableBundle} may be overridden by the system's default configuration service.
88     * </p>
89     *
90     * @param id contains details about the current carrier that can be used do decide what
91     *            configuration values to return.
92     * @return a {@link PersistableBundle} object containing the configuration or null if default
93     *         values should be used.
94     */
95    public abstract PersistableBundle onLoadConfig(CarrierIdentifier id);
96
97    /**
98     * Informs the system of an intentional upcoming carrier network change by
99     * a carrier app. This call is optional and is only used to allow the
100     * system to provide alternative UI while telephony is performing an action
101     * that may result in intentional, temporary network lack of connectivity.
102     * <p>
103     * Based on the active parameter passed in, this method will either show or
104     * hide the alternative UI. There is no timeout associated with showing
105     * this UX, so a carrier app must be sure to call with active set to false
106     * sometime after calling with it set to true.
107     * <p>
108     * Requires Permission:
109     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
110     * Or the calling app has carrier privileges.
111     *   @see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}
112     *
113     * @param active Whether the carrier network change is or shortly will be
114     *               active. Set this value to true to begin showing
115     *               alternative UI and false to stop.
116     */
117    public final void notifyCarrierNetworkChange(boolean active) {
118        try {
119            if (sRegistry != null) sRegistry.notifyCarrierNetworkChange(active);
120        } catch (RemoteException | NullPointerException ex) {}
121    }
122
123    /**
124     * If overriding this method, call through to the super method for any unknown actions.
125     * {@inheritDoc}
126     */
127    @Override
128    @CallSuper
129    public IBinder onBind(Intent intent) {
130        return mStubWrapper;
131    }
132
133    /**
134     * A wrapper around ICarrierService that forwards calls to implementations of
135     * {@link CarrierService}.
136     */
137    private class ICarrierServiceWrapper extends ICarrierService.Stub {
138        @Override
139        public PersistableBundle getCarrierConfig(CarrierIdentifier id) {
140            return CarrierService.this.onLoadConfig(id);
141        }
142    }
143}
144