diff options
author | cretin45 <cretin45@gmail.com> | 2015-01-15 16:04:44 -0800 |
---|---|---|
committer | cretin45 <cretin45@gmail.com> | 2015-01-15 16:04:44 -0800 |
commit | 0328b87bf68f6389049991c68caa515f4230f95f (patch) | |
tree | 556b0a23df4bb849eada991b01f4861c651f25e8 /src/com/cyanogenmod/setupwizard/setup | |
download | packages_apps_SetupWizard-0328b87bf68f6389049991c68caa515f4230f95f.zip packages_apps_SetupWizard-0328b87bf68f6389049991c68caa515f4230f95f.tar.gz packages_apps_SetupWizard-0328b87bf68f6389049991c68caa515f4230f95f.tar.bz2 |
SetupWizard: Initial commit
Diffstat (limited to 'src/com/cyanogenmod/setupwizard/setup')
16 files changed, 2141 insertions, 0 deletions
diff --git a/src/com/cyanogenmod/setupwizard/setup/AbstractSetupData.java b/src/com/cyanogenmod/setupwizard/setup/AbstractSetupData.java new file mode 100644 index 0000000..fed8732 --- /dev/null +++ b/src/com/cyanogenmod/setupwizard/setup/AbstractSetupData.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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.cyanogenmod.setupwizard.setup; + +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; + +import java.util.ArrayList; + +public abstract class AbstractSetupData implements SetupDataCallbacks { + + private static final String TAG = AbstractSetupData.class.getSimpleName(); + + protected Context mContext; + private ArrayList<SetupDataCallbacks> mListeners = new ArrayList<SetupDataCallbacks>(); + private PageList mPageList; + + private int mCurrentPageIndex = 0; + + public AbstractSetupData(Context context) { + mContext = context; + mPageList = onNewPageList(); + } + + protected abstract PageList onNewPageList(); + + @Override + public void onPageLoaded(Page page) { + for (int i = 0; i < mListeners.size(); i++) { + mListeners.get(i).onPageLoaded(page); + } + } + + @Override + public void onPageTreeChanged() { + for (int i = 0; i < mListeners.size(); i++) { + mListeners.get(i).onPageTreeChanged(); + } + } + + @Override + public void onFinish() { + for (int i = 0; i < mListeners.size(); i++) { + mListeners.get(i).onFinish(); + } + } + + @Override + public Page getPage(String key) { + return mPageList.getPage(key); + } + + @Override + public Page getPage(int index) { + return mPageList.getPage(index); + } + + public Page getCurrentPage() { + return mPageList.getPage(mCurrentPageIndex); + } + + public boolean isFirstPage() { + return mCurrentPageIndex == 0; + } + + public boolean isLastPage() { + return mCurrentPageIndex == mPageList.size() - 1; + } + + @Override + public void onNextPage() { + if (getCurrentPage().doNextAction() == false) { + if (advanceToNextUncompleted()) { + for (int i = 0; i < mListeners.size(); i++) { + mListeners.get(i).onNextPage(); + } + } + } + } + + @Override + public void onPreviousPage() { + if (getCurrentPage().doPreviousAction() == false) { + if (advanceToPreviousUncompleted()) { + for (int i = 0; i < mListeners.size(); i++) { + mListeners.get(i).onPreviousPage(); + } + } + } + } + + @Override + public void onPageViewCreated(LayoutInflater inflater, Bundle savedInstanceState, + int layoutResource) {} + + private boolean advanceToNextUncompleted() { + while (mCurrentPageIndex < mPageList.size()) { + mCurrentPageIndex++; + if (!getCurrentPage().isCompleted()) { + return true; + } + } + return false; + } + + private boolean advanceToPreviousUncompleted() { + while (mCurrentPageIndex > 0) { + mCurrentPageIndex--; + if (!getCurrentPage().isCompleted()) { + return true; + } + } + return false; + } + + public void load(Bundle savedValues) { + for (String key : savedValues.keySet()) { + Page page = mPageList.getPage(key); + if (page != null) { + page.resetData(savedValues.getBundle(key)); + } + } + } + + public Bundle save() { + Bundle bundle = new Bundle(); + for (Page page : mPageList.values()) { + bundle.putBundle(page.getKey(), page.getData()); + } + return bundle; + } + + public void registerListener(SetupDataCallbacks listener) { + mListeners.add(listener); + } + + public void unregisterListener(SetupDataCallbacks listener) { + mListeners.remove(listener); + } +} diff --git a/src/com/cyanogenmod/setupwizard/setup/CMSetupWizardData.java b/src/com/cyanogenmod/setupwizard/setup/CMSetupWizardData.java new file mode 100644 index 0000000..e50f1ac --- /dev/null +++ b/src/com/cyanogenmod/setupwizard/setup/CMSetupWizardData.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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.cyanogenmod.setupwizard.setup; + +import com.cyanogenmod.setupwizard.util.SetupWizardUtils; + +import android.content.Context; +import android.telephony.SubscriptionManager; + +import java.util.ArrayList; + +public class CMSetupWizardData extends AbstractSetupData { + + public CMSetupWizardData(Context context) { + super(context); + } + + @Override + protected PageList onNewPageList() { + ArrayList<SetupPage> pages = new ArrayList<SetupPage>(); + pages.add(new WelcomePage(mContext, this)); + pages.add(new WifiSetupPage(mContext, this)); + if (SetupWizardUtils.isGSMPhone(mContext) && SetupWizardUtils.isSimMissing(mContext)) { + pages.add(new SimCardMissingPage(mContext, this)); + } + if (SetupWizardUtils.isMultiSimDevice(mContext) + && SubscriptionManager.getActiveSubInfoCount() > 1) { + pages.add(new ChooseDataSimPage(mContext, this)); + } + if (SetupWizardUtils.hasTelephony(mContext) && + !SetupWizardUtils.isMobileDataEnabled(mContext)) { + pages.add(new MobileDataPage(mContext, this)); + } + if (SetupWizardUtils.hasGMS(mContext)) { + pages.add(new GmsAccountPage(mContext, this)); + } + pages.add(new CyanogenAccountPage(mContext, this)); + pages.add(new LocationSettingsPage(mContext, this)); + pages.add(new DateTimePage(mContext, this)); + pages.add(new FinishPage(mContext, this)); + return new PageList(pages.toArray(new SetupPage[pages.size()])); + } + + +}
\ No newline at end of file diff --git a/src/com/cyanogenmod/setupwizard/setup/ChooseDataSimPage.java b/src/com/cyanogenmod/setupwizard/setup/ChooseDataSimPage.java new file mode 100644 index 0000000..820edc6 --- /dev/null +++ b/src/com/cyanogenmod/setupwizard/setup/ChooseDataSimPage.java @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2014 The CyanogenMod 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.cyanogenmod.setupwizard.setup; + +import android.app.Fragment; +import android.content.Context; +import android.os.Bundle; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; +import android.telephony.SignalStrength; +import android.telephony.SubInfoRecord; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.util.Log; +import android.util.SparseArray; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.ImageView; +import android.widget.TextView; + +import com.cyanogenmod.setupwizard.R; +import com.cyanogenmod.setupwizard.ui.SetupPageFragment; + +import java.util.List; + +public class ChooseDataSimPage extends SetupPage { + + public static final String TAG = "ChooseDataSimPage"; + + public ChooseDataSimPage(Context context, SetupDataCallbacks callbacks) { + super(context, callbacks); + } + + @Override + public Fragment getFragment() { + Bundle args = new Bundle(); + args.putString(SetupPage.KEY_PAGE_ARGUMENT, getKey()); + + ChooseDataSimFragment fragment = new ChooseDataSimFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public String getKey() { + return TAG; + } + + @Override + public int getTitleResId() { + return R.string.setup_choose_data_sim; + } + + @Override + public int getNextButtonTitleResId() { + return R.string.skip; + } + + + public static class ChooseDataSimFragment extends SetupPageFragment { + + private ViewGroup mPageView; + private SparseArray<TextView> mNameViews; + private SparseArray<ImageView> mSignalViews; + private SparseArray<CheckBox> mCheckBoxes; + + private TelephonyManager mPhone; + private List<SubInfoRecord> mSubInfoRecords; + private SparseArray<SignalStrength> mSignalStrengths; + private SparseArray<ServiceState> mServiceStates; + private SparseArray<PhoneStateListener> mPhoneStateListeners; + + private View.OnClickListener mSetDataSimClickListener = new View.OnClickListener() { + @Override + public void onClick(View view) { + SubInfoRecord subInfoRecord = (SubInfoRecord)view.getTag(); + if (subInfoRecord != null) { + SubscriptionManager.setDefaultDataSubId(subInfoRecord.subId); + setDataSubChecked(subInfoRecord); + } + } + }; + + @Override + protected void initializePage() { + mPageView = (ViewGroup)mRootView.findViewById(R.id.page_view); + mSubInfoRecords = SubscriptionManager.getActiveSubInfoList(); + int simCount = mSubInfoRecords.size(); + mNameViews = new SparseArray<TextView>(simCount); + mSignalViews = new SparseArray<ImageView>(simCount); + mCheckBoxes = new SparseArray<CheckBox>(simCount); + mServiceStates = new SparseArray<ServiceState>(simCount); + mSignalStrengths = new SparseArray<SignalStrength>(simCount); + mPhoneStateListeners = new SparseArray<PhoneStateListener>(simCount); + LayoutInflater inflater = LayoutInflater.from(getActivity()); + for (int i = 0; i < simCount; i++) { + View simRow = inflater.inflate(R.layout.data_sim_row, null); + mPageView.addView(simRow); + SubInfoRecord subInfoRecord = mSubInfoRecords.get(i); + simRow.setTag(subInfoRecord); + simRow.setOnClickListener(mSetDataSimClickListener); + mNameViews.put(i, (TextView) simRow.findViewById(R.id.sim_title)); + mSignalViews.put(i, (ImageView) simRow.findViewById(R.id.signal)); + mCheckBoxes.put(i, (CheckBox) simRow.findViewById(R.id.enable_check)); + mPhoneStateListeners.put(i, createPhoneStateListener(subInfoRecord)); + mPageView.addView(inflater.inflate(R.layout.divider, null)); + } + mPhone = (TelephonyManager)getActivity().getSystemService(Context.TELEPHONY_SERVICE); + for (int i = 0; i < mPhoneStateListeners.size(); i++) { + mPhone.listen(mPhoneStateListeners.get(i), + PhoneStateListener.LISTEN_SERVICE_STATE + | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); + } + updateSignalStrengths(); + updateCurrentDataSub(); + } + + @Override + protected int getLayoutResource() { + return R.layout.choose_data_sim_page; + } + + @Override + public void onResume() { + super.onResume(); + updateSignalStrengths(); + updateCurrentDataSub(); + } + + @Override + public void onDetach() { + super.onDetach(); + for (int i = 0; i < mPhoneStateListeners.size(); i++) { + mPhone.listen(mPhoneStateListeners.get(i), PhoneStateListener.LISTEN_NONE); + } + } + + private PhoneStateListener createPhoneStateListener(final SubInfoRecord subInfoRecord) { + return new PhoneStateListener(subInfoRecord.subId) { + + @Override + public void onSignalStrengthsChanged(SignalStrength signalStrength) { + mSignalStrengths.put(subInfoRecord.slotId, signalStrength); + updateSignalStrength(subInfoRecord); + } + + @Override + public void onServiceStateChanged(ServiceState state) { + mServiceStates.put(subInfoRecord.slotId, state); + updateSignalStrength(subInfoRecord); + } + }; + } + + private void updateSignalStrengths() { + for (int i = 0; i < mSubInfoRecords.size(); i++) { + updateSignalStrength(mSubInfoRecords.get(i)); + } + } + + private void setDataSubChecked(SubInfoRecord subInfoRecord) { + for (int i = 0; i < mCheckBoxes.size(); i++) { + mCheckBoxes.get(i).setChecked(subInfoRecord.slotId == i); + + } + } + + private void updateCurrentDataSub() { + for (int i = 0; i < mSubInfoRecords.size(); i++) { + SubInfoRecord subInfoRecord = mSubInfoRecords.get(i); + mCheckBoxes.get(i).setChecked(SubscriptionManager.getDefaultDataSubId() + == subInfoRecord.subId); + + } + } + + private void updateCarrierText(SubInfoRecord subInfoRecord) { + String name = mPhone.getNetworkOperatorName(subInfoRecord.subId); + ServiceState serviceState = mServiceStates.get(subInfoRecord.slotId); + if (TextUtils.isEmpty(name)) { + if (serviceState != null && serviceState.isEmergencyOnly()) { + name = getString(R.string.setup_mobile_data_emergency_only); + } else { + name = getString(R.string.setup_mobile_data_no_service); + } + } + String formattedName = + getString(R.string.data_sim_name, subInfoRecord.slotId + 1, name); + mNameViews.get(subInfoRecord.slotId).setText(formattedName); + } + + private void updateSignalStrength(SubInfoRecord subInfoRecord) { + ImageView signalView = mSignalViews.get(subInfoRecord.slotId); + SignalStrength signalStrength = mSignalStrengths.get(subInfoRecord.slotId); + if (!hasService(subInfoRecord)) { + signalView.setImageResource(R.drawable.ic_signal_no_signal); + } else { + if (signalStrength != null) { + int resId; + switch (signalStrength.getLevel()) { + case 4: + resId = R.drawable.ic_signal_4; + break; + case 3: + resId = R.drawable.ic_signal_3; + break; + case 2: + resId = R.drawable.ic_signal_2; + break; + case 1: + resId = R.drawable.ic_signal_1; + break; + default: + resId = R.drawable.ic_signal_0; + break; + } + signalView.setImageResource(resId); + } + } + updateCarrierText(subInfoRecord); + } + + private boolean hasService(SubInfoRecord subInfoRecord) { + boolean retVal; + ServiceState serviceState = mServiceStates.get(subInfoRecord.slotId); + if (serviceState != null) { + // Consider the device to be in service if either voice or data service is available. + // Some SIM cards are marketed as data-only and do not support voice service, and on + // these SIM cards, we want to show signal bars for data service as well as the "no + // service" or "emergency calls only" text that indicates that voice is not available. + switch(serviceState.getVoiceRegState()) { + case ServiceState.STATE_POWER_OFF: + retVal = false; + break; + case ServiceState.STATE_OUT_OF_SERVICE: + case ServiceState.STATE_EMERGENCY_ONLY: + retVal = serviceState.getDataRegState() == ServiceState.STATE_IN_SERVICE; + break; + default: + retVal = true; + } + } else { + retVal = false; + } + Log.d(TAG, "hasService: mServiceState=" + serviceState + " retVal=" + retVal); + return retVal; + } + } + +} diff --git a/src/com/cyanogenmod/setupwizard/setup/CyanogenAccountPage.java b/src/com/cyanogenmod/setupwizard/setup/CyanogenAccountPage.java new file mode 100644 index 0000000..dc48faa --- /dev/null +++ b/src/com/cyanogenmod/setupwizard/setup/CyanogenAccountPage.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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.cyanogenmod.setupwizard.setup; + +import com.cyanogenmod.setupwizard.SetupWizardApp; +import com.cyanogenmod.setupwizard.R; + +import android.accounts.AccountManager; +import android.accounts.AccountManagerCallback; +import android.accounts.AccountManagerFuture; +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; + +public class CyanogenAccountPage extends SetupPage { + + public static final String TAG = "CyanogenAccountPage"; + + public CyanogenAccountPage(Context context, SetupDataCallbacks callbacks) { + super(context, callbacks); + } + + @Override + public int getNextButtonTitleResId() { + return R.string.skip; + } + + @Override + public String getKey() { + return TAG; + } + + @Override + public int getTitleResId() { + return -1; + } + + @Override + public void doLoadAction(Activity context, int action) { + launchCyanogenAccountSetup(context, action); + } + + public void launchCyanogenAccountSetup(final Activity activity, final int action) { + Bundle bundle = new Bundle(); + bundle.putBoolean(SetupWizardApp.EXTRA_FIRST_RUN, true); + AccountManager + .get(activity).addAccount(SetupWizardApp.ACCOUNT_TYPE_CYANOGEN, null, null, bundle, + activity, new AccountManagerCallback<Bundle>() { + @Override + public void run(AccountManagerFuture<Bundle> bundleAccountManagerFuture) { + if (activity == null) return; //There is a chance this activity has been torn down. + if (accountExists(activity, SetupWizardApp.ACCOUNT_TYPE_CYANOGEN)) { + setCompleted(true); + getCallbacks().onNextPage(); + } else { + if (action == Page.ACTION_NEXT) { + getCallbacks().onNextPage(); + } else { + getCallbacks().onPreviousPage(); + } + } + } + }, null); + } + + private boolean accountExists(Activity activity, String accountType) { + return AccountManager.get(activity).getAccountsByType(accountType).length > 0; + } +} diff --git a/src/com/cyanogenmod/setupwizard/setup/DateTimePage.java b/src/com/cyanogenmod/setupwizard/setup/DateTimePage.java new file mode 100644 index 0000000..40eda95 --- /dev/null +++ b/src/com/cyanogenmod/setupwizard/setup/DateTimePage.java @@ -0,0 +1,464 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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.cyanogenmod.setupwizard.setup; + +import com.cyanogenmod.setupwizard.R; +import com.cyanogenmod.setupwizard.ui.SetupPageFragment; + +import org.xmlpull.v1.XmlPullParserException; + +import android.app.Activity; +import android.app.AlarmManager; +import android.app.DatePickerDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.app.Fragment; +import android.app.TimePickerDialog; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.XmlResourceParser; +import android.os.Bundle; +import android.os.Handler; +import android.text.format.DateFormat; +import android.util.Log; +import android.view.View; +import android.widget.AdapterView; +import android.widget.DatePicker; +import android.widget.SimpleAdapter; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.TimePicker; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; + +public class DateTimePage extends SetupPage { + + public static final String TAG = "DateTimePage"; + + private static final String KEY_ID = "id"; // value: String + private static final String KEY_DISPLAYNAME = "name"; // value: String + private static final String KEY_GMT = "gmt"; // value: String + private static final String KEY_OFFSET = "offset"; // value: int (Integer) + private static final String XMLTAG_TIMEZONE = "timezone"; + + private static final int HOURS_1 = 60 * 60000; + + + public DateTimePage(Context context, SetupDataCallbacks callbacks) { + super(context, callbacks); + } + + @Override + public Fragment getFragment() { + Bundle args = new Bundle(); + args.putString(SetupPage.KEY_PAGE_ARGUMENT, getKey()); + + DateTimeFragment fragment = new DateTimeFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public String getKey() { + return TAG; + } + + @Override + public int getTitleResId() { + return R.string.setup_datetime; + } + + public static class DateTimeFragment extends SetupPageFragment + implements TimePickerDialog.OnTimeSetListener, DatePickerDialog.OnDateSetListener { + + private TimeZone mCurrentTimeZone; + private View mDateView; + private View mTimeView; + private TextView mDateTextView; + private TextView mTimeTextView; + + + private final Handler mHandler = new Handler(); + + @Override + public void onResume() { + super.onResume(); + // Register for time ticks and other reasons for time change + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_TIME_TICK); + filter.addAction(Intent.ACTION_TIME_CHANGED); + filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); + getActivity().registerReceiver(mIntentReceiver, filter, null, null); + + updateTimeAndDateDisplay(getActivity()); + } + + @Override + public void onPause() { + super.onPause(); + getActivity().unregisterReceiver(mIntentReceiver); + } + + @Override + protected void initializePage() { + final Spinner spinner = (Spinner) mRootView.findViewById(R.id.timezone_list); + final SimpleAdapter adapter = constructTimezoneAdapter(getActivity(), false); + mCurrentTimeZone = TimeZone.getDefault(); + mDateView = mRootView.findViewById(R.id.date_item); + mDateView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + showDatePicker(); + } + }); + mTimeView = mRootView.findViewById(R.id.time_item); + mTimeView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + showTimePicker(); + } + }); + mDateTextView = (TextView)mRootView.findViewById(R.id.date_text); + mTimeTextView = (TextView)mRootView.findViewById(R.id.time_text); + // Pre-select current/default timezone + mHandler.post(new Runnable() { + @Override + public void run() { + int tzIndex = getTimeZoneIndex(adapter, mCurrentTimeZone); + spinner.setAdapter(adapter); + if (tzIndex != -1) { + spinner.setSelection(tzIndex); + } + spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) { + final Map<?, ?> map = (Map<?, ?>) adapterView.getItemAtPosition(position); + final String tzId = (String) map.get(KEY_ID); + if (mCurrentTimeZone != null && !mCurrentTimeZone.getID().equals(tzId)) { + // Update the system timezone value + final Activity activity = getActivity(); + final AlarmManager alarm = (AlarmManager) activity.getSystemService(Context.ALARM_SERVICE); + alarm.setTimeZone(tzId); + mCurrentTimeZone = TimeZone.getTimeZone(tzId); + } + + } + + @Override + public void onNothingSelected(AdapterView<?> adapterView) { + } + }); + } + }); + } + + private void showDatePicker() { + DatePickerFragment datePickerFragment = DatePickerFragment.newInstance(); + datePickerFragment.setOnDateSetListener(this); + datePickerFragment.show(getFragmentManager(), DatePickerFragment.TAG); + } + + private void showTimePicker() { + TimePickerFragment timePickerFragment = TimePickerFragment.newInstance(); + timePickerFragment.setOnTimeSetListener(this); + timePickerFragment.show(getFragmentManager(), TimePickerFragment.TAG); + } + + public void updateTimeAndDateDisplay(Context context) { + java.text.DateFormat shortDateFormat = DateFormat.getDateFormat(context); + final Calendar now = Calendar.getInstance(); + mTimeTextView.setText(DateFormat.getTimeFormat(getActivity()).format(now.getTime())); + mDateTextView.setText(shortDateFormat.format(now.getTime())); + } + + @Override + protected int getLayoutResource() { + return R.layout.setup_datetime_page; + } + + @Override + public void onDateSet(DatePicker view, int year, int month, int day) { + final Activity activity = getActivity(); + if (activity != null) { + setDate(activity, year, month, day); + updateTimeAndDateDisplay(activity); + } + } + + @Override + public void onTimeSet(TimePicker view, int hourOfDay, int minute) { + final Activity activity = getActivity(); + if (activity != null) { + setTime(activity, hourOfDay, minute); + updateTimeAndDateDisplay(activity); + } + } + + private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final Activity activity = getActivity(); + if (activity != null) { + updateTimeAndDateDisplay(activity); + } + } + }; + + } + + private static SimpleAdapter constructTimezoneAdapter(Context context, + boolean sortedByName) { + final String[] from = new String[] {KEY_DISPLAYNAME, KEY_GMT}; + final int[] to = new int[] {android.R.id.text1, android.R.id.text2}; + + final String sortKey = (sortedByName ? KEY_DISPLAYNAME : KEY_OFFSET); + final TimeZoneComparator comparator = new TimeZoneComparator(sortKey); + final List<HashMap<String, Object>> sortedList = getZones(context); + Collections.sort(sortedList, comparator); + final SimpleAdapter adapter = new SimpleAdapter(context, + sortedList, + R.layout.date_time_setup_custom_list_item_2, + from, + to); + + return adapter; + } + + private static List<HashMap<String, Object>> getZones(Context context) { + final List<HashMap<String, Object>> myData = new ArrayList<HashMap<String, Object>>(); + final long date = Calendar.getInstance().getTimeInMillis(); + try { + XmlResourceParser xrp = context.getResources().getXml(R.xml.timezones); + while (xrp.next() != XmlResourceParser.START_TAG) + continue; + xrp.next(); + while (xrp.getEventType() != XmlResourceParser.END_TAG) { + while (xrp.getEventType() != XmlResourceParser.START_TAG) { + if (xrp.getEventType() == XmlResourceParser.END_DOCUMENT) { + return myData; + } + xrp.next(); + } + if (xrp.getName().equals(XMLTAG_TIMEZONE)) { + String id = xrp.getAttributeValue(0); + String displayName = xrp.nextText(); + addItem(myData, id, displayName, date); + } + while (xrp.getEventType() != XmlResourceParser.END_TAG) { + xrp.next(); + } + xrp.next(); + } + xrp.close(); + } catch (XmlPullParserException xppe) { + Log.e(TAG, "Ill-formatted timezones.xml file"); + } catch (java.io.IOException ioe) { + Log.e(TAG, "Unable to read timezones.xml file"); + } + + return myData; + } + + private static void addItem( + List<HashMap<String, Object>> myData, String id, String displayName, long date) { + final HashMap<String, Object> map = new HashMap<String, Object>(); + map.put(KEY_ID, id); + map.put(KEY_DISPLAYNAME, displayName); + final TimeZone tz = TimeZone.getTimeZone(id); + final int offset = tz.getOffset(date); + final int p = Math.abs(offset); + final StringBuilder name = new StringBuilder(); + name.append("GMT"); + + if (offset < 0) { + name.append('-'); + } else { + name.append('+'); + } + + name.append(p / (HOURS_1)); + name.append(':'); + + int min = p / 60000; + min %= 60; + + if (min < 10) { + name.append('0'); + } + name.append(min); + + map.put(KEY_GMT, name.toString()); + map.put(KEY_OFFSET, offset); + + myData.add(map); + } + + private static int getTimeZoneIndex(SimpleAdapter adapter, TimeZone tz) { + final String defaultId = tz.getID(); + final int listSize = adapter.getCount(); + for (int i = 0; i < listSize; i++) { + // Using HashMap<String, Object> induces unnecessary warning. + final HashMap<?,?> map = (HashMap<?,?>)adapter.getItem(i); + final String id = (String)map.get(KEY_ID); + if (defaultId.equals(id)) { + // If current timezone is in this list, move focus to it + return i; + } + } + return -1; + } + + private static void setDate(Context context, int year, int month, int day) { + Calendar c = Calendar.getInstance(); + + c.set(Calendar.YEAR, year); + c.set(Calendar.MONTH, month); + c.set(Calendar.DAY_OF_MONTH, day); + long when = c.getTimeInMillis(); + + if (when / 1000 < Integer.MAX_VALUE) { + ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).setTime(when); + } + } + + private static void setTime(Context context, int hourOfDay, int minute) { + Calendar c = Calendar.getInstance(); + + c.set(Calendar.HOUR_OF_DAY, hourOfDay); + c.set(Calendar.MINUTE, minute); + c.set(Calendar.SECOND, 0); + c.set(Calendar.MILLISECOND, 0); + long when = c.getTimeInMillis(); + + if (when / 1000 < Integer.MAX_VALUE) { + ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).setTime(when); + } + } + + private static class TimeZoneComparator implements Comparator<HashMap<?, ?>> { + private String mSortingKey; + + public TimeZoneComparator(String sortingKey) { + mSortingKey = sortingKey; + } + + public void setSortingKey(String sortingKey) { + mSortingKey = sortingKey; + } + + public int compare(HashMap<?, ?> map1, HashMap<?, ?> map2) { + Object value1 = map1.get(mSortingKey); + Object value2 = map2.get(mSortingKey); + + /* + * This should never happen, but just in-case, put non-comparable + * items at the end. + */ + if (!isComparable(value1)) { + return isComparable(value2) ? 1 : 0; + } else if (!isComparable(value2)) { + return -1; + } + + return ((Comparable) value1).compareTo(value2); + } + + private boolean isComparable(Object value) { + return (value != null) && (value instanceof Comparable); + } + } + + private static class TimePickerFragment extends DialogFragment implements TimePickerDialog.OnTimeSetListener { + + private static String TAG = TimePickerFragment.class.getSimpleName(); + + private TimePickerDialog.OnTimeSetListener mOnTimeSetListener; + + public static TimePickerFragment newInstance() { + TimePickerFragment frag = new TimePickerFragment(); + return frag; + } + + private void setOnTimeSetListener(TimePickerDialog.OnTimeSetListener onTimeSetListener) { + mOnTimeSetListener = onTimeSetListener; + } + + @Override + public void onTimeSet(TimePicker view, int hourOfDay, int minute) { + if (mOnTimeSetListener != null) { + mOnTimeSetListener.onTimeSet(view, hourOfDay, minute); + } + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Calendar calendar = Calendar.getInstance(); + return new TimePickerDialog( + getActivity(), + this, + calendar.get(Calendar.HOUR_OF_DAY), + calendar.get(Calendar.MINUTE), + DateFormat.is24HourFormat(getActivity())); + + } + } + + private static class DatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener { + + private static String TAG = DatePickerFragment.class.getSimpleName(); + + private DatePickerDialog.OnDateSetListener mOnDateSetListener; + + public static DatePickerFragment newInstance() { + DatePickerFragment frag = new DatePickerFragment(); + return frag; + } + + private void setOnDateSetListener(DatePickerDialog.OnDateSetListener onDateSetListener) { + mOnDateSetListener = onDateSetListener; + } + + @Override + public void onDateSet(DatePicker view, int year, int month, int day) { + if (mOnDateSetListener != null) { + mOnDateSetListener.onDateSet(view, year, month, day); + } + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Calendar calendar = Calendar.getInstance(); + return new DatePickerDialog( + getActivity(), + this, + calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH), + calendar.get(Calendar.DAY_OF_MONTH)); + + } + } + +} diff --git a/src/com/cyanogenmod/setupwizard/setup/FinishPage.java b/src/com/cyanogenmod/setupwizard/setup/FinishPage.java new file mode 100644 index 0000000..1ab0df9 --- /dev/null +++ b/src/com/cyanogenmod/setupwizard/setup/FinishPage.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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.cyanogenmod.setupwizard.setup; + +import com.cyanogenmod.setupwizard.R; +import com.cyanogenmod.setupwizard.ui.SetupPageFragment; + +import android.app.Fragment; +import android.content.Context; +import android.os.Bundle; + +public class FinishPage extends SetupPage { + + public static final String TAG = "FinishPage"; + + public FinishPage(Context context, SetupDataCallbacks callbacks) { + super(context, callbacks); + } + + @Override + public Fragment getFragment() { + Bundle args = new Bundle(); + args.putString(SetupPage.KEY_PAGE_ARGUMENT, getKey()); + + FinishFragment fragment = new FinishFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public String getKey() { + return TAG; + } + + @Override + public int getTitleResId() { + return R.string.setup_complete; + } + + @Override + public boolean doNextAction() { + getCallbacks().onFinish(); + return true; + } + + @Override + public int getNextButtonTitleResId() { + return R.string.start; + } + + @Override + public int getPrevButtonTitleResId() { + return -1; + } + + public static class FinishFragment extends SetupPageFragment { + + @Override + protected void initializePage() {} + + @Override + protected int getLayoutResource() { + return R.layout.setup_finished_page; + } + + @Override + protected int getHeaderLayoutResource() { + return -1; + } + } + +} diff --git a/src/com/cyanogenmod/setupwizard/setup/GmsAccountPage.java b/src/com/cyanogenmod/setupwizard/setup/GmsAccountPage.java new file mode 100644 index 0000000..a7d2aa8 --- /dev/null +++ b/src/com/cyanogenmod/setupwizard/setup/GmsAccountPage.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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.cyanogenmod.setupwizard.setup; + +import android.accounts.AccountManager; +import android.accounts.AccountManagerCallback; +import android.accounts.AccountManagerFuture; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; +import android.app.Activity; +import android.content.Context; +import android.os.Bundle; + +import com.cyanogenmod.setupwizard.R; +import com.cyanogenmod.setupwizard.SetupWizardApp; + +import java.io.IOException; + +public class GmsAccountPage extends SetupPage { + + public static final String TAG = "GmsAccountPage"; + + public GmsAccountPage(Context context, SetupDataCallbacks callbacks) { + super(context, callbacks); + } + + @Override + public String getKey() { + return TAG; + } + + @Override + public int getTitleResId() { + return R.string.setup_gms_account; + } + + @Override + public int getNextButtonTitleResId() { + return R.string.skip; + } + + @Override + public void doLoadAction(Activity context, int action) { + launchGmsAccountSetup(context, action); + } + + public void launchGmsAccountSetup(final Activity activity, final int action) { + Bundle bundle = new Bundle(); + bundle.putBoolean(SetupWizardApp.EXTRA_FIRST_RUN, true); + bundle.putBoolean(SetupWizardApp.EXTRA_ALLOW_SKIP, true); + AccountManager + .get(activity).addAccount(SetupWizardApp.ACCOUNT_TYPE_GMS, null, null, + bundle, activity, new AccountManagerCallback<Bundle>() { + @Override + public void run(AccountManagerFuture<Bundle> bundleAccountManagerFuture) { + //There is a chance this activity has been torn down. + if (activity == null) return; + String token = null; + try { + token = bundleAccountManagerFuture.getResult().getString(AccountManager.KEY_AUTHTOKEN); + } catch (OperationCanceledException e) { + } catch (IOException e) { + } catch (AuthenticatorException e) { + } + if (token != null) { + setCompleted(true); + } + if (action == Page.ACTION_NEXT) { + getCallbacks().onNextPage(); + } else { + getCallbacks().onPreviousPage(); + } + } + }, null); + } +} diff --git a/src/com/cyanogenmod/setupwizard/setup/LocationSettingsPage.java b/src/com/cyanogenmod/setupwizard/setup/LocationSettingsPage.java new file mode 100644 index 0000000..00865f4 --- /dev/null +++ b/src/com/cyanogenmod/setupwizard/setup/LocationSettingsPage.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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.cyanogenmod.setupwizard.setup; + +import android.app.Fragment; +import android.content.ContentQueryMap; +import android.content.ContentResolver; +import android.content.Context; +import android.database.Cursor; +import android.location.LocationManager; +import android.os.Bundle; +import android.provider.Settings; +import android.view.View; +import android.widget.CheckBox; + +import com.cyanogenmod.setupwizard.R; +import com.cyanogenmod.setupwizard.ui.SetupPageFragment; + +import java.util.Observable; +import java.util.Observer; + +public class LocationSettingsPage extends SetupPage { + + private static final String TAG = "LocationSettingsPage"; + + public LocationSettingsPage(Context context, SetupDataCallbacks callbacks) { + super(context, callbacks); + } + + @Override + public Fragment getFragment() { + Bundle args = new Bundle(); + args.putString(Page.KEY_PAGE_ARGUMENT, getKey()); + + LocationSettingsFragment fragment = new LocationSettingsFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public String getKey() { + return TAG; + } + + @Override + public int getTitleResId() { + return R.string.setup_location; + } + + public static class LocationSettingsFragment extends SetupPageFragment { + + private View mLocationRow; + private View mGpsRow; + private View mNetworkRow; + private CheckBox mNetwork; + private CheckBox mGps; + private CheckBox mLocationAccess; + + private ContentResolver mContentResolver; + + // These provide support for receiving notification when Location Manager settings change. + // This is necessary because the Network Location Provider can change settings + // if the user does not confirm enabling the provider. + private ContentQueryMap mContentQueryMap; + private Observer mSettingsObserver; + + + private View.OnClickListener mLocationClickListener = new View.OnClickListener() { + @Override + public void onClick(View view) { + onToggleLocationAccess(!mLocationAccess.isChecked()); + } + }; + + private View.OnClickListener mGpsClickListener = new View.OnClickListener() { + @Override + public void onClick(View view) { + Settings.Secure.setLocationProviderEnabled(mContentResolver, + LocationManager.GPS_PROVIDER, !mGps.isChecked()); + } + }; + + private View.OnClickListener mNetworkClickListener = new View.OnClickListener() { + @Override + public void onClick(View view) { + Settings.Secure.setLocationProviderEnabled(mContentResolver, + LocationManager.NETWORK_PROVIDER, !mNetwork.isChecked()); + } + }; + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + mContentResolver = getActivity().getContentResolver(); + getActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.primary_dark)); + } + + @Override + protected void initializePage() { + mLocationRow = mRootView.findViewById(R.id.location); + mLocationRow.setOnClickListener(mLocationClickListener); + mLocationAccess = (CheckBox) mRootView.findViewById(R.id.location_checkbox); + mGpsRow = mRootView.findViewById(R.id.gps); + mGpsRow.setOnClickListener(mGpsClickListener); + mGps = (CheckBox) mRootView.findViewById(R.id.gps_checkbox); + mNetworkRow = mRootView.findViewById(R.id.network); + mNetworkRow.setOnClickListener(mNetworkClickListener); + mNetwork = (CheckBox) mRootView.findViewById(R.id.network_checkbox); + } + + @Override + protected int getLayoutResource() { + return R.layout.location_settings; + } + + @Override + protected int getHeaderLayoutResource() { + return R.layout.header_condensed; + } + + @Override + public void onResume() { + super.onResume(); + updateLocationToggles(); + if (mSettingsObserver == null) { + mSettingsObserver = new Observer() { + public void update(Observable o, Object arg) { + updateLocationToggles(); + } + }; + } + + mContentQueryMap.addObserver(mSettingsObserver); + } + + @Override + public void onStart() { + super.onStart(); + // listen for Location Manager settings changes + Cursor settingsCursor = getActivity().getContentResolver().query(Settings.Secure.CONTENT_URI, null, + "(" + Settings.System.NAME + "=?)", + new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED}, + null); + mContentQueryMap = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, null); + } + + @Override + public void onStop() { + super.onStop(); + if (mSettingsObserver != null) { + mContentQueryMap.deleteObserver(mSettingsObserver); + } + mContentQueryMap.close(); + } + + + private void updateLocationToggles() { + boolean gpsEnabled = Settings.Secure.isLocationProviderEnabled( + mContentResolver, LocationManager.GPS_PROVIDER); + boolean networkEnabled = Settings.Secure.isLocationProviderEnabled( + mContentResolver, LocationManager.NETWORK_PROVIDER); + mGps.setChecked(gpsEnabled); + mNetwork.setChecked(networkEnabled); + mLocationAccess.setChecked(gpsEnabled || networkEnabled); + } + + private void onToggleLocationAccess(boolean checked) { + Settings.Secure.setLocationProviderEnabled(mContentResolver, + LocationManager.GPS_PROVIDER, checked); + mGps.setEnabled(checked); + mGpsRow.setEnabled(checked); + Settings.Secure.setLocationProviderEnabled(mContentResolver, + LocationManager.NETWORK_PROVIDER, checked); + mNetwork.setEnabled(checked); + mNetworkRow.setEnabled(checked); + updateLocationToggles(); + } + + } +} diff --git a/src/com/cyanogenmod/setupwizard/setup/MobileDataPage.java b/src/com/cyanogenmod/setupwizard/setup/MobileDataPage.java new file mode 100644 index 0000000..9223128 --- /dev/null +++ b/src/com/cyanogenmod/setupwizard/setup/MobileDataPage.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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.cyanogenmod.setupwizard.setup; + +import android.app.Activity; +import android.app.Fragment; +import android.content.Context; +import android.os.Bundle; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; +import android.telephony.SignalStrength; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; +import android.widget.Switch; +import android.widget.TextView; + +import com.cyanogenmod.setupwizard.R; +import com.cyanogenmod.setupwizard.ui.SetupPageFragment; +import com.cyanogenmod.setupwizard.util.SetupWizardUtils; + +public class MobileDataPage extends SetupPage { + + public static final String TAG = "MobileDataPage"; + + public MobileDataPage(Context context, SetupDataCallbacks callbacks) { + super(context, callbacks); + } + + @Override + public Fragment getFragment() { + Bundle args = new Bundle(); + args.putString(SetupPage.KEY_PAGE_ARGUMENT, getKey()); + + MobileDataFragment fragment = new MobileDataFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public String getKey() { + return TAG; + } + + @Override + public int getTitleResId() { + return R.string.setup_mobile_data; + } + + public static class MobileDataFragment extends SetupPageFragment { + + private View mEnableDataRow; + private Switch mEnableMobileData; + private ImageView mSignalView; + private TextView mNameView; + + private TelephonyManager mPhone; + private SignalStrength mSignalStrength; + private ServiceState mServiceState; + + private PhoneStateListener mPhoneStateListener = + new PhoneStateListener(SubscriptionManager.getDefaultDataSubId()) { + + @Override + public void onSignalStrengthsChanged(SignalStrength signalStrength) { + mSignalStrength = signalStrength; + updateSignalStrength(); + } + + @Override + public void onServiceStateChanged(ServiceState state) { + mServiceState = state; + updateSignalStrength(); + } + + }; + + private View.OnClickListener mEnableDataClickListener = new View.OnClickListener() { + @Override + public void onClick(View view) { + boolean checked = !mEnableMobileData.isChecked(); + SetupWizardUtils.setMobileDataEnabled(getActivity(), checked); + mEnableMobileData.setChecked(checked); + } + }; + + @Override + protected void initializePage() { + mEnableDataRow = mRootView.findViewById(R.id.data); + mEnableDataRow.setOnClickListener(mEnableDataClickListener); + mEnableMobileData = (Switch) mRootView.findViewById(R.id.data_switch); + mSignalView = (ImageView) mRootView.findViewById(R.id.signal); + mNameView = (TextView) mRootView.findViewById(R.id.enable_data_title); + updateDataConnectionStatus(); + updateSignalStrength(); + } + + @Override + protected int getLayoutResource() { + return R.layout.mobile_data_settings; + } + + @Override + public void onResume() { + super.onResume(); + updateDataConnectionStatus(); + updateSignalStrength(); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + mPhone = (TelephonyManager)getActivity().getSystemService(Context.TELEPHONY_SERVICE); + mPhone.listen(mPhoneStateListener, + PhoneStateListener.LISTEN_SERVICE_STATE + | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); + } + + @Override + public void onDetach() { + super.onDetach(); + mPhone.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE); + } + + private void updateCarrierText() { + String name = mPhone.getNetworkOperatorName(SubscriptionManager.getDefaultDataSubId()); + if (TextUtils.isEmpty(name)) { + if (mServiceState != null && mServiceState.isEmergencyOnly()) { + name = getString(R.string.setup_mobile_data_emergency_only); + } else { + name = getString(R.string.setup_mobile_data_no_service); + } + } + mNameView.setText(name); + } + + private void updateSignalStrength() { + if (!hasService()) { + mSignalView.setImageResource(R.drawable.ic_signal_no_signal); + } else { + if (mSignalStrength != null) { + int resId; + switch (mSignalStrength.getLevel()) { + case 4: + resId = R.drawable.ic_signal_4; + break; + case 3: + resId = R.drawable.ic_signal_3; + break; + case 2: + resId = R.drawable.ic_signal_2; + break; + case 1: + resId = R.drawable.ic_signal_1; + break; + default: + resId = R.drawable.ic_signal_0; + break; + } + mSignalView.setImageResource(resId); + } + } + updateCarrierText(); + } + + private void updateDataConnectionStatus() { + mEnableMobileData.setChecked(SetupWizardUtils.isMobileDataEnabled(getActivity())); + } + + private boolean hasService() { + boolean retVal; + if (mServiceState != null) { + // Consider the device to be in service if either voice or data service is available. + // Some SIM cards are marketed as data-only and do not support voice service, and on + // these SIM cards, we want to show signal bars for data service as well as the "no + // service" or "emergency calls only" text that indicates that voice is not available. + switch(mServiceState.getVoiceRegState()) { + case ServiceState.STATE_POWER_OFF: + retVal = false; + break; + case ServiceState.STATE_OUT_OF_SERVICE: + case ServiceState.STATE_EMERGENCY_ONLY: + retVal = mServiceState.getDataRegState() == ServiceState.STATE_IN_SERVICE; + break; + default: + retVal = true; + } + } else { + retVal = false; + } + return retVal; + } + + } +} diff --git a/src/com/cyanogenmod/setupwizard/setup/Page.java b/src/com/cyanogenmod/setupwizard/setup/Page.java new file mode 100644 index 0000000..31a02a7 --- /dev/null +++ b/src/com/cyanogenmod/setupwizard/setup/Page.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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.cyanogenmod.setupwizard.setup; + +import android.app.Activity; +import android.app.Fragment; +import android.content.Intent; +import android.os.Bundle; + +public interface Page { + + public static final String KEY_PAGE_ARGUMENT = "key_arg"; + + public static final int ACTION_NEXT = 1; + public static final int ACTION_PREVIOUS = 2; + + public String getKey(); + public int getTitleResId(); + public int getPrevButtonTitleResId(); + public int getNextButtonTitleResId(); + public Fragment getFragment(); + public Bundle getData(); + public void resetData(Bundle data); + public boolean isRequired(); + public Page setRequired(boolean required); + public boolean isCompleted(); + public void setCompleted(boolean completed); + public boolean doPreviousAction(); + public boolean doNextAction(); + public void doLoadAction(Activity context, int action); + public abstract boolean onActivityResult(int requestCode, int resultCode, Intent data); +} diff --git a/src/com/cyanogenmod/setupwizard/setup/PageList.java b/src/com/cyanogenmod/setupwizard/setup/PageList.java new file mode 100644 index 0000000..6709d47 --- /dev/null +++ b/src/com/cyanogenmod/setupwizard/setup/PageList.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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.cyanogenmod.setupwizard.setup; + +import java.util.LinkedHashMap; + +public class PageList extends LinkedHashMap<String, Page> { + + public PageList(Page... pages) { + for (Page page : pages) { + put(page.getKey(), page); + } + } + + public Page getPage(String key) { + return get(key); + } + + public Page getPage(int index) { + int i=0; + for (Page page : values()) { + if (i == index) { + return page; + } + i++; + } + return null; + } + +} diff --git a/src/com/cyanogenmod/setupwizard/setup/SetupDataCallbacks.java b/src/com/cyanogenmod/setupwizard/setup/SetupDataCallbacks.java new file mode 100644 index 0000000..2e787b4 --- /dev/null +++ b/src/com/cyanogenmod/setupwizard/setup/SetupDataCallbacks.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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.cyanogenmod.setupwizard.setup; + +import android.os.Bundle; +import android.view.LayoutInflater; + +public interface SetupDataCallbacks { + void onNextPage(); + void onPreviousPage(); + void onPageLoaded(Page page); + void onPageTreeChanged(); + void onFinish(); + Page getPage(String key); + Page getPage(int key); + void onPageViewCreated(LayoutInflater inflater, Bundle savedInstanceState, int layoutResource); +} diff --git a/src/com/cyanogenmod/setupwizard/setup/SetupPage.java b/src/com/cyanogenmod/setupwizard/setup/SetupPage.java new file mode 100644 index 0000000..c607857 --- /dev/null +++ b/src/com/cyanogenmod/setupwizard/setup/SetupPage.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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.cyanogenmod.setupwizard.setup; + +import com.cyanogenmod.setupwizard.R; + +import android.app.Activity; +import android.app.Fragment; +import android.app.FragmentManager; +import android.app.FragmentTransaction; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + + +public abstract class SetupPage implements Page { + + private final SetupDataCallbacks mCallbacks; + + private Bundle mData = new Bundle(); + private boolean mRequired = false; + private boolean mCompleted = false; + + protected final Context mContext; + + protected SetupPage(Context context, SetupDataCallbacks callbacks) { + mContext = context; + mCallbacks = callbacks; + } + + @Override + public Fragment getFragment() { + return null; + } + + @Override + public int getPrevButtonTitleResId() { + return -1; + } + + @Override + public int getNextButtonTitleResId() { + return R.string.next; + } + + @Override + public boolean doNextAction() { + return false; + } + + @Override + public boolean doPreviousAction() { + return false; + } + + @Override + public void doLoadAction(Activity context, int action) { + if (context == null || context.isFinishing()) { return; } + final FragmentManager fragmentManager = context.getFragmentManager(); + if (action == Page.ACTION_NEXT) { + FragmentTransaction transaction = fragmentManager.beginTransaction(); + transaction.replace(R.id.content, getFragment(), getKey()); + transaction.commit(); + } else { + FragmentTransaction transaction = fragmentManager.beginTransaction(); + transaction.replace(R.id.content, getFragment(), getKey()); + transaction.commit(); + } + } + + @Override + public boolean onActivityResult(int requestCode, int resultCode, Intent data) { + return false; + } + + @Override + public boolean isRequired() { + return mRequired; + } + + @Override + public Page setRequired(boolean required) { + mRequired = required; + return this; + } + + @Override + public boolean isCompleted() { + return mCompleted; + } + + @Override + public void setCompleted(boolean completed) { + mCompleted = completed; + mCallbacks.onNextPage(); + } + + @Override + public Bundle getData() { + return mData; + } + + @Override + public void resetData(Bundle data) { + mData = data; + mCallbacks.onPageLoaded(this); + } + + protected SetupDataCallbacks getCallbacks() { + return mCallbacks; + } +} diff --git a/src/com/cyanogenmod/setupwizard/setup/SimCardMissingPage.java b/src/com/cyanogenmod/setupwizard/setup/SimCardMissingPage.java new file mode 100644 index 0000000..8f74e24 --- /dev/null +++ b/src/com/cyanogenmod/setupwizard/setup/SimCardMissingPage.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2014 The CyanogenMod 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.cyanogenmod.setupwizard.setup; + +import android.app.Fragment; +import android.content.Context; +import android.os.Bundle; + +import com.cyanogenmod.setupwizard.R; +import com.cyanogenmod.setupwizard.ui.SetupPageFragment; + +public class SimCardMissingPage extends SetupPage { + + public static final String TAG = "SimCardMissingPage"; + + public SimCardMissingPage(Context context, SetupDataCallbacks callbacks) { + super(context, callbacks); + } + + @Override + public Fragment getFragment() { + Bundle args = new Bundle(); + args.putString(SetupPage.KEY_PAGE_ARGUMENT, getKey()); + + FinishFragment fragment = new FinishFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public String getKey() { + return TAG; + } + + @Override + public int getTitleResId() { + return R.string.setup_sim_missing; + } + + @Override + public int getNextButtonTitleResId() { + return R.string.skip; + } + + + public static class FinishFragment extends SetupPageFragment { + + @Override + protected void initializePage() {} + + @Override + protected int getLayoutResource() { + return R.layout.sim_missing_page; + } + + } + +} diff --git a/src/com/cyanogenmod/setupwizard/setup/WelcomePage.java b/src/com/cyanogenmod/setupwizard/setup/WelcomePage.java new file mode 100644 index 0000000..ca3bf99 --- /dev/null +++ b/src/com/cyanogenmod/setupwizard/setup/WelcomePage.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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.cyanogenmod.setupwizard.setup; + +import android.app.Fragment; +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.os.Bundle; +import android.os.Handler; +import android.widget.ArrayAdapter; +import android.widget.NumberPicker; + +import com.cyanogenmod.setupwizard.R; +import com.cyanogenmod.setupwizard.ui.LocalePicker; +import com.cyanogenmod.setupwizard.ui.SetupPageFragment; + +import java.util.Locale; + +public class WelcomePage extends SetupPage { + + public static final String TAG = "WelcomePage"; + + public WelcomePage(Context context, SetupDataCallbacks callbacks) { + super(context, callbacks); + } + + @Override + public Fragment getFragment() { + Bundle args = new Bundle(); + args.putString(SetupPage.KEY_PAGE_ARGUMENT, getKey()); + + WelcomeFragment fragment = new WelcomeFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public int getTitleResId() { + return R.string.setup_welcome; + } + + @Override + public String getKey() { + return TAG; + } + + @Override + public int getPrevButtonTitleResId() { + return R.string.emergency_call; + } + + public static class WelcomeFragment extends SetupPageFragment { + + private ArrayAdapter<com.android.internal.app.LocalePicker.LocaleInfo> mLocaleAdapter; + private Locale mInitialLocale; + private Locale mCurrentLocale; + private int[] mAdapterIndices; + + private LocalePicker mLanguagePicker; + + private final Handler mHandler = new Handler(); + + private final Runnable mUpdateLocale = new Runnable() { + public void run() { + if (mCurrentLocale != null) { + com.android.internal.app.LocalePicker.updateLocale(mCurrentLocale); + } + } + }; + + @Override + protected void initializePage() { + mLanguagePicker = (LocalePicker) mRootView.findViewById(R.id.locale_list); + loadLanguages(); + } + + private void loadLanguages() { + mLocaleAdapter = com.android.internal.app.LocalePicker.constructAdapter(getActivity(), R.layout.locale_picker_item, R.id.locale); + mInitialLocale = Locale.getDefault(); + mCurrentLocale = mInitialLocale; + mAdapterIndices = new int[mLocaleAdapter.getCount()]; + int currentLocaleIndex = 0; + String [] labels = new String[mLocaleAdapter.getCount()]; + for (int i=0; i<mAdapterIndices.length; i++) { + com.android.internal.app.LocalePicker.LocaleInfo localLocaleInfo = mLocaleAdapter.getItem(i); + Locale localLocale = localLocaleInfo.getLocale(); + if (localLocale.equals(mCurrentLocale)) { + currentLocaleIndex = i; + } + mAdapterIndices[i] = i; + labels[i] = localLocaleInfo.getLabel(); + } + mLanguagePicker.setDisplayedValues(labels); + mLanguagePicker.setMaxValue(labels.length - 1); + mLanguagePicker.setValue(currentLocaleIndex); + mLanguagePicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS); + mLanguagePicker.setOnValueChangedListener(new LocalePicker.OnValueChangeListener() { + public void onValueChange(LocalePicker picker, int oldVal, int newVal) { + setLocaleFromPicker(); + } + }); + } + + private void setLocaleFromPicker() { + int i = mAdapterIndices[mLanguagePicker.getValue()]; + final com.android.internal.app.LocalePicker.LocaleInfo localLocaleInfo = mLocaleAdapter.getItem(i); + onLocaleChanged(localLocaleInfo.getLocale()); + } + + private void onLocaleChanged(Locale paramLocale) { + Resources localResources = getActivity().getResources(); + Configuration localConfiguration1 = localResources.getConfiguration(); + Configuration localConfiguration2 = new Configuration(); + localConfiguration2.locale = paramLocale; + localResources.updateConfiguration(localConfiguration2, null); + localResources.updateConfiguration(localConfiguration1, null); + mHandler.removeCallbacks(mUpdateLocale); + mCurrentLocale = paramLocale; + mHandler.postDelayed(mUpdateLocale, 1000); + } + + @Override + protected int getLayoutResource() { + return R.layout.setup_welcome_page; + } + + @Override + protected int getHeaderLayoutResource() { + return R.layout.logo_header; + } + } + +} diff --git a/src/com/cyanogenmod/setupwizard/setup/WifiSetupPage.java b/src/com/cyanogenmod/setupwizard/setup/WifiSetupPage.java new file mode 100644 index 0000000..705b932 --- /dev/null +++ b/src/com/cyanogenmod/setupwizard/setup/WifiSetupPage.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2013 The CyanogenMod 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.cyanogenmod.setupwizard.setup; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; + +import com.cyanogenmod.setupwizard.R; +import com.cyanogenmod.setupwizard.SetupWizardApp; +import com.cyanogenmod.setupwizard.util.SetupWizardUtils; + +public class WifiSetupPage extends SetupPage { + + public static final String TAG = "WifiSetupPage"; + + public WifiSetupPage(Context context, SetupDataCallbacks callbacks) { + super(context, callbacks); + } + + @Override + public int getNextButtonTitleResId() { + return R.string.skip; + } + + @Override + public String getKey() { + return TAG; + } + + @Override + public int getTitleResId() { + return R.string.existing; + } + + @Override + public void doLoadAction(Activity context, int action) { + if (action == Page.ACTION_PREVIOUS) { + getCallbacks().onPreviousPage(); + } else { + SetupWizardUtils.launchWifiSetup(context); + } + } + + @Override + public boolean onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode != SetupWizardApp.REQUEST_CODE_SETUP_WIFI) return false; + getCallbacks().onNextPage(); + return true; + } +} |