Loading src/java/com/android/internal/telephony/DefaultPhoneNotifier.java +20 −7 Original line number Diff line number Diff line Loading @@ -28,13 +28,6 @@ import android.telephony.ServiceState; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.PreciseCallState; import android.telephony.DisconnectCause; import com.android.internal.telephony.Call; import com.android.internal.telephony.CallManager; import com.android.internal.telephony.Phone; import com.android.internal.telephony.ITelephonyRegistry; import com.android.internal.telephony.PhoneConstants; import java.util.List; Loading Loading @@ -293,6 +286,26 @@ public class DefaultPhoneNotifier implements PhoneNotifier { } } @Override public void notifyDataActivationStateChanged(Phone sender, int activationState) { try { mRegistry.notifySimActivationStateChangedForPhoneId(sender.getPhoneId(), sender.getSubId(), PhoneConstants.SIM_ACTIVATION_TYPE_DATA, activationState); } catch (RemoteException ex) { // system process is dead } } @Override public void notifyVoiceActivationStateChanged(Phone sender, int activationState) { try { mRegistry.notifySimActivationStateChangedForPhoneId(sender.getPhoneId(), sender.getSubId(), PhoneConstants.SIM_ACTIVATION_TYPE_VOICE, activationState); } catch (RemoteException ex) { // system process is dead } } @Override public void notifyOemHookRawEventForSubscriber(int subId, byte[] rawData) { try { Loading src/java/com/android/internal/telephony/Phone.java +48 −1 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ import android.telephony.Rlog; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.VoLteServiceState; import android.text.TextUtils; Loading Loading @@ -239,7 +240,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { private int mCallRingContinueToken; private int mCallRingDelay; private boolean mIsVoiceCapable = true; private SimActivationTracker mSimActivationTracker; // Keep track of whether or not the phone is in Emergency Callback Mode for Phone and // subclasses protected boolean mIsPhoneInEcmState = false; Loading Loading @@ -511,6 +512,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null); mCarrierSignalAgent = mTelephonyComponentFactory.makeCarrierSignalAgent(this); mCarrierActionAgent = mTelephonyComponentFactory.makeCarrierActionAgent(this); mSimActivationTracker = mTelephonyComponentFactory.makeSimActivationTracker(this); if (getPhoneType() != PhoneConstants.PHONE_TYPE_SIP) { mCi.registerForSrvccStateChanged(this, EVENT_SRVCC_STATE_CHANGED, null); } Loading Loading @@ -1536,6 +1538,32 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return null; } /** * Update voice activation state */ public void setVoiceActivationState(int state) { mSimActivationTracker.setVoiceActivationState(state); } /** * Update data activation state */ public void setDataActivationState(int state) { mSimActivationTracker.setDataActivationState(state); } /** * Returns voice activation state */ public int getVoiceActivationState() { return mSimActivationTracker.getVoiceActivationState(); } /** * Returns data activation state */ public int getDataActivationState() { return mSimActivationTracker.getDataActivationState(); } /** * Update voice mail count related fields and notify listeners */ Loading Loading @@ -2059,6 +2087,14 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mNotifier.notifyOtaspChanged(this, otaspMode); } public void notifyVoiceActivationStateChanged(int state) { mNotifier.notifyVoiceActivationStateChanged(this, state); } public void notifyDataActivationStateChanged(int state) { mNotifier.notifyDataActivationStateChanged(this, state); } public void notifySignalStrength() { mNotifier.notifySignalStrength(this); } Loading Loading @@ -3464,6 +3500,17 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { pw.println("++++++++++++++++++++++++++++++++"); } if (mSimActivationTracker != null) { try { mSimActivationTracker.dump(fd, pw, args); } catch (Exception e) { e.printStackTrace(); } pw.flush(); pw.println("++++++++++++++++++++++++++++++++"); } if (mCi != null && mCi instanceof RIL) { try { ((RIL)mCi).dump(fd, pw, args); Loading src/java/com/android/internal/telephony/PhoneNotifier.java +4 −0 Original line number Diff line number Diff line Loading @@ -59,5 +59,9 @@ public interface PhoneNotifier { public void notifyVoLteServiceStateChanged(Phone sender, VoLteServiceState lteState); public void notifyVoiceActivationStateChanged(Phone sender, int activationState); public void notifyDataActivationStateChanged(Phone sender, int activationState); public void notifyOemHookRawEventForSubscriber(int subId, byte[] rawData); } src/java/com/android/internal/telephony/SimActivationTracker.java 0 → 100644 +179 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 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 com.android.internal.telephony; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.telephony.Rlog; import android.util.LocalLog; import android.util.Log; import com.android.internal.util.IndentingPrintWriter; import java.io.FileDescriptor; import java.io.PrintWriter; import java.security.InvalidParameterException; import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_ACTIVATED; import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_DEACTIVATED; import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN; import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_RESTRICTED; import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_ACTIVATING; public class SimActivationTracker { /** * SimActivationTracker(SAT) serves as a central place to keep track of all knowledge of * voice & data activation state which is set by custom/default carrier apps. * Each phone object maintains a single activation tracker. */ private static final boolean DBG = true; private static final String LOG_TAG = "SAT"; private static final boolean VDBG = Rlog.isLoggable(LOG_TAG, Log.VERBOSE); private Phone mPhone; /** * Voice Activation State * @see android.telephony.TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN * @see android.telephony.TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING * @see android.telephony.TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED * @see android.telephony.TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED */ private int mVoiceActivationState; /** * Data Activation State * @see android.telephony.TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN * @see android.telephony.TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING * @see android.telephony.TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED * @see android.telephony.TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED * @see android.telephony.TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED */ private int mDataActivationState; private final LocalLog mVoiceActivationStateLog = new LocalLog(10); private final LocalLog mDataActivationStateLog = new LocalLog(10); private final BroadcastReceiver mReceiver; public SimActivationTracker(Phone phone) { mPhone = phone; mVoiceActivationState = SIM_ACTIVATION_STATE_UNKNOWN; mDataActivationState = SIM_ACTIVATION_STATE_UNKNOWN; mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (VDBG) log("action: " + action); if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){ if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals( intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE))) { if (DBG) log("onSimAbsent, reset activation state to UNKNOWN"); setVoiceActivationState(SIM_ACTIVATION_STATE_UNKNOWN); setDataActivationState(SIM_ACTIVATION_STATE_UNKNOWN); } } } }; IntentFilter intentFilter = new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED); mPhone.getContext().registerReceiver(mReceiver, intentFilter); } public void setVoiceActivationState(int state) { if (!isValidActivationState(state) || (SIM_ACTIVATION_STATE_RESTRICTED == state)) { throw new IllegalArgumentException("invalid voice activation state: " + state); } if (DBG) log("setVoiceActivationState=" + state); mVoiceActivationState = state; mVoiceActivationStateLog.log(toString(state)); mPhone.notifyVoiceActivationStateChanged(state); } public void setDataActivationState(int state) { if (!isValidActivationState(state)) { throw new IllegalArgumentException("invalid data activation state: " + state); } if (DBG) log("setDataActivationState=" + state); mDataActivationState = state; mDataActivationStateLog.log(toString(state)); mPhone.notifyDataActivationStateChanged(state); } public int getVoiceActivationState() { return mVoiceActivationState; } public int getDataActivationState() { return mDataActivationState; } private static boolean isValidActivationState(int state) { switch (state) { case SIM_ACTIVATION_STATE_UNKNOWN: case SIM_ACTIVATION_STATE_ACTIVATING: case SIM_ACTIVATION_STATE_ACTIVATED: case SIM_ACTIVATION_STATE_DEACTIVATED: case SIM_ACTIVATION_STATE_RESTRICTED: return true; default: return false; } } private static String toString(int state) { switch (state) { case SIM_ACTIVATION_STATE_UNKNOWN: return "unknown"; case SIM_ACTIVATION_STATE_ACTIVATING: return "activating"; case SIM_ACTIVATION_STATE_ACTIVATED: return "activated"; case SIM_ACTIVATION_STATE_DEACTIVATED: return "deactivated"; case SIM_ACTIVATION_STATE_RESTRICTED: return "restricted"; default: return "invalid"; } } private void log(String s) { Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); } private void loge(String s) { Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); pw.println(" mVoiceActivationState Log:"); ipw.increaseIndent(); mVoiceActivationStateLog.dump(fd, ipw, args); ipw.decreaseIndent(); pw.println(" mDataActivationState Log:"); ipw.increaseIndent(); mDataActivationStateLog.dump(fd, ipw, args); ipw.decreaseIndent(); } public void dispose() { mPhone.getContext().unregisterReceiver(mReceiver); } } No newline at end of file src/java/com/android/internal/telephony/TelephonyComponentFactory.java +4 −2 Original line number Diff line number Diff line Loading @@ -20,10 +20,8 @@ import android.content.Context; import android.database.Cursor; import android.os.Handler; import android.os.IDeviceIdleController; import android.os.PowerManager; import android.os.ServiceManager; import com.android.ims.ImsManager; import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; import com.android.internal.telephony.cdma.EriManager; import com.android.internal.telephony.dataconnection.DcTracker; Loading Loading @@ -64,6 +62,10 @@ public class TelephonyComponentFactory { return new ServiceStateTracker(phone, ci); } public SimActivationTracker makeSimActivationTracker(Phone phone) { return new SimActivationTracker(phone); } public DcTracker makeDcTracker(Phone phone) { return new DcTracker(phone); } Loading Loading
src/java/com/android/internal/telephony/DefaultPhoneNotifier.java +20 −7 Original line number Diff line number Diff line Loading @@ -28,13 +28,6 @@ import android.telephony.ServiceState; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.PreciseCallState; import android.telephony.DisconnectCause; import com.android.internal.telephony.Call; import com.android.internal.telephony.CallManager; import com.android.internal.telephony.Phone; import com.android.internal.telephony.ITelephonyRegistry; import com.android.internal.telephony.PhoneConstants; import java.util.List; Loading Loading @@ -293,6 +286,26 @@ public class DefaultPhoneNotifier implements PhoneNotifier { } } @Override public void notifyDataActivationStateChanged(Phone sender, int activationState) { try { mRegistry.notifySimActivationStateChangedForPhoneId(sender.getPhoneId(), sender.getSubId(), PhoneConstants.SIM_ACTIVATION_TYPE_DATA, activationState); } catch (RemoteException ex) { // system process is dead } } @Override public void notifyVoiceActivationStateChanged(Phone sender, int activationState) { try { mRegistry.notifySimActivationStateChangedForPhoneId(sender.getPhoneId(), sender.getSubId(), PhoneConstants.SIM_ACTIVATION_TYPE_VOICE, activationState); } catch (RemoteException ex) { // system process is dead } } @Override public void notifyOemHookRawEventForSubscriber(int subId, byte[] rawData) { try { Loading
src/java/com/android/internal/telephony/Phone.java +48 −1 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ import android.telephony.Rlog; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.VoLteServiceState; import android.text.TextUtils; Loading Loading @@ -239,7 +240,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { private int mCallRingContinueToken; private int mCallRingDelay; private boolean mIsVoiceCapable = true; private SimActivationTracker mSimActivationTracker; // Keep track of whether or not the phone is in Emergency Callback Mode for Phone and // subclasses protected boolean mIsPhoneInEcmState = false; Loading Loading @@ -511,6 +512,7 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null); mCarrierSignalAgent = mTelephonyComponentFactory.makeCarrierSignalAgent(this); mCarrierActionAgent = mTelephonyComponentFactory.makeCarrierActionAgent(this); mSimActivationTracker = mTelephonyComponentFactory.makeSimActivationTracker(this); if (getPhoneType() != PhoneConstants.PHONE_TYPE_SIP) { mCi.registerForSrvccStateChanged(this, EVENT_SRVCC_STATE_CHANGED, null); } Loading Loading @@ -1536,6 +1538,32 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return null; } /** * Update voice activation state */ public void setVoiceActivationState(int state) { mSimActivationTracker.setVoiceActivationState(state); } /** * Update data activation state */ public void setDataActivationState(int state) { mSimActivationTracker.setDataActivationState(state); } /** * Returns voice activation state */ public int getVoiceActivationState() { return mSimActivationTracker.getVoiceActivationState(); } /** * Returns data activation state */ public int getDataActivationState() { return mSimActivationTracker.getDataActivationState(); } /** * Update voice mail count related fields and notify listeners */ Loading Loading @@ -2059,6 +2087,14 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { mNotifier.notifyOtaspChanged(this, otaspMode); } public void notifyVoiceActivationStateChanged(int state) { mNotifier.notifyVoiceActivationStateChanged(this, state); } public void notifyDataActivationStateChanged(int state) { mNotifier.notifyDataActivationStateChanged(this, state); } public void notifySignalStrength() { mNotifier.notifySignalStrength(this); } Loading Loading @@ -3464,6 +3500,17 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { pw.println("++++++++++++++++++++++++++++++++"); } if (mSimActivationTracker != null) { try { mSimActivationTracker.dump(fd, pw, args); } catch (Exception e) { e.printStackTrace(); } pw.flush(); pw.println("++++++++++++++++++++++++++++++++"); } if (mCi != null && mCi instanceof RIL) { try { ((RIL)mCi).dump(fd, pw, args); Loading
src/java/com/android/internal/telephony/PhoneNotifier.java +4 −0 Original line number Diff line number Diff line Loading @@ -59,5 +59,9 @@ public interface PhoneNotifier { public void notifyVoLteServiceStateChanged(Phone sender, VoLteServiceState lteState); public void notifyVoiceActivationStateChanged(Phone sender, int activationState); public void notifyDataActivationStateChanged(Phone sender, int activationState); public void notifyOemHookRawEventForSubscriber(int subId, byte[] rawData); }
src/java/com/android/internal/telephony/SimActivationTracker.java 0 → 100644 +179 −0 Original line number Diff line number Diff line /* * Copyright (C) 2016 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 com.android.internal.telephony; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.telephony.Rlog; import android.util.LocalLog; import android.util.Log; import com.android.internal.util.IndentingPrintWriter; import java.io.FileDescriptor; import java.io.PrintWriter; import java.security.InvalidParameterException; import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_ACTIVATED; import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_DEACTIVATED; import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN; import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_RESTRICTED; import static android.telephony.TelephonyManager.SIM_ACTIVATION_STATE_ACTIVATING; public class SimActivationTracker { /** * SimActivationTracker(SAT) serves as a central place to keep track of all knowledge of * voice & data activation state which is set by custom/default carrier apps. * Each phone object maintains a single activation tracker. */ private static final boolean DBG = true; private static final String LOG_TAG = "SAT"; private static final boolean VDBG = Rlog.isLoggable(LOG_TAG, Log.VERBOSE); private Phone mPhone; /** * Voice Activation State * @see android.telephony.TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN * @see android.telephony.TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING * @see android.telephony.TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED * @see android.telephony.TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED */ private int mVoiceActivationState; /** * Data Activation State * @see android.telephony.TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN * @see android.telephony.TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING * @see android.telephony.TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED * @see android.telephony.TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED * @see android.telephony.TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED */ private int mDataActivationState; private final LocalLog mVoiceActivationStateLog = new LocalLog(10); private final LocalLog mDataActivationStateLog = new LocalLog(10); private final BroadcastReceiver mReceiver; public SimActivationTracker(Phone phone) { mPhone = phone; mVoiceActivationState = SIM_ACTIVATION_STATE_UNKNOWN; mDataActivationState = SIM_ACTIVATION_STATE_UNKNOWN; mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (VDBG) log("action: " + action); if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){ if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals( intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE))) { if (DBG) log("onSimAbsent, reset activation state to UNKNOWN"); setVoiceActivationState(SIM_ACTIVATION_STATE_UNKNOWN); setDataActivationState(SIM_ACTIVATION_STATE_UNKNOWN); } } } }; IntentFilter intentFilter = new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED); mPhone.getContext().registerReceiver(mReceiver, intentFilter); } public void setVoiceActivationState(int state) { if (!isValidActivationState(state) || (SIM_ACTIVATION_STATE_RESTRICTED == state)) { throw new IllegalArgumentException("invalid voice activation state: " + state); } if (DBG) log("setVoiceActivationState=" + state); mVoiceActivationState = state; mVoiceActivationStateLog.log(toString(state)); mPhone.notifyVoiceActivationStateChanged(state); } public void setDataActivationState(int state) { if (!isValidActivationState(state)) { throw new IllegalArgumentException("invalid data activation state: " + state); } if (DBG) log("setDataActivationState=" + state); mDataActivationState = state; mDataActivationStateLog.log(toString(state)); mPhone.notifyDataActivationStateChanged(state); } public int getVoiceActivationState() { return mVoiceActivationState; } public int getDataActivationState() { return mDataActivationState; } private static boolean isValidActivationState(int state) { switch (state) { case SIM_ACTIVATION_STATE_UNKNOWN: case SIM_ACTIVATION_STATE_ACTIVATING: case SIM_ACTIVATION_STATE_ACTIVATED: case SIM_ACTIVATION_STATE_DEACTIVATED: case SIM_ACTIVATION_STATE_RESTRICTED: return true; default: return false; } } private static String toString(int state) { switch (state) { case SIM_ACTIVATION_STATE_UNKNOWN: return "unknown"; case SIM_ACTIVATION_STATE_ACTIVATING: return "activating"; case SIM_ACTIVATION_STATE_ACTIVATED: return "activated"; case SIM_ACTIVATION_STATE_DEACTIVATED: return "deactivated"; case SIM_ACTIVATION_STATE_RESTRICTED: return "restricted"; default: return "invalid"; } } private void log(String s) { Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); } private void loge(String s) { Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s); } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " "); pw.println(" mVoiceActivationState Log:"); ipw.increaseIndent(); mVoiceActivationStateLog.dump(fd, ipw, args); ipw.decreaseIndent(); pw.println(" mDataActivationState Log:"); ipw.increaseIndent(); mDataActivationStateLog.dump(fd, ipw, args); ipw.decreaseIndent(); } public void dispose() { mPhone.getContext().unregisterReceiver(mReceiver); } } No newline at end of file
src/java/com/android/internal/telephony/TelephonyComponentFactory.java +4 −2 Original line number Diff line number Diff line Loading @@ -20,10 +20,8 @@ import android.content.Context; import android.database.Cursor; import android.os.Handler; import android.os.IDeviceIdleController; import android.os.PowerManager; import android.os.ServiceManager; import com.android.ims.ImsManager; import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; import com.android.internal.telephony.cdma.EriManager; import com.android.internal.telephony.dataconnection.DcTracker; Loading Loading @@ -64,6 +62,10 @@ public class TelephonyComponentFactory { return new ServiceStateTracker(phone, ci); } public SimActivationTracker makeSimActivationTracker(Phone phone) { return new SimActivationTracker(phone); } public DcTracker makeDcTracker(Phone phone) { return new DcTracker(phone); } Loading