package com.jphonelite; import android.app.*; import android.os.*; import android.view.*; import android.widget.*; import android.util.*; import android.net.*; import android.database.*; import android.provider.*; import android.provider.Contacts.*; import android.content.*; import java.util.*; import javaforce.*; import javaforce.voip.*; /** * jPhoneLite for Android : Main Activity * * author : Peter Quiring (pquiring at gmail dot com) * * website : jphonelite.sourceforge.net */ public class Main extends Activity { private String ICICLE_KEY = "jpl-view"; private TextView dial, status; private Button l1, l2, l3, l4, l5, l6; private Button xfr, hld, aa, ac, dnd, cnf; private Button n0, n1, n2, n3, n4, n5, n6, n7, n8, n9; private Button star, pound; private Button contacts, callButton, del; protected static Button spk; private Button lineButtons[]; //make it easy to access them private java.util.Timer buttonTimer; private final int PICK_CONTACT = 0; private final int VIEW_SETTINGS = 1; private final int DIALOG_CONTACTS_ID = 0; private final int DIALOG_ABOUT_ID = 1; private ArrayList<CharSequence> contactList; private String ns; //notification service private NotificationManager mNotificationManager; private final int NOTIFY_ID = 1; private boolean pickingContact = false; public static Handler handler = null; public boolean exiting = false; public Engine engine; public static boolean active = false; /** * Called when Activity is first created. Turns off the title bar, sets up * the content views, and fires up the View. */ @Override public void onCreate(Bundle savedInstanceState) { JFLog.log( "onCreate()"+this); super.onCreate(savedInstanceState); try { if (handler == null) handler = new Handler(); requestWindowFeature(Window.FEATURE_NO_TITLE); // No Title bar ns = Context.NOTIFICATION_SERVICE; mNotificationManager = (NotificationManager) getSystemService(ns); engine = Engine.getInstance(this, this); showView(); spk.setBackgroundResource(Settings.current.speakerMode ? R.drawable.spk_green : R.drawable.spk_grey); } catch (Exception e) { JFLog.log(e); } } @Override protected void onStart() { JFLog.log( "onStart()"+this); super.onStart(); // The activity is about to become visible. } @Override protected void onResume() { JFLog.log( "onResume()"+this); super.onResume(); // The activity has become visible (it is now "resumed"). active = true; notify(null, false); startButtonTimer(); updateScreen(); } @Override protected void onPause() { JFLog.log( "onPause()"+this); super.onPause(); // Pause the app along with the activity try { active = false; stopButtonTimer(); if ((engine.active) && (!pickingContact)) { if (!exiting) { if (engine.line == -1) notify("Idle", false); else notify(engine.lines[engine.line].incall ? "Incall" : "Idle", false); } if (!isFinishing()) finish(); //BUG : notify() intent still sometimes creates a second instance of this class (so confusing) } } catch (Exception e) { JFLog.log(e); } } @Override protected void onStop() { JFLog.log( "onStop()"+this); super.onStop(); // The activity is no longer visible (it is now "stopped") } @Override protected void onDestroy() { JFLog.log( "onDestroy()"+this); super.onDestroy(); // The activity is about to be destroyed. } @Override public void onSaveInstanceState(Bundle outState) { //Store the game state outState.putBundle(ICICLE_KEY, saveState()); } public void notify(String msg, boolean sound) { try { if (msg == null) { mNotificationManager.cancel(NOTIFY_ID); return; } int icon = R.drawable.ic_main; CharSequence tickerText = msg; long when = System.currentTimeMillis(); Notification notification = new Notification(icon, tickerText, when); Context context = getApplicationContext(); CharSequence contentTitle = "VoIP Phone Status"; CharSequence contentText = msg; Intent notificationIntent = new Intent(this, Main.class); notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0); notification.setLatestEventInfo(context, contentTitle, contentText, pendingIntent); if (sound) { notification.defaults |= Notification.DEFAULT_SOUND; notification.defaults |= Notification.DEFAULT_VIBRATE; } mNotificationManager.notify(NOTIFY_ID, notification); } catch (Exception e) { JFLog.log(e); } } /** * Restore game state if our process is being relaunched * * @param icicle a Bundle containing the app state */ public void restoreState(Bundle icicle) { // member = icicle.getX("name"); } /** * Saves state if our process is being relaunched * * @return a Bundle containing the app state */ public Bundle saveState() { Bundle map = new Bundle(); // map.putX("name", value); return map; } @Override public boolean onCreateOptionsMenu(Menu menu) { try { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main, menu); } catch (Exception e) { JFLog.log(e); } return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection switch (item.getItemId()) { case R.id.about: about(); return true; case R.id.settings: showSettings(); return true; case R.id.exit: exiting = true; if (engine.active) { engine.uninit(); engine.release(); } finish(); return true; default: return super.onOptionsItemSelected(item); } } protected Dialog onCreateDialog(int id) { try { Dialog dialog; AlertDialog.Builder builder = new AlertDialog.Builder(this); switch(id) { case DIALOG_CONTACTS_ID: builder.setTitle("Pick a number"); builder.setItems((CharSequence[])contactList.toArray(new CharSequence[] {}), new DialogInterface.OnClickListener() { private ArrayList<CharSequence> contactList; public void onClick(DialogInterface dialog, int item) { String res[] = contactList.get(item).toString().split(":"); engine.lines[engine.line].dial = res[0].replaceAll("-", ""); updateScreen(); } public DialogInterface.OnClickListener init(ArrayList<CharSequence> contactList) { this.contactList = contactList; return this; } }.init(contactList)); dialog = builder.create(); break; case DIALOG_ABOUT_ID: builder.setTitle("About") .setMessage(R.string.main_about_text) .setCancelable(false) .setPositiveButton("Ok", null); dialog = builder.create(); break; default: dialog = null; } return dialog; } catch (Exception e) { JFLog.log(e); } return null; } protected void onPrepareDialog (int id, Dialog dialog) { switch (id) { case DIALOG_CONTACTS_ID: } } private String getType(String type) { if (type.equals("1")) return "HOME"; if (type.equals("2")) return "MOBILE"; if (type.equals("3")) return "WORK"; return "OTHER"; } @Override public void onActivityResult(int reqCode, int resultCode, Intent data) { super.onActivityResult(reqCode, resultCode, data); //JFLog.log( "onActivityResult(" + reqCode + "," + resultCode + "," + data); try { switch (reqCode) { case PICK_CONTACT: pickingContact = false; // if (resultCode == Activity.RESULT_OK) { if (data == null) break; Uri contactData = data.getData(); if (contactData == null) break; //JFLog.log( "Uri=" + contactData); ContentResolver cr = getContentResolver(); Cursor c = managedQuery(contactData, null, null, null, null); //JFLog.log( "Cursor=" + c); if (c.moveToFirst()) { //JFLog.log( "moveToFirst = true"); if (Integer.parseInt(c.getString(c.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) { String id = c.getString(c.getColumnIndex(ContactsContract.Contacts._ID)); Cursor pCur = managedQuery(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[]{id}, null); contactList = new ArrayList<CharSequence>(); while (pCur.moveToNext()) { String num = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)); String type = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE)); if (num != null) { //JFLog.log( "num=" + num + ",type=" + type); String ent = num.replaceAll("-", "") + ":" + getType(type); boolean dup = false; for(int a=0;a<contactList.size();a++) { if (contactList.get(a).toString().split(":")[0].equals(ent.split(":")[0])) {dup = true; break;} } if (!dup) contactList.add((CharSequence)ent); } } if (contactList.size() > 1) { //JFLog.log( "contactList.size=" + contactList.size()); removeDialog(DIALOG_CONTACTS_ID); //make sure it's deleted showDialog(DIALOG_CONTACTS_ID); } else if (contactList.size() == 1) { String res[] = contactList.get(0).toString().split(":"); engine.lines[engine.line].dial = res[0].replaceAll("-", ""); updateScreen(); } } } // } break; case VIEW_SETTINGS: //return from ViewSettings engine.reinit(); updateScreen(); break; } } catch (Exception e) { JFLog.log(e); } } public void showView() { // Display display = getWindowManager().getDefaultDisplay(); // JFLog.log( "ScreenSize=" + display.getWidth() + "x" + display.getHeight()); try { setContentView(R.layout.main); dial = (TextView) findViewById(R.id.main_text1); status = (TextView) findViewById(R.id.main_text2); spk = (Button) findViewById(R.id.main_spk); spk.setBackgroundResource(Settings.current.speakerMode ? R.drawable.spk_green : R.drawable.spk_grey); l1 = (Button) findViewById(R.id.main_l1); l2 = (Button) findViewById(R.id.main_l2); l3 = (Button) findViewById(R.id.main_l3); l4 = (Button) findViewById(R.id.main_l4); l5 = (Button) findViewById(R.id.main_l5); l6 = (Button) findViewById(R.id.main_l6); lineButtons = new Button[6]; lineButtons[0] = l1; lineButtons[1] = l2; lineButtons[2] = l3; lineButtons[3] = l4; lineButtons[4] = l5; lineButtons[5] = l6; xfr = (Button) findViewById(R.id.main_xfr); hld = (Button) findViewById(R.id.main_hld); aa = (Button) findViewById(R.id.main_aa); ac = (Button) findViewById(R.id.main_ac); dnd = (Button) findViewById(R.id.main_dnd); cnf = (Button) findViewById(R.id.main_cnf); n0 = (Button) findViewById(R.id.main_0); n0.setBackgroundResource( R.drawable.phone_0 ); n1 = (Button) findViewById(R.id.main_1); n1.setBackgroundResource( R.drawable.phone_1 ); n2 = (Button) findViewById(R.id.main_2); n2.setBackgroundResource( R.drawable.phone_2 ); n3 = (Button) findViewById(R.id.main_3); n3.setBackgroundResource( R.drawable.phone_3 ); n4 = (Button) findViewById(R.id.main_4); n4.setBackgroundResource( R.drawable.phone_4 ); n5 = (Button) findViewById(R.id.main_5); n5.setBackgroundResource( R.drawable.phone_5 ); n6 = (Button) findViewById(R.id.main_6); n6.setBackgroundResource( R.drawable.phone_6 ); n7 = (Button) findViewById(R.id.main_7); n7.setBackgroundResource( R.drawable.phone_7 ); n8 = (Button) findViewById(R.id.main_8); n8.setBackgroundResource( R.drawable.phone_8 ); n9 = (Button) findViewById(R.id.main_9); n9.setBackgroundResource( R.drawable.phone_9 ); star = (Button) findViewById(R.id.main_star); star.setBackgroundResource( R.drawable.phone_star ); pound = (Button) findViewById(R.id.main_pound); pound.setBackgroundResource( R.drawable.phone_pound ); contacts = (Button) findViewById(R.id.main_contacts); contacts.setBackgroundResource( R.drawable.phone_contacts ); callButton = (Button) findViewById(R.id.main_call); callButton.setBackgroundResource( R.drawable.phone_green ); del = (Button) findViewById(R.id.main_del); del.setBackgroundResource( R.drawable.phone_del ); spk.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { Settings.current.speakerMode = !Settings.current.speakerMode; spk.setBackgroundResource(Settings.current.speakerMode ? R.drawable.spk_green : R.drawable.spk_grey); engine.sound.restartSound(); } }); l1.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { engine.selectLine(0); } }); l2.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { engine.selectLine(1); } }); l3.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { engine.selectLine(2); } }); l4.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { engine.selectLine(3); } }); l5.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { engine.selectLine(4); } }); l6.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { engine.selectLine(5); } }); xfr.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { do_xfr(); } }); hld.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { do_hld(); } }); aa.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { do_aa(); } }); ac.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { do_ac(); } }); dnd.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { do_dnd(); } }); cnf.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { do_cnf(); } }); n0.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { addDigit('0'); } }); n1.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { addDigit('1'); } }); n2.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { addDigit('2'); } }); n3.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { addDigit('3'); } }); n4.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { addDigit('4'); } }); n5.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { addDigit('5'); } }); n6.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { addDigit('6'); } }); n7.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { addDigit('7'); } }); n8.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { addDigit('8'); } }); n9.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { addDigit('9'); } }); star.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { addDigit('*'); } }); pound.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { addDigit('#'); } }); contacts.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { do_contacts(); } }); del.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { do_del(); } }); del.setOnLongClickListener(new View.OnLongClickListener() { public boolean onLongClick(View v) { engine.clearDial(); return true; } }); callButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { do_call(); } }); callButton.setOnLongClickListener(new View.OnLongClickListener() { public boolean onLongClick(View v) { redial(); return true; } }); aa.setBackgroundResource( Settings.current.aa ? R.drawable.sel_green : R.drawable.sel_grey ); ac.setBackgroundResource( Settings.current.ac ? R.drawable.sel_green : R.drawable.sel_grey ); } catch (Exception e) { JFLog.log(e); } } public void setText(TextView tv, String str) { try { tv.setText(str.toCharArray(),0,str.length()); } catch (Exception e) { JFLog.log(e); } } public void startButtonTimer() { try { if (buttonTimer == null) { buttonTimer = new Timer(); buttonTimer.schedule(new ButtonColorUpdater(), 250, 250); } } catch (Exception e) { JFLog.log(e); } } public void stopButtonTimer() { try { if (buttonTimer != null) { buttonTimer.cancel(); buttonTimer = null; } } catch (Exception e) { JFLog.log(e); } } public void do_xfr() { try { engine.do_xfr(); updateScreen(); } catch (Exception e) { JFLog.log(e); } } public void do_hld() { try { engine.do_hld(); updateScreen(); } catch (Exception e) { JFLog.log(e); } } public void do_aa() { try { Settings.current.aa = !Settings.current.aa; aa.setBackgroundResource( Settings.current.aa ? R.drawable.sel_green : R.drawable.sel_grey ); } catch (Exception e) { JFLog.log(e); } } public void do_ac() { try { Settings.current.ac = !Settings.current.ac; ac.setBackgroundResource( Settings.current.ac ? R.drawable.sel_green : R.drawable.sel_grey ); } catch (Exception e) { JFLog.log(e); } } public void do_dnd() { try { engine.do_dnd(); updateScreen(); call(); } catch (Exception e) { JFLog.log(e); } } public void do_cnf() { try { engine.do_cnf(); updateScreen(); } catch (Exception e) { JFLog.log(e); } } public void do_call() { try { engine.do_call(); } catch (Exception e) { JFLog.log(e); } } public void do_contacts() { try { if (engine.line == -1) return; if (engine.lines[engine.line].incall) return; pickingContact = true; Intent intent = new Intent(Intent.ACTION_PICK); intent.setType(ContactsContract.Contacts.CONTENT_TYPE); startActivityForResult(intent, PICK_CONTACT); } catch (Exception e) { JFLog.log(e); } } public void do_del() { try { addDigit('x'); } catch (Exception e) { JFLog.log(e); } } public void addDigit(char digit) { try { engine.addDigit(digit); updateScreen(); } catch (Exception e) { JFLog.log(e); } } /** Update the number to be dialed, status and buttons for current selected line. */ public void updateScreen() { //JFLog.log( "updateScreen():line=" + engine.line); try { if (engine.line == -1) { setText(dial, ""); setText(status, ""); xfr.setBackgroundResource( R.drawable.sel_grey ); hld.setBackgroundResource( R.drawable.sel_grey ); dnd.setBackgroundResource( R.drawable.sel_grey ); cnf.setBackgroundResource( R.drawable.sel_grey ); callButton.setBackgroundResource( R.drawable.phone_red ); return; } //JFLog.log( "updateScreen():status=" + engine.lines[engine.line].status); setText(dial, engine.lines[engine.line].dial); setText(status, engine.lines[engine.line].status); xfr.setBackgroundResource( engine.lines[engine.line].xfr ? R.drawable.sel_green : R.drawable.sel_grey ); hld.setBackgroundResource( engine.lines[engine.line].hld ? R.drawable.sel_green : R.drawable.sel_grey ); dnd.setBackgroundResource( engine.lines[engine.line].dnd ? R.drawable.sel_green : R.drawable.sel_grey ); cnf.setBackgroundResource( engine.lines[engine.line].cnf ? R.drawable.sel_green : R.drawable.sel_grey ); callButton.setBackgroundResource( engine.lines[engine.line].incall ? R.drawable.phone_red : R.drawable.phone_green ); } catch (Exception e) { JFLog.log(e); } } /** TimerTask executed every 250ms to change the line lights(icons). */ private class ButtonColorUpdater extends TimerTask { private boolean odd = false; public void run() { //JFLog.log( "ButtonColorUpdater:line=" + engine.line); try { int clr = R.drawable.black; for(int a=0;a<6;a++) { if ((engine.lines[a].sip != null) && (engine.lines[a].sip.isRegistered())) { clr = (engine.line == a ? R.drawable.sel_grey : R.drawable.grey); if (engine.lines[a].msgwaiting) { if (odd) clr = (engine.line == a ? R.drawable.sel_orange : R.drawable.orange); } if (engine.lines[a].incoming) { if (odd) clr = (engine.line == a ? R.drawable.sel_green : R.drawable.green); else clr = (engine.line == a ? R.drawable.sel_grey : R.drawable.grey); } else if (engine.lines[a].incall) clr = (engine.line == a ? R.drawable.sel_green : R.drawable.green); } else { if (engine.lines[a].unauth) clr = (engine.line == a ? R.drawable.sel_red : R.drawable.red); else clr = (engine.line == a ? R.drawable.sel_black : R.drawable.black); } if (engine.lines[a].clr != clr) { //JFLog.log( "ButtonColorUpdater:line=" + (a+1) + "=" + clr); _setBackgroundResource(lineButtons[a], clr); engine.lines[a].clr = clr; } } odd = !odd; } catch (Exception e) { JFLog.log(e); } } } /** Starts a call or accepts an inbound call. (may!UI thread) */ public void call() { try { engine.call(); _updateScreen(); } catch (Exception e) { JFLog.log(e); } } public void redial() { try { engine.redial(); updateScreen(); } catch (Exception e) { JFLog.log(e); } } public void about() { try { showDialog(DIALOG_ABOUT_ID); } catch (Exception e) { JFLog.log(e); } } public void showSettings() { try { for(int a=0;a<6;a++) { if (engine.lines[a].incall) return; } engine.uninit(); Intent intent = new Intent(this, ViewSettings.class); startActivityForResult(intent, VIEW_SETTINGS); } catch (Exception e) { JFLog.log(e); } } //these members call the same member without the underscore in the UI thread public void _updateScreen() { try { handler.post(new Runnable() {public void run() { updateScreen(); }}); } catch (Exception e) { JFLog.log(e); } } public static void _setBackgroundResource(Button b, int clr) { try { handler.post(new Runnable() { private Button b; private int clr; public void run() { b.setBackgroundResource(clr); } public Runnable init(Button b, int clr) { this.b = b; this.clr = clr; return this;} }.init(b, clr)); } catch (Exception e) { JFLog.log(e); } } }