blockchain: add name registration
- Allow to register name during account creation
- New account settings allow to see registered name,
if any, or to register a name.
Tuleap: #1157
Change-Id: Ib26cf3325efeee10db0a088f3dd5a9c12de149fb
diff --git a/ring-android/app/src/main/AndroidManifest.xml b/ring-android/app/src/main/AndroidManifest.xml
index d11ee57..326713d 100644
--- a/ring-android/app/src/main/AndroidManifest.xml
+++ b/ring-android/app/src/main/AndroidManifest.xml
@@ -49,6 +49,7 @@
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-feature
android:name="android.hardware.wifi"
@@ -67,22 +68,21 @@
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
- android:supportsRtl="true"
- android:resizeableActivity="true">
+ android:resizeableActivity="true"
+ android:supportsRtl="true">
<activity
android:name=".client.HomeActivity"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
android:label="@string/title_activity_sflphone_home"
- android:theme="@style/AppThemeBase"
- android:windowSoftInputMode="adjustResize"
- android:screenOrientation="fullUser"
android:launchMode="singleTask"
- android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize">
+ android:screenOrientation="fullUser"
+ android:theme="@style/AppThemeBase"
+ android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
-
<intent-filter>
<action android:name="android.intent.action.DIAL" />
<action android:name="android.intent.action.VIEW" />
@@ -134,28 +134,27 @@
<data android:scheme="ring" />
</intent-filter>
-
</activity>
<activity
android:name=".client.AccountWizard"
- android:theme="@style/AppThemeBase"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
android:screenOrientation="fullUser"
- android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize">
+ android:theme="@style/AppThemeBase">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="cx.ring.client.AccountEditionActivity" />
</activity>
<activity
android:name=".client.AccountEditionActivity"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
android:label="@string/app_name"
- android:theme="@style/AppThemeBase"
android:screenOrientation="fullUser"
- android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"/>
+ android:theme="@style/AppThemeBase" />
<activity
android:name=".client.NewConversationActivity"
android:label="@string/app_name"
- android:theme="@style/AppThemeBase"
- android:screenOrientation="fullUser"/>
+ android:screenOrientation="fullUser"
+ android:theme="@style/AppThemeBase" />
<receiver android:name=".service.OutgoingCallHandler">
<intent-filter>
@@ -172,12 +171,11 @@
<activity
android:name=".client.CallActivity"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
android:label="@string/app_name"
android:screenOrientation="fullUser"
- android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
android:theme="@style/AppTheme.ActionBar.Transparent"
android:windowSoftInputMode="adjustPan|stateHidden">
-
<intent-filter>
<action android:name="android.intent.action.CALL" />
@@ -224,7 +222,6 @@
<data android:scheme="ring" />
</intent-filter>
-
<intent-filter>
<action android:name="android.intent.action.CALL" />
<action android:name="android.intent.action.DIAL" />
@@ -238,19 +235,18 @@
</activity>
<activity
android:name=".client.ConversationActivity"
+ android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
android:label="@string/app_name"
android:parentActivityName=".client.HomeActivity"
- android:theme="@style/AppThemeBase"
- android:windowSoftInputMode="adjustResize"
android:screenOrientation="fullUser"
- android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
- />
- <activity android:name=".client.QRCodeScannerActivity"
+ android:theme="@style/AppThemeBase"
+ android:windowSoftInputMode="adjustResize" />
+ <activity
+ android:name=".client.QRCodeScannerActivity"
android:screenOrientation="fullUser"
android:stateNotNeeded="true"
android:theme="@style/zxing_CaptureTheme"
- android:windowSoftInputMode="stateAlwaysHidden">
- </activity>
+ android:windowSoftInputMode="stateAlwaysHidden"></activity>
<service
android:name=".service.LocalService"
@@ -268,4 +264,4 @@
</service>
</application>
-</manifest>
+</manifest>
\ No newline at end of file
diff --git a/ring-android/app/src/main/java/cx/ring/client/AccountEditionActivity.java b/ring-android/app/src/main/java/cx/ring/client/AccountEditionActivity.java
index 8289747..4a55281 100644
--- a/ring-android/app/src/main/java/cx/ring/client/AccountEditionActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/client/AccountEditionActivity.java
@@ -22,49 +22,34 @@
package cx.ring.client;
-import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Fragment;
import android.app.FragmentManager;
-import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Build;
import android.os.Bundle;
-import android.os.Environment;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.NonNull;
-import android.support.design.widget.Snackbar;
+import android.support.annotation.StringRes;
import android.support.v13.app.FragmentPagerAdapter;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.view.inputmethod.EditorInfo;
import android.widget.TextView;
-import android.widget.Toast;
import com.astuetz.PagerSlidingTabStrip;
-import java.io.File;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;
@@ -122,41 +107,23 @@
private boolean mBound = false;
private LocalService mService;
private Account mAccSelected = null;
- private Fragment mCurrentlyDisplayed;
- private Observer mAccountObserver = new Observer() {
+ private Fragment mCurrentlyDisplayed;
+ private ViewPager mViewPager = null;
+ private PagerSlidingTabStrip mSlidingTabLayout = null;
+
+ private final Observer mAccountObserver = new Observer() {
@Override
public void update(Observable observable, Object data) {
- if (mAccSelected == null || mService == null) {
- return;
+ Log.i(TAG, "Observer: account changed !");
+ for (AccountChangedListener l : listeners) {
+ l.accountChanged(mAccSelected);
}
-
- final Account acc = mAccSelected;
- if (getSupportActionBar() != null) {
- getSupportActionBar().setTitle(acc.getAlias());
- }
-
- final IDRingService remote = getRemoteService();
- if (remote == null) {
- Log.w(TAG, "Error updating account, remote service is null");
- return;
- }
- mService.getThreadPool().submit(new Runnable() {
- @Override
- public void run() {
- try {
- remote.setCredentials(acc.getAccountID(), acc.getCredentialsHashMapList());
- remote.setAccountDetails(acc.getAccountID(), acc.getDetails());
- } catch (RemoteException e) {
- Log.e(TAG, "Error while setting credentials", e);
- }
- }
- });
}
};
- private ServiceConnection mConnection = new ServiceConnection() {
+ private final ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder s) {
LocalService.LocalBinder binder = (LocalService.LocalBinder) s;
@@ -174,14 +141,13 @@
mAccSelected.addObserver(mAccountObserver);
getSupportActionBar().setTitle(mAccSelected.getAlias());
- final ViewPager mViewPager = (ViewPager) findViewById(R.id.pager);
+ mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setOffscreenPageLimit(4);
mViewPager.setAdapter(new PreferencesPagerAdapter(getFragmentManager(), AccountEditionActivity.this, mAccSelected.isRing()));
final PagerSlidingTabStrip mSlidingTabLayout = (PagerSlidingTabStrip) findViewById(R.id.sliding_tabs);
mSlidingTabLayout.setViewPager(mViewPager);
-
for (AccountChangedListener listener : listeners) {
listener.accountChanged(mAccSelected);
}
@@ -210,6 +176,13 @@
}
});
+
+ if (mAccSelected.isRing()) {
+ mSlidingTabLayout.setVisibility(View.GONE);
+ mViewPager.setVisibility(View.GONE);
+ mCurrentlyDisplayed = new DeviceAccountFragment();
+ getFragmentManager().beginTransaction().add(R.id.fragment_container, mCurrentlyDisplayed).commit();
+ }
}
@Override
@@ -229,12 +202,30 @@
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ mViewPager = (ViewPager) findViewById(R.id.pager);
+ mSlidingTabLayout = (PagerSlidingTabStrip) findViewById(R.id.sliding_tabs);
+
if (!mBound) {
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
}
+
+ public void editAdvanced() {
+ mSlidingTabLayout.setVisibility(View.VISIBLE);
+ mViewPager.setVisibility(View.VISIBLE);
+ }
+
+ private void finishAdvanced() {
+ mSlidingTabLayout.setVisibility(View.GONE);
+ mViewPager.setVisibility(View.GONE);
+ }
+
+ private boolean isAdvancedSettings() {
+ return mSlidingTabLayout.getVisibility() == View.VISIBLE;
+ }
+
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
@@ -257,7 +248,9 @@
@Override
public void onBackPressed() {
- if (!(mCurrentlyDisplayed instanceof BackHandlerInterface) || !((BackHandlerInterface) mCurrentlyDisplayed).onBackPressed()) {
+ if (isAdvancedSettings()) {
+ finishAdvanced();
+ } else if (!(mCurrentlyDisplayed instanceof BackHandlerInterface) || !((BackHandlerInterface) mCurrentlyDisplayed).onBackPressed()) {
super.onBackPressed();
}
}
@@ -330,6 +323,37 @@
}
@Override
+ public void saveAccount() {
+ if (mAccSelected == null || mService == null) {
+ return;
+ }
+
+ final Account account = mAccSelected;
+ if (getSupportActionBar() != null) {
+ getSupportActionBar().setTitle(account.getAlias());
+ }
+
+ final IDRingService remote = getRemoteService();
+ if (remote == null) {
+ Log.w(TAG, "Error updating account, remote service is null");
+ return;
+ }
+
+ mService.getThreadPool().submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Log.i(TAG, "updating account");
+ remote.setCredentials(account.getAccountID(), account.getCredentialsHashMapList());
+ remote.setAccountDetails(account.getAccountID(), account.getDetails());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception updating account", e);
+ }
+ }
+ });
+ }
+
+ @Override
public IDRingService getRemoteService() {
return mService.getRemoteService();
}
@@ -356,8 +380,6 @@
private static class PreferencesPagerAdapter extends FragmentPagerAdapter {
boolean isRing = false;
- Fragment[] ringFragments = {new DeviceAccountFragment(), new GeneralAccountFragment(), new MediaPreferenceFragment(), new AdvancedAccountFragment()};
- Fragment[] sipFragments = {new GeneralAccountFragment(), new MediaPreferenceFragment(), new AdvancedAccountFragment(), new SecurityAccountFragment()};
private Context ctx;
PreferencesPagerAdapter(FragmentManager fm, Context c, boolean ring) {
@@ -366,6 +388,53 @@
isRing = ring;
}
+ @Override
+ public int getCount() {
+ return isRing ? 3 : 4;
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ return isRing ? getRingPanel(position) : getSIPPanel(position);
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ int resId = isRing ? getRingPanelTitle(position) : getSIPPanelTitle(position);
+ return ctx.getString(resId);
+ }
+
+ private static Fragment getRingPanel(int position) {
+ Log.i(TAG, "PreferencesPagerAdapter getFragment " + position);
+ switch (position) {
+ case 0:
+ return new GeneralAccountFragment();
+ case 1:
+ return new MediaPreferenceFragment();
+ case 2:
+ return new AdvancedAccountFragment();
+ default:
+ return null;
+ }
+ }
+
+ private static Fragment getSIPPanel(int position) {
+ Log.i(TAG, "PreferencesPagerAdapter getFragment " + position);
+ switch (position) {
+ case 0:
+ return new GeneralAccountFragment();
+ case 1:
+ return new MediaPreferenceFragment();
+ case 2:
+ return new AdvancedAccountFragment();
+ case 3:
+ return new SecurityAccountFragment();
+ default:
+ return null;
+ }
+ }
+
+ @StringRes
private static int getRingPanelTitle(int position) {
switch (position) {
case 0:
@@ -381,6 +450,7 @@
}
}
+ @StringRes
private static int getSIPPanelTitle(int position) {
switch (position) {
case 0:
@@ -395,63 +465,5 @@
return -1;
}
}
-
- @Override
- public int getCount() {
- // For now we have 4 panels in each account type (Ring/SIP), but it may change
- return isRing ? ringFragments.length : sipFragments.length;
- }
-
- @Override
- public Fragment getItem(int position) {
- return isRing ? getRingPanel(position) : getSIPPanel(position);
- }
-
- @Override
- public CharSequence getPageTitle(int position) {
- int resId = isRing ? getRingPanelTitle(position) : getSIPPanelTitle(position);
- return ctx.getString(resId);
- }
-
- private Fragment getRingPanel(int position) {
- Log.i(TAG, "PreferencesPagerAdapter getFragment " + position);
- return ringFragments[position];
- }
-
- private Fragment getSIPPanel(int position) {
- Log.i(TAG, "PreferencesPagerAdapter getFragment " + position);
- return sipFragments[position];
- }
}
-
- @Override
- public void saveAccount() {
- if (mAccSelected == null || mService == null) {
- return;
- }
-
- final Account account = mAccSelected;
- if (getSupportActionBar() != null) {
- getSupportActionBar().setTitle(account.getAlias());
- }
-
- final IDRingService remote = getRemoteService();
- if (remote == null) {
- Log.w(TAG, "Error updating account, remote service is null");
- return;
- }
- mService.getThreadPool().submit(new Runnable() {
- @Override
- public void run() {
- try {
- Log.w(TAG, "updating account");
- remote.setCredentials(account.getAccountID(), account.getCredentialsHashMapList());
- remote.setAccountDetails(account.getAccountID(), account.getDetails());
- } catch (RemoteException e) {
- Log.e(TAG, "Exception updating account", e);
- }
- }
- });
- }
-
}
diff --git a/ring-android/app/src/main/java/cx/ring/client/AccountWizard.java b/ring-android/app/src/main/java/cx/ring/client/AccountWizard.java
index a2c897e..3f69ef7 100644
--- a/ring-android/app/src/main/java/cx/ring/client/AccountWizard.java
+++ b/ring-android/app/src/main/java/cx/ring/client/AccountWizard.java
@@ -21,40 +21,52 @@
package cx.ring.client;
-import android.app.Fragment;
+import android.Manifest;
+import android.app.Activity;
+import android.app.AlertDialog;
import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
-import android.support.v13.app.FragmentStatePagerAdapter;
-import android.support.v4.view.ViewPager;
+import android.os.RemoteException;
+import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.Log;
import android.view.MenuItem;
+import android.widget.Toast;
-import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
import butterknife.BindView;
import butterknife.ButterKnife;
import cx.ring.R;
import cx.ring.fragments.AccountCreationFragment;
import cx.ring.fragments.AccountMigrationFragment;
+import cx.ring.fragments.RingAccountCreationFragment;
+import cx.ring.fragments.RingAccountLoginFragment;
+import cx.ring.model.account.Account;
+import cx.ring.model.account.AccountConfig;
+import cx.ring.model.account.ConfigKey;
import cx.ring.service.IDRingService;
import cx.ring.service.LocalService;
public class AccountWizard extends AppCompatActivity implements LocalService.Callbacks {
static final String TAG = AccountWizard.class.getName();
private boolean mBound = false;
- private LocalService service;
-
- @BindView(R.id.pager)
- ViewPager mViewPager;
+ private LocalService mService;
+ private boolean mCreatingAccount = false;
@BindView(R.id.main_toolbar)
Toolbar mToolbar;
@@ -63,7 +75,7 @@
@Override
public void onServiceConnected(ComponentName className, IBinder binder) {
- service = ((LocalService.LocalBinder) binder).getService();
+ mService = ((LocalService.LocalBinder) binder).getService();
mBound = true;
}
@@ -83,21 +95,13 @@
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
- if (getIntent().getData() != null && !TextUtils.isEmpty(getIntent().getData().getLastPathSegment())) {
- String accountId = getIntent().getData().getLastPathSegment();
- SectionsPagerAdapter mSectionsPagerAdapter = new SectionsPagerAdapter(getFragmentManager(), accountId);
- mViewPager.setAdapter(mSectionsPagerAdapter);
- } else {
- SectionsPagerAdapter mSectionsPagerAdapter = new SectionsPagerAdapter(AccountWizard.this, getFragmentManager());
- mViewPager.setAdapter(mSectionsPagerAdapter);
- }
-
if (!mBound) {
Log.i(TAG, "onCreate: Binding service...");
Intent intent = new Intent(this, LocalService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
+ ringChoose();
}
@Override
@@ -119,11 +123,11 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case android.R.id.home:
- checkAccountPresence();
- return true;
- default:
- return super.onOptionsItemSelected(item);
+ case android.R.id.home:
+ checkAccountPresence();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
}
}
@@ -132,63 +136,221 @@
* If not, exit the app
*/
private void checkAccountPresence() {
- if (mBound && !service.getAccounts().isEmpty()) {
- finish();
+ if (mBound && !mService.getAccounts().isEmpty()) {
+ FragmentManager fm = getFragmentManager();
+ if (fm.getBackStackEntryCount() >= 1) {
+ fm.popBackStack();
+ } else {
+ finish();
+ }
} else {
- service.stopSelf();
+ mService.stopSelf();
finishAffinity();
}
}
@Override
public void onBackPressed() {
- checkAccountPresence();
+ FragmentManager fm = getFragmentManager();
+ if (fm.getBackStackEntryCount() >= 1) {
+ fm.popBackStack();
+ return;
+ }
+ super.onBackPressed();
}
- public class SectionsPagerAdapter extends FragmentStatePagerAdapter {
- private final ArrayList<Fragment> fragments;
- private final String mAccountId;
+ @SuppressWarnings("unchecked")
+ public void initAccountCreation(boolean isRingAccount, String newUsername, String pin, String password, String host) {
+ final String accountType = isRingAccount ? AccountConfig.ACCOUNT_TYPE_RING : AccountConfig.ACCOUNT_TYPE_SIP;
- SectionsPagerAdapter(Context c, FragmentManager fm) {
- this(fm, null);
- }
-
- SectionsPagerAdapter(FragmentManager fm, String accountId) {
- super(fm);
- fragments = new ArrayList<>();
- mAccountId = accountId;
-
- if (TextUtils.isEmpty(mAccountId)) {
- fragments.add(new AccountCreationFragment());
- } else {
- AccountMigrationFragment fragment = new AccountMigrationFragment();
- // give the installation id to display
- Bundle bundle = new Bundle();
- bundle.putString(AccountMigrationFragment.ACCOUNT_ID, mAccountId);
- fragment.setArguments(bundle);
- fragments.add(fragment);
+ try {
+ HashMap<String, String> accountDetails = (HashMap<String, String>) mService.getRemoteService().getAccountTemplate(accountType);
+ for (Map.Entry<String, String> e : accountDetails.entrySet()) {
+ Log.d(TAG, "Default account detail: " + e.getKey() + " -> " + e.getValue());
}
+ //~ Checking the state of the Camera permission to enable Video or not.
+ boolean hasCameraPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED;
+ accountDetails.put(ConfigKey.VIDEO_ENABLED.key(), Boolean.toString(hasCameraPermission));
+
+ //~ Sipinfo is forced for any sipaccount since overrtp is not supported yet.
+ //~ This will have to be removed when it will be supported.
+ accountDetails.put(ConfigKey.ACCOUNT_DTMF_TYPE.key(), getString(R.string.account_sip_dtmf_type_sipinfo));
+
+ if (isRingAccount) {
+ accountDetails.put(ConfigKey.ACCOUNT_ALIAS.key(), "Ring");
+ accountDetails.put(ConfigKey.ACCOUNT_HOSTNAME.key(), "bootstrap.ring.cx");
+ if (newUsername != null && !newUsername.isEmpty()) {
+ accountDetails.put(ConfigKey.ACCOUNT_REGISTERED_NAME.key(), newUsername);
+ }
+ if (password != null && !password.isEmpty()) {
+ accountDetails.put(ConfigKey.ARCHIVE_PASSWORD.key(), password);
+ }
+ if (pin != null && !pin.isEmpty()) {
+ accountDetails.put(ConfigKey.ARCHIVE_PIN.key(), pin);
+ }
+ // Enable UPNP by default for Ring accounts
+ accountDetails.put(ConfigKey.ACCOUNT_UPNP_ENABLE.key(), AccountConfig.TRUE_STR);
+ createNewAccount(accountDetails, newUsername);
+ } else {
+ accountDetails.put(ConfigKey.ACCOUNT_ALIAS.key(), newUsername);
+ if (!TextUtils.isEmpty(host)) {
+ accountDetails.put(ConfigKey.ACCOUNT_HOSTNAME.key(), host);
+ accountDetails.put(ConfigKey.ACCOUNT_USERNAME.key(), newUsername);
+ accountDetails.put(ConfigKey.ACCOUNT_PASSWORD.key(), password);
+ }
+ createNewAccount(accountDetails, null);
+ }
+
+ } catch (RemoteException e) {
+ Toast.makeText(this, "Error creating account", Toast.LENGTH_SHORT).show();
+ Log.e(TAG, "Error creating account", e);
+ }
+
+ }
+
+ public void ringChoose() {
+ boolean migrate = getIntent().getData() != null && !TextUtils.isEmpty(getIntent().getData().getLastPathSegment());
+
+ FragmentManager fragmentManager = getFragmentManager();
+ fragmentManager
+ .beginTransaction()
+ .replace(R.id.fragment_container, migrate ? new AccountMigrationFragment() : new AccountCreationFragment())
+ .commit();
+ }
+
+ public void ringCreate(boolean switchFragment) {
+ FragmentManager fragmentManager = getFragmentManager();
+ FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
+ if (!switchFragment) {
+ fragmentTransaction.addToBackStack(null);
+ }
+ fragmentTransaction
+ .replace(R.id.fragment_container, new RingAccountCreationFragment())
+ .commit();
+ }
+
+ public void ringLogin(boolean switchFragment) {
+ FragmentManager fragmentManager = getFragmentManager();
+ FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
+ if (!switchFragment) {
+ fragmentTransaction.addToBackStack(null);
+ }
+ fragmentTransaction
+ .replace(R.id.fragment_container, new RingAccountLoginFragment())
+ .commit();
+ }
+
+ private class CreateAccountTask extends AsyncTask<HashMap<String, String>, Void, String> {
+ private ProgressDialog progress = null;
+ private final String username;
+ private final Context ctx;
+
+ CreateAccountTask(String registerUsername, Context c) {
+ Log.d(TAG, "CreateAccountTask ");
+ username = registerUsername;
+ ctx = c;
}
@Override
- public Fragment getItem(int i) {
- return fragments.get(i);
+ protected void onPreExecute() {
+ progress = new ProgressDialog(ctx);
+ progress.setTitle(R.string.dialog_wait_create);
+ progress.setMessage(ctx.getString(R.string.dialog_wait_create_details));
+ progress.setCancelable(false);
+ progress.setCanceledOnTouchOutside(false);
+ progress.show();
}
+ @SafeVarargs
@Override
- public int getCount() {
- return 1;
+ protected final String doInBackground(HashMap<String, String>... accs) {
+ final Account account = mService.createAccount(accs[0]);
+ account.stateListener = new Account.OnStateChangedListener() {
+ @Override
+ public void stateChanged(String state, int code) {
+ Log.i(TAG, "stateListener -> stateChanged " + state + " " + code);
+ if (!AccountConfig.STATE_INITIALIZING.contentEquals(state)) {
+ account.stateListener = null;
+ if (progress != null) {
+ if (progress.isShowing()) {
+ progress.dismiss();
+ }
+ progress = null;
+ }
+ //Intent resultIntent = new Intent();
+ AlertDialog.Builder dialog = new AlertDialog.Builder(ctx);
+ dialog.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ //do things
+ }
+ });
+ boolean success = false;
+ switch (state) {
+ case AccountConfig.STATE_ERROR_GENERIC:
+ dialog.setTitle(R.string.account_cannot_be_found_title)
+ .setMessage(R.string.account_cannot_be_found_message);
+ break;
+ case AccountConfig.STATE_ERROR_NETWORK:
+ dialog.setTitle(R.string.account_no_network_title)
+ .setMessage(R.string.account_no_network_message);
+ break;
+ default:
+ dialog.setTitle(R.string.account_device_added_title)
+ .setMessage(R.string.account_device_added_message);
+ success = true;
+ break;
+ }
+ AlertDialog alertDialog = dialog.show();
+ if (success) {
+ if (!TextUtils.isEmpty(username)) {
+ Log.i(TAG, "Account created, registering " + username);
+ mService.registerName(account, "", username, new LocalService.NameRegistrationCallback() {
+ @Override
+ public void onRegistered(String name) {
+ Log.i(TAG, "Account wizard, onRegistered " + name);
+ }
+
+ @Override
+ public void onError(String name, CharSequence err) {
+ Log.w(TAG, "Account wizard, onError " + name);
+ }
+ });
+ }
+
+ alertDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
+ @Override
+ public void onDismiss(DialogInterface dialogInterface) {
+ setResult(Activity.RESULT_OK, new Intent());
+ finish();
+ }
+ });
+ }
+ }
+ }
+ };
+ return account.getAccountID();
}
}
+ private void createNewAccount(HashMap<String, String> accountDetails, String registerName) {
+ if (mCreatingAccount) {
+ return;
+ }
+
+ mCreatingAccount = true;
+
+ //noinspection unchecked
+ new CreateAccountTask(registerName, this).execute(accountDetails);
+ }
+
@Override
public IDRingService getRemoteService() {
- return service.getRemoteService();
+ return mService.getRemoteService();
}
@Override
public LocalService getService() {
- return service;
+ return mService;
}
}
diff --git a/ring-android/app/src/main/java/cx/ring/client/HomeActivity.java b/ring-android/app/src/main/java/cx/ring/client/HomeActivity.java
index 7be2dfc..c7a480a 100644
--- a/ring-android/app/src/main/java/cx/ring/client/HomeActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/client/HomeActivity.java
@@ -467,7 +467,7 @@
fContent = fragmentManager.findFragmentById(R.id.main_frame);
if (fContent == null) {
fContent = new SmartListFragment();
- fragmentManager.beginTransaction().replace(R.id.main_frame, fContent, HOME_TAG).commitAllowingStateLoss();
+ fragmentManager.beginTransaction().replace(R.id.main_frame, fContent, HOME_TAG).addToBackStack(HOME_TAG).commitAllowingStateLoss();
} else if (fContent instanceof Refreshable) {
fragmentManager.beginTransaction().replace(R.id.main_frame, fContent).addToBackStack(HOME_TAG).commit();
((Refreshable) fContent).refresh();
@@ -673,7 +673,7 @@
}
private void setVideoEnabledFromPermission() {
- //~ Setting correct AccountDetailBasic.CONFIG_VIDEO_ENABLED value based on the state of the
+ //~ Setting correct VIDEO_ENABLED value based on the state of the
//~ permission. It can handle the case where the user decides to remove a permission from
//~ the Android general settings.
if (!LocalService.checkPermission(this, Manifest.permission.CAMERA) && service != null) {
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/AccountCreationFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/AccountCreationFragment.java
index 1f884f4..d39d29a 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/AccountCreationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/AccountCreationFragment.java
@@ -20,7 +20,6 @@
package cx.ring.fragments;
-import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
@@ -42,7 +41,6 @@
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.support.annotation.NonNull;
-import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
@@ -50,8 +48,6 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
@@ -64,17 +60,13 @@
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.Writer;
-import java.util.HashMap;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.OnEditorAction;
-import butterknife.OnFocusChange;
import cx.ring.R;
-import cx.ring.model.account.Account;
-import cx.ring.model.account.AccountConfig;
-import cx.ring.model.account.ConfigKey;
+import cx.ring.client.AccountWizard;
import cx.ring.service.LocalService;
public class AccountCreationFragment extends Fragment {
@@ -88,18 +80,9 @@
private String mHostname;
private String mUsername;
private String mPassword;
- private String mAccountType;
private String mDataPath;
private LocalService.Callbacks mCallbacks = LocalService.DUMMY_CALLBACKS;
- private CreateAccountTask mAccountTask;
-
- // UI references.
- @BindView(R.id.addAccountLayout)
- LinearLayout mAddAccountLayout;
-
- @BindView(R.id.newAccountLayout)
- LinearLayout mNewAccountLayout;
@BindView(R.id.sipFormLinearLayout)
LinearLayout mSipFormLinearLayout;
@@ -122,34 +105,6 @@
@BindView(R.id.create_sip_button)
Button mCreateSIPAccountButton;
- @BindView(R.id.ring_password)
- EditText mRingPassword;
-
- @BindView(R.id.ring_password_repeat)
- EditText mRingPasswordRepeat;
-
- @BindView(R.id.ring_add_pin)
- EditText mRingPin;
-
- @BindView(R.id.ring_add_password)
- EditText mRingAddPassword;
-
- private void flipForm(boolean addAccount, boolean newAccount) {
- mAddAccountLayout.setVisibility(addAccount ? View.VISIBLE : View.GONE);
- mNewAccountLayout.setVisibility(newAccount ? View.VISIBLE : View.GONE);
- InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
- if (newAccount) {
- mRingPassword.requestFocus();
- imm.showSoftInput(mRingPassword, InputMethodManager.SHOW_IMPLICIT);
- } else if (addAccount) {
- mRingPin.requestFocus();
- imm.showSoftInput(mRingPin, InputMethodManager.SHOW_IMPLICIT);
- }
- if (addAccount || newAccount) {
- mSipFormLinearLayout.setVisibility(View.GONE);
- }
- }
-
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
final View inflatedView = inflater.inflate(R.layout.frag_account_creation, parent, false);
@@ -160,29 +115,6 @@
return inflatedView;
}
- private boolean checkPassword(@NonNull TextView pwd, TextView confirm) {
- boolean error = false;
- if (pwd.getText().length() == 0) {
- error = true;
- } else {
- if (pwd.getText().length() < 6) {
- pwd.setError(getString(R.string.error_password_char_count));
- error = true;
- } else {
- pwd.setError(null);
- }
- }
- if (confirm != null) {
- if (!pwd.getText().toString().equals(confirm.getText().toString())) {
- confirm.setError(getString(R.string.error_passwords_not_equals));
- error = true;
- } else {
- confirm.setError(null);
- }
- }
- return error;
- }
-
@OnEditorAction(R.id.password)
@SuppressWarnings("unused")
public boolean keyPressedOnPasswordField(TextView v, int actionId, KeyEvent event) {
@@ -194,73 +126,20 @@
return true;
}
- /***********************
- * Ring Account Creation
- ***********************/
- @OnEditorAction(R.id.ring_password)
- @SuppressWarnings("unused")
- public boolean keyPressedOnRingPasswordField(TextView v, int actionId, KeyEvent event) {
- if (actionId == EditorInfo.IME_ACTION_NEXT) {
- return checkPassword(v, null);
- }
- return false;
- }
-
- @OnFocusChange(R.id.ring_password)
- @SuppressWarnings("unused")
- public void onFocusChangeOnPasswordField(TextView v, boolean hasFocus) {
- if (!hasFocus) {
- checkPassword(v, null);
- }
- }
-
- @OnEditorAction(R.id.ring_password_repeat)
- @SuppressWarnings("unused")
- public boolean keyPressedOnPasswordRepeatField(TextView v, int actionId, KeyEvent event) {
- if (actionId == EditorInfo.IME_ACTION_DONE) {
- if (mRingPassword.getText().length() != 0 && !checkPassword(mRingPassword, v)) {
- createRingAccount();
- return true;
- }
- }
- return false;
- }
-
@OnClick(R.id.ring_create_btn)
public void createRingAccount() {
- if (mNewAccountLayout.getVisibility() == View.GONE) {
- flipForm(false, true);
- } else {
- if (!checkPassword(mRingPassword, mRingPasswordRepeat)) {
- mAccountType = AccountConfig.ACCOUNT_TYPE_RING;
- mUsername = mAlias;
- initAccountCreation(null, mRingPassword.getText().toString());
- }
+ AccountWizard accountWizard = (AccountWizard) getActivity();
+ if (accountWizard != null) {
+ accountWizard.ringCreate(false);
}
}
- /************************
- * Ring Account ADD
- ***********************/
- @OnEditorAction(R.id.ring_add_password)
- @SuppressWarnings("unused")
- public boolean keyPressedOnPasswordAddField(TextView v, int actionId, KeyEvent event) {
- if (actionId == EditorInfo.IME_ACTION_DONE) {
- addRingAccount();
- return true;
- }
- return false;
- }
-
@OnClick(R.id.ring_add_account)
@SuppressWarnings("unused")
public void addRingAccount() {
- if (mAddAccountLayout.getVisibility() == View.GONE) {
- flipForm(true, false);
- } else if (mRingPin.getText().length() != 0 && mRingAddPassword.getText().length() != 0) {
- mAccountType = AccountConfig.ACCOUNT_TYPE_RING;
- mUsername = mAlias;
- initAccountCreation(mRingPin.getText().toString(), mRingAddPassword.getText().toString());
+ AccountWizard accountWizard = (AccountWizard) getActivity();
+ if (accountWizard != null) {
+ accountWizard.ringLogin(false);
}
}
@@ -269,7 +148,6 @@
***********************/
@OnClick(R.id.create_sip_button)
public void createSIPAccount() {
- mAccountType = AccountConfig.ACCOUNT_TYPE_SIP;
mAlias = mAliasView.getText().toString();
mHostname = mHostnameView.getText().toString();
mUsername = mUsernameView.getText().toString();
@@ -297,7 +175,6 @@
public void onClickHeader(View v) {
if (null != mSipFormLinearLayout) {
if (mSipFormLinearLayout.getVisibility() != View.VISIBLE) {
- flipForm(false, false);
mSipFormLinearLayout.setVisibility(View.VISIBLE);
//~ Let the time to perform setVisibility before scrolling.
mSIPLoginForm.postDelayed(new Runnable() {
@@ -562,7 +439,6 @@
return alertDialog;
}
-
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
@@ -672,7 +548,10 @@
} else if (warningIPAccount) {
showIP2IPDialog();
} else {
- initAccountCreation(null, null);
+ AccountWizard accountWizard = (AccountWizard) getActivity();
+ if (accountWizard != null) {
+ accountWizard.initAccountCreation(false, mUsernameView.getText().toString(), null, mPasswordView.getText().toString(), mHostnameView.getText().toString());
+ }
}
}
@@ -683,7 +562,9 @@
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) {
- initAccountCreation(null, null);
+ AccountWizard a = (AccountWizard) getActivity();
+ if (a != null)
+ a.initAccountCreation(false, mAliasView.getText().toString(), null, null, null);
}
})
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@@ -694,137 +575,4 @@
})
.create().show();
}
-
- @SuppressWarnings("unchecked")
- private void initAccountCreation(String pin, String password) {
- try {
- HashMap<String, String> accountDetails = (HashMap<String, String>) mCallbacks.getRemoteService().getAccountTemplate(mAccountType);
- accountDetails.put(ConfigKey.ACCOUNT_TYPE.key(), mAccountType);
- //~ Checking the state of the Camera permission to enable Video or not.
- boolean hasCameraPermission = ContextCompat.checkSelfPermission(getActivity(),
- Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED;
- accountDetails.put(ConfigKey.VIDEO_ENABLED.key(), Boolean.toString(hasCameraPermission));
-
- //~ Sipinfo is forced for any sipaccount since overrtp is not supported yet.
- //~ This will have to be removed when it will be supported.
- accountDetails.put(ConfigKey.ACCOUNT_DTMF_TYPE.key(), getString(R.string.account_sip_dtmf_type_sipinfo));
-
- if (mAccountType.equals(AccountConfig.ACCOUNT_TYPE_RING)) {
- accountDetails.put(ConfigKey.ACCOUNT_ALIAS.key(), "Ring");
- accountDetails.put(ConfigKey.ACCOUNT_HOSTNAME.key(), "bootstrap.ring.cx");
- if (password != null && !password.isEmpty()) {
- accountDetails.put(ConfigKey.ARCHIVE_PASSWORD.key(), password);
- }
- if (pin != null && !pin.isEmpty()) {
- accountDetails.put(ConfigKey.ARCHIVE_PIN.key(), pin);
- }
- // Enable UPNP by default for Ring accounts
- accountDetails.put(ConfigKey.ACCOUNT_UPNP_ENABLE.key(), AccountConfig.TRUE_STR);
- createNewAccount(accountDetails);
- } else {
- accountDetails.put(ConfigKey.ACCOUNT_ALIAS.key(), mAlias);
- if (!TextUtils.isEmpty(mHostname)) {
- accountDetails.put(ConfigKey.ACCOUNT_HOSTNAME.key(), mHostname);
- accountDetails.put(ConfigKey.ACCOUNT_USERNAME.key(), mUsername);
- accountDetails.put(ConfigKey.ACCOUNT_PASSWORD.key(), mPassword);
- }
- createNewAccount(accountDetails);
- }
-
- } catch (RemoteException e) {
- Toast.makeText(getActivity(), R.string.account_creation_error, Toast.LENGTH_SHORT).show();
- Log.d(TAG, "Error while creating account", e);
- }
-
- }
-
- private class CreateAccountTask extends AsyncTask<HashMap<String, String>, Void, String> {
- private ProgressDialog progress = null;
-
- @Override
- protected void onPreExecute() {
- progress = new ProgressDialog(getActivity());
- progress.setTitle(R.string.dialog_wait_create);
- progress.setMessage(getString(R.string.dialog_wait_create_details));
- progress.setCancelable(false);
- progress.setCanceledOnTouchOutside(false);
- progress.show();
- }
-
- @Override
- protected void onPostExecute(String s) {
- super.onPostExecute(s);
- mAccountTask = null;
- }
-
- @SafeVarargs
- @Override
- protected final String doInBackground(HashMap<String, String>... accounts) {
- final Account account = mCallbacks.getService().createAccount(accounts[0]);
- account.stateListener = new Account.OnStateChangedListener() {
- @Override
- public void stateChanged(String state, int code) {
- if (!AccountConfig.STATE_INITIALIZING.contentEquals(state)) {
- account.stateListener = null;
- if (progress != null) {
- if (progress.isShowing()) {
- progress.dismiss();
- }
- progress = null;
- }
-
- if (account.isSip()) {
- getActivity().setResult(Activity.RESULT_OK, new Intent());
- getActivity().finish();
- return;
- }
-
- AlertDialog.Builder dialog = new AlertDialog.Builder(getActivity());
- dialog.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- //do things
- }
- });
- boolean success = false;
- switch (state) {
- case AccountConfig.STATE_ERROR_GENERIC:
- dialog.setTitle(R.string.account_cannot_be_found_title)
- .setMessage(R.string.account_cannot_be_found_message);
- break;
- case AccountConfig.STATE_ERROR_NETWORK:
- dialog.setTitle(R.string.account_no_network_title)
- .setMessage(R.string.account_no_network_message);
- break;
- default:
- dialog.setTitle(R.string.account_device_added_title)
- .setMessage(R.string.account_device_added_message);
- success = true;
- break;
- }
- AlertDialog d = dialog.show();
- if (success) {
- d.setOnDismissListener(new DialogInterface.OnDismissListener() {
- @Override
- public void onDismiss(DialogInterface dialogInterface) {
- getActivity().setResult(Activity.RESULT_OK, new Intent());
- getActivity().finish();
- }
- });
- }
- }
- }
- };
- return account.getAccountID();
- }
- }
-
- private void createNewAccount(HashMap<String, String> accountDetails) {
- if (mAccountTask != null) {
- return;
- }
-
- //noinspection unchecked
- mAccountTask = new CreateAccountTask();
- mAccountTask.execute(accountDetails);
- }
}
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/DeviceAccountFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/DeviceAccountFragment.java
index 37673ae..09f519f 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/DeviceAccountFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/DeviceAccountFragment.java
@@ -55,18 +55,22 @@
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.OnEditorAction;
-
import cx.ring.R;
+import cx.ring.client.AccountEditionActivity;
import cx.ring.interfaces.AccountCallbacks;
import cx.ring.interfaces.AccountChangedListener;
import cx.ring.interfaces.BackHandlerInterface;
import cx.ring.model.account.Account;
+import cx.ring.model.account.ConfigKey;
+import cx.ring.service.LocalService;
import cx.ring.utils.KeyboardVisibilityManager;
import cx.ring.views.LinkNewDeviceLayout;
import static cx.ring.client.AccountEditionActivity.DUMMY_CALLBACKS;
-public class DeviceAccountFragment extends Fragment implements AccountChangedListener, BackHandlerInterface {
+public class DeviceAccountFragment extends Fragment implements AccountChangedListener,
+ BackHandlerInterface,
+ RegisterNameDialog.RegisterNameDialogListener {
private static final String TAG = DeviceAccountFragment.class.getSimpleName();
@@ -88,6 +92,30 @@
@BindView(R.id.account_link_info)
TextView mExportInfos;
+ @BindView(R.id.account_edit_btn)
+ View mEditBtn;
+
+ @BindView(R.id.account_alias_txt)
+ TextView mAccountNameTxt;
+
+ @BindView(R.id.account_id_txt)
+ TextView mAccountIdTxt;
+
+ @BindView(R.id.registered_name_txt)
+ TextView mAccountUsernameTxt;
+
+ @BindView(R.id.register_name_btn)
+ Button mRegisterNameBtn;
+
+ @BindView(R.id.group_registering_name)
+ ViewGroup registeringNameGroup;
+
+ @BindView(R.id.group_register_name)
+ ViewGroup mRegisterNameGroup;
+
+ @BindView(R.id.group_registered_name)
+ ViewGroup mRegisteredNameGroup;
+
@BindView(R.id.device_list)
ListView mDeviceList;
@@ -99,24 +127,6 @@
private AccountCallbacks mCallbacks = DUMMY_CALLBACKS;
private DeviceAdapter mDeviceAdapter;
- /*
- Fragment LifeCycle
- */
- @Nullable
- @Override
- public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- ViewGroup devLayout = (ViewGroup) inflater.inflate(R.layout.frag_device_list, container, false);
-
- ButterKnife.bind(this, devLayout);
-
- Account account = mCallbacks.getAccount();
- if (account != null) {
- accountChanged(account);
- }
- mLinkAccountView.setContainer(this);
- hidePopWizard();
- return devLayout;
- }
@Override
public void onAttach(Activity activity) {
@@ -144,6 +154,18 @@
public void accountChanged(Account account) {
mDeviceAdapter = new DeviceAdapter(getActivity(), account.getDevices());
mDeviceList.setAdapter(mDeviceAdapter);
+
+ mAccountNameTxt.setText(account.getAlias());
+ mAccountIdTxt.setText(account.getUsername());
+ String username = account.getRegisteredName();
+ boolean currentRegisteredName = account.registeringUsername;
+ boolean hasRegisteredName = !currentRegisteredName && username != null && !username.isEmpty();
+ registeringNameGroup.setVisibility(currentRegisteredName ? View.VISIBLE : View.GONE);
+ mRegisterNameGroup.setVisibility((!hasRegisteredName && !currentRegisteredName) ? View.VISIBLE : View.GONE);
+ mRegisteredNameGroup.setVisibility(hasRegisteredName ? View.VISIBLE : View.GONE);
+ if (hasRegisteredName) {
+ mAccountUsernameTxt.setText(username);
+ }
account.devicesListener = new Account.OnDevicesChangedListener() {
@Override
public void devicesChanged(Map<String, String> devices) {
@@ -159,6 +181,7 @@
*/
@Override
public boolean onBackPressed() {
+
if (isDisplayingWizard()) {
hideWizard();
return true;
@@ -251,6 +274,31 @@
}
}
+ @OnClick(R.id.register_name_btn)
+ public void showUsernameRegistrationPopup() {
+ RegisterNameDialog registrationDialog = new RegisterNameDialog();
+ registrationDialog.setListener(this);
+ registrationDialog.show(getFragmentManager(), TAG);
+ }
+
+ @Override
+ public void onRegisterName(String name, String password) {
+ final Account account = mCallbacks.getAccount();
+ account.setDetail(ConfigKey.ACCOUNT_REGISTERED_NAME, name);
+ mCallbacks.getService().registerName(account, password, name, new LocalService.NameRegistrationCallback() {
+ @Override
+ public void onRegistered(String name) {
+ Log.w(TAG, "Account wizard, onRegistered " + name);
+ mCallbacks.saveAccount();
+ }
+
+ @Override
+ public void onError(String name, CharSequence err) {
+ Log.w(TAG, "Account wizard, onError " + name);
+ }
+ });
+ }
+
class DeviceAdapter extends BaseAdapter {
private final Context mCtx;
private final ArrayList<Map.Entry<String, String>> devices = new ArrayList<>();
@@ -358,4 +406,28 @@
}
}
+ @Nullable
+ @Override
+ public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ if (container == null) return null;
+ ViewGroup devLayout = (ViewGroup) inflater.inflate(R.layout.frag_device_list, container, false);
+
+ ButterKnife.bind(this, devLayout);
+
+ Account account = mCallbacks.getAccount();
+ if (account != null) {
+ accountChanged(account);
+ }
+
+ mLinkAccountView.setContainer(this);
+ hidePopWizard();
+
+ return devLayout;
+ }
+
+ @OnClick(R.id.account_edit_btn)
+ public void editAccount() {
+ ((AccountEditionActivity) getActivity()).editAdvanced();
+ }
+
}
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/RegisterNameDialog.java b/ring-android/app/src/main/java/cx/ring/fragments/RegisterNameDialog.java
new file mode 100644
index 0000000..39b57a1
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/fragments/RegisterNameDialog.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2016 Savoir-faire Linux Inc.
+ *
+ * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package cx.ring.fragments;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.design.widget.TextInputLayout;
+import android.text.TextWatcher;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.inputmethod.EditorInfo;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import butterknife.BindString;
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.OnEditorAction;
+import cx.ring.R;
+import cx.ring.service.LocalService;
+import cx.ring.utils.BlockchainUtils;
+
+public class RegisterNameDialog extends DialogFragment {
+ static final String TAG = RegisterNameDialog.class.getSimpleName();
+
+ public interface RegisterNameDialogListener {
+ void onRegisterName(String name, String password);
+ }
+
+ @BindView(R.id.ring_username_txt_box)
+ public TextInputLayout mUsernameTxtBox;
+
+ @BindView(R.id.ring_username)
+ public EditText mUsernameTxt;
+
+ @BindView(R.id.ring_password_txt_box)
+ public TextInputLayout mPasswordTxtBox;
+
+ @BindView(R.id.ring_password_txt)
+ public EditText mPasswordTxt;
+
+ @BindString(R.string.register_name)
+ public String mRegisterTitle;
+
+ @BindString(R.string.register_username)
+ public String mRegisterMessage;
+
+ @BindString(R.string.prompt_new_username)
+ public String mPromptUsername;
+
+ @BindString(R.string.prompt_password)
+ public String mPromptPassword;
+
+ private TextWatcher mUsernameTextWatcher;
+
+ private RegisterNameDialogListener mListener = null;
+
+ void setListener(RegisterNameDialogListener l) {
+ mListener = l;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+
+ View view = getActivity().getLayoutInflater().inflate(R.layout.frag_register_name, null);
+
+ ButterKnife.bind(this, view);
+
+ BlockchainUtils.attachUsernameTextFilter(mUsernameTxt);
+ mUsernameTextWatcher = BlockchainUtils.attachUsernameTextWatcher((LocalService.Callbacks) getActivity(), mUsernameTxtBox, mUsernameTxt);
+
+ AlertDialog dialog = (AlertDialog) getDialog();
+ if (dialog != null) {
+ dialog.setView(view);
+ dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+ }
+
+ builder.setView(view);
+
+ builder.setMessage(mRegisterMessage)
+ .setTitle(mRegisterTitle)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ validate();
+ }
+ })
+ .setNegativeButton(android.R.string.cancel,
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ dismiss();
+ }
+ }
+ );
+
+ return builder.create();
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ if (mUsernameTxt != null) {
+ mUsernameTextWatcher = BlockchainUtils.attachUsernameTextWatcher((LocalService.Callbacks) getActivity(), mUsernameTxtBox, mUsernameTxt);
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ if (mUsernameTxt != null) {
+ mUsernameTxt.removeTextChangedListener(mUsernameTextWatcher);
+ }
+ super.onDetach();
+ }
+
+ public String getUsername() {
+ return mUsernameTxt.getText().toString();
+ }
+
+ public boolean checkInput() {
+ if (mUsernameTxt.getText().toString().isEmpty()) {
+ mUsernameTxtBox.setErrorEnabled(true);
+ mUsernameTxtBox.setError(mPromptUsername);
+ return false;
+ } else {
+ mUsernameTxtBox.setErrorEnabled(false);
+ mUsernameTxtBox.setError(null);
+ }
+ if (mPasswordTxt.getText().toString().isEmpty()) {
+ mPasswordTxtBox.setErrorEnabled(true);
+ mPasswordTxtBox.setError(mPromptPassword);
+ return false;
+ } else {
+ mPasswordTxtBox.setErrorEnabled(false);
+ mPasswordTxtBox.setError(null);
+ }
+ return true;
+ }
+
+ boolean validate() {
+ if (checkInput() && mListener != null) {
+ final String username = mUsernameTxt.getText().toString();
+ final String password = mPasswordTxt.getText().toString();
+ getDialog().dismiss();
+ mListener.onRegisterName(username, password);
+ return true;
+ }
+ return false;
+ }
+
+ @OnEditorAction({R.id.ring_username, R.id.ring_password_txt})
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ if (v == mPasswordTxt) {
+ if (actionId == EditorInfo.IME_ACTION_DONE) {
+ return validate();
+ }
+ }
+ return false;
+ }
+}
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/RingAccountCreationFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/RingAccountCreationFragment.java
new file mode 100644
index 0000000..4b99ce3
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/fragments/RingAccountCreationFragment.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2004-2016 Savoir-faire Linux Inc.
+ *
+ * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package cx.ring.fragments;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.design.widget.TextInputLayout;
+import android.support.v7.app.ActionBar;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.EditorInfo;
+import android.widget.Button;
+import android.widget.CompoundButton;
+import android.widget.EditText;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.OnCheckedChanged;
+import butterknife.OnClick;
+import butterknife.OnEditorAction;
+import butterknife.OnFocusChange;
+import cx.ring.R;
+import cx.ring.client.AccountWizard;
+import cx.ring.service.LocalService;
+import cx.ring.utils.BlockchainUtils;
+
+public class RingAccountCreationFragment extends Fragment {
+ static final String TAG = RingAccountCreationFragment.class.getSimpleName();
+ private static final int PASSWORD_MIN_LENGTH = 6;
+
+ @BindView(R.id.switch_ring_username)
+ Switch mUsernameSwitch;
+
+ @BindView(R.id.ring_username_txt_box)
+ TextInputLayout mUsernameTxtBox;
+
+ @BindView(R.id.ring_username)
+ EditText mUsernameTxt;
+
+ private TextWatcher mUsernameTextWatcher;
+
+ @BindView(R.id.ring_password_txt_box)
+ TextInputLayout mPasswordTxtBox;
+
+ @BindView(R.id.ring_password)
+ EditText mPasswordTxt;
+
+ @BindView(R.id.ring_password_repeat_txt_box)
+ TextInputLayout mPasswordRepeatTxtBox;
+
+ @BindView(R.id.add_button)
+ Button mAddAccountBtn;
+
+ @BindView(R.id.ring_username_box)
+ ViewGroup mUsernameBox;
+
+ private boolean checkPassword(@NonNull TextInputLayout pwd, TextInputLayout confirm) {
+ boolean error = false;
+ pwd.setError(null);
+ if (mUsernameSwitch.isChecked()) {
+ if (mUsernameTxt.getText().toString().isEmpty()) {
+ mUsernameTxtBox.setErrorEnabled(true);
+ mUsernameTxtBox.setError(getString(R.string.error_username_empty));
+ return true;
+ }
+ }
+ if (pwd.getEditText().getText().length() == 0) {
+ error = true;
+ } else {
+ if (pwd.getEditText().getText().length() < PASSWORD_MIN_LENGTH) {
+ pwd.setError(getString(R.string.error_password_char_count));
+ error = true;
+ } else {
+ pwd.setError(null);
+ }
+ }
+ if (confirm != null) {
+ if (!pwd.getEditText().getText().toString().equals(confirm.getEditText().getText().toString())) {
+ confirm.setError(getString(R.string.error_passwords_not_equals));
+ error = true;
+ } else {
+ confirm.setError(null);
+ }
+ }
+ mAddAccountBtn.setEnabled(!error);
+ return error;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
+ final View view = inflater.inflate(R.layout.frag_acc_ring_create, parent, false);
+ ButterKnife.bind(this, view);
+
+ BlockchainUtils.attachUsernameTextFilter(mUsernameTxt);
+
+ if (isAdded()) {
+ mUsernameTextWatcher = BlockchainUtils.attachUsernameTextWatcher((LocalService.Callbacks) getActivity(), mUsernameTxtBox, mUsernameTxt);
+ }
+
+ return view;
+ }
+
+ @OnCheckedChanged(R.id.switch_ring_username)
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ mUsernameBox.setVisibility(isChecked ? View.VISIBLE : View.GONE);
+ }
+
+ @OnEditorAction(R.id.ring_password)
+ public boolean onPasswordEditorAction(TextView view, int actionId, KeyEvent event) {
+ Log.w(TAG, "onEditorAction " + actionId + " " + (event == null ? null : event.toString()));
+ if (actionId == EditorInfo.IME_ACTION_DONE) {
+ if (mPasswordTxt.getText().length() != 0 && !checkPassword(mPasswordTxtBox, mPasswordRepeatTxtBox)) {
+ mAddAccountBtn.callOnClick();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @OnFocusChange(R.id.ring_password)
+ public void onFocusChange(View view, boolean hasFocus) {
+ if (!hasFocus) {
+ checkPassword(mPasswordTxtBox, null);
+ }
+ }
+
+ @OnEditorAction(R.id.ring_password_repeat)
+ public boolean onPasswordRepeatEditorAction(TextView view, int actionId, KeyEvent event) {
+ Log.w(TAG, "onEditorAction " + actionId + " " + (event == null ? null : event.toString()));
+ if (actionId == EditorInfo.IME_ACTION_DONE) {
+ if (mPasswordTxt.getText().length() != 0 && !checkPassword(mPasswordTxtBox, mPasswordRepeatTxtBox)) {
+ mAddAccountBtn.callOnClick();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @OnClick(R.id.add_button)
+ public void onAddButtonClick(View view) {
+ if (!checkPassword(mPasswordTxtBox, mPasswordRepeatTxtBox))
+ ((AccountWizard) getActivity()).initAccountCreation(true, mUsernameTxt.getText().toString(), null, mPasswordTxt.getText().toString(), null);
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ ActionBar ab = ((AccountWizard) activity).getSupportActionBar();
+ if (ab != null) {
+ ab.setTitle(R.string.account_create_title);
+ }
+ if (mUsernameTxt != null) {
+ mUsernameTextWatcher = BlockchainUtils.attachUsernameTextWatcher((LocalService.Callbacks) getActivity(), mUsernameTxtBox, mUsernameTxt);
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ if (mUsernameTxt != null) {
+ mUsernameTxt.removeTextChangedListener(mUsernameTextWatcher);
+ }
+ super.onDetach();
+ }
+}
\ No newline at end of file
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/RingAccountLoginFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/RingAccountLoginFragment.java
new file mode 100644
index 0000000..d7ca140
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/fragments/RingAccountLoginFragment.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2004-2016 Savoir-faire Linux Inc.
+ *
+ * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+package cx.ring.fragments;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.os.Bundle;
+import android.support.v7.widget.AppCompatButton;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.OnClick;
+import cx.ring.R;
+import cx.ring.client.AccountWizard;
+
+public class RingAccountLoginFragment extends Fragment {
+ static final String TAG = RingAccountLoginFragment.class.getSimpleName();
+
+ @BindView(R.id.ring_add_pin)
+ EditText mPinTxt;
+
+ @BindView(R.id.ring_password)
+ EditText mPasswordTxt;
+
+ @BindView(R.id.link_button)
+ AppCompatButton mLinkAccountBtn;
+
+ void checkNextState() {
+ mLinkAccountBtn.setEnabled(!mPinTxt.getText().toString().isEmpty() && !mPasswordTxt.getText().toString().isEmpty());
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
+ final View view = inflater.inflate(R.layout.frag_acc_ring_login, parent, false);
+
+ ButterKnife.bind(this, view);
+
+ mPinTxt.addTextChangedListener(inputWatcher);
+ mPasswordTxt.addTextChangedListener(inputWatcher);
+
+ checkNextState();
+ return view;
+ }
+
+ @OnClick(R.id.link_button)
+ public void onLinkClick(View view) {
+ ((AccountWizard) getActivity()).initAccountCreation(true, null, mPinTxt.getText().toString(), mPasswordTxt.getText().toString(), null);
+ }
+
+ private final TextWatcher inputWatcher = new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ checkNextState();
+ }
+ };
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ AccountWizard account = (AccountWizard) getActivity();
+ if (account != null) {
+ account.getSupportActionBar().setTitle(R.string.account_import_title);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ring-android/app/src/main/java/cx/ring/model/account/Account.java b/ring-android/app/src/main/java/cx/ring/model/account/Account.java
index 7daf2a5..0e078b4 100644
--- a/ring-android/app/src/main/java/cx/ring/model/account/Account.java
+++ b/ring-android/app/src/main/java/cx/ring/model/account/Account.java
@@ -15,8 +15,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cx.ring.model.account;
@@ -29,17 +28,19 @@
public class Account extends java.util.Observable {
private static final String TAG = Account.class.getName();
- private final String accountID;
+ private String accountID;
+
private AccountConfig mVolatileDetails;
private AccountConfig mDetails;
private ArrayList<AccountCredentials> credentialsDetails = new ArrayList<>();
-
private Map<String, String> devices = new HashMap<>();
public OnDevicesChangedListener devicesListener = null;
public OnExportEndedListener exportListener = null;
public OnStateChangedListener stateListener = null;
+ public boolean registeringUsername = false;
+
public Account(String bAccountID) {
accountID = bAccountID;
mDetails = new AccountConfig();
@@ -170,7 +171,7 @@
}
public String getRegisteredName() {
- return mVolatileDetails.get(ConfigKey.ACCOUNT_REGISTRED_NAME);
+ return mVolatileDetails.get(ConfigKey.ACCOUNT_REGISTERED_NAME);
}
public String getAlias() {
diff --git a/ring-android/app/src/main/java/cx/ring/model/account/ConfigKey.java b/ring-android/app/src/main/java/cx/ring/model/account/ConfigKey.java
index ddcbabe..d44d929 100644
--- a/ring-android/app/src/main/java/cx/ring/model/account/ConfigKey.java
+++ b/ring-android/app/src/main/java/cx/ring/model/account/ConfigKey.java
@@ -78,7 +78,7 @@
TLS_VERIFY_CLIENT("TLS.verifyClient"),
TLS_REQUIRE_CLIENT_CERTIFICATE("TLS.requireClientCertificate"),
TLS_NEGOTIATION_TIMEOUT_SEC("TLS.negotiationTimeoutSec"),
- ACCOUNT_REGISTRED_NAME("Account.registredName"),
+ ACCOUNT_REGISTERED_NAME("Account.registredName"),
ACCOUNT_REGISTRATION_STATUS("Account.registrationStatus"),
ACCOUNT_REGISTRATION_STATE_CODE("Account.registrationCode"),
ACCOUNT_REGISTRATION_STATE_DESC("Account.registrationDescription"),
diff --git a/ring-android/app/src/main/java/cx/ring/service/ConfigurationManagerCallback.java b/ring-android/app/src/main/java/cx/ring/service/ConfigurationManagerCallback.java
index 5d7353b..dc2a0ff 100644
--- a/ring-android/app/src/main/java/cx/ring/service/ConfigurationManagerCallback.java
+++ b/ring-android/app/src/main/java/cx/ring/service/ConfigurationManagerCallback.java
@@ -38,6 +38,8 @@
static public final String ACCOUNT_STATE_CHANGED = BuildConfig.APPLICATION_ID + "account.stateChanged";
static public final String INCOMING_TEXT = BuildConfig.APPLICATION_ID + ".message.incomingTxt";
static public final String MESSAGE_STATE_CHANGED = BuildConfig.APPLICATION_ID + ".message.stateChanged";
+ static public final String NAME_LOOKUP_ENDED = BuildConfig.APPLICATION_ID + ".name.lookupEnded";
+ static public final String NAME_REGISTRATION_ENDED = BuildConfig.APPLICATION_ID + ".name.registrationEnded";
static public final String MESSAGE_STATE_CHANGED_EXTRA_ID = "id";
static public final String MESSAGE_STATE_CHANGED_EXTRA_STATUS = "status";
@@ -154,4 +156,26 @@
intent.putExtra("pin", pin);
mService.sendBroadcast(intent);
}
+
+ @Override
+ public void nameRegistrationEnded(String account, int state, String name) {
+ Log.w(TAG, "nameRegistrationEnded: " + account + " " + state + " " + name);
+ Intent intent = new Intent(NAME_REGISTRATION_ENDED);
+ intent.putExtra("account", account);
+ intent.putExtra("state", state);
+ intent.putExtra("name", name);
+ mService.sendBroadcast(intent);
+ }
+
+ @Override
+ public void registeredNameFound(String account, int state, String address, String name) {
+ Log.w(TAG, "registeredNameFound: " + account + " " + state + " " + name + " " + address);
+ Intent intent = new Intent(NAME_LOOKUP_ENDED);
+ intent.putExtra("account", account);
+ intent.putExtra("state", state);
+ intent.putExtra("name", name);
+ intent.putExtra("address", address);
+ mService.sendBroadcast(intent);
+ }
+
}
diff --git a/ring-android/app/src/main/java/cx/ring/service/DRingService.java b/ring-android/app/src/main/java/cx/ring/service/DRingService.java
index 3ea9992..c9651ac 100644
--- a/ring-android/app/src/main/java/cx/ring/service/DRingService.java
+++ b/ring-android/app/src/main/java/cx/ring/service/DRingService.java
@@ -1476,5 +1476,55 @@
}
});
}
+
+ public void lookupName(final String account, final String nameserver, final String name) {
+ getExecutor().execute(new SipRunnable() {
+ @Override
+ protected void doRun() throws SameThreadException, RemoteException {
+ Log.i(TAG, "DRingService.lookupName thread running() " + name);
+ if (!Ringservice.lookupName(account, nameserver, name)) {
+ Intent intent = new Intent(ConfigurationManagerCallback.NAME_LOOKUP_ENDED);
+ intent.putExtra("account", account);
+ intent.putExtra("state", -1);
+ intent.putExtra("name", name);
+ sendBroadcast(intent);
+ }
+ Log.i(TAG, "DRingService.lookupName DONE " + name);
+ }
+ });
+ }
+
+ public void lookupAddress(final String account, final String nameserver, final String address) {
+ getExecutor().execute(new SipRunnable() {
+ @Override
+ protected void doRun() throws SameThreadException, RemoteException {
+ Log.i(TAG, "DRingService.lookupAddress thread running() " + address);
+ if (!Ringservice.lookupAddress(account, nameserver, address)) {
+ Intent intent = new Intent(ConfigurationManagerCallback.NAME_LOOKUP_ENDED);
+ intent.putExtra("account", account);
+ intent.putExtra("state", -1);
+ intent.putExtra("address", address);
+ sendBroadcast(intent);
+ }
+ }
+ });
+ }
+
+ public void registerName(final String account, final String password, final String name) {
+ getExecutor().execute(new SipRunnable() {
+ @Override
+ protected void doRun() throws SameThreadException, RemoteException {
+ Log.w(TAG, "DRingService.registerName thread running() " + name);
+ if (!Ringservice.registerName(account, password, name)) {
+ Intent intent = new Intent(ConfigurationManagerCallback.NAME_REGISTRATION_ENDED);
+ intent.putExtra("account", account);
+ intent.putExtra("state", -1);
+ intent.putExtra("name", name);
+ sendBroadcast(intent);
+ }
+ }
+ });
+ }
+
};
}
diff --git a/ring-android/app/src/main/java/cx/ring/service/IDRingService.aidl b/ring-android/app/src/main/java/cx/ring/service/IDRingService.aidl
index 0c50e0a..c7bf03b 100644
--- a/ring-android/app/src/main/java/cx/ring/service/IDRingService.aidl
+++ b/ring-android/app/src/main/java/cx/ring/service/IDRingService.aidl
@@ -32,6 +32,10 @@
void hold(in String callID);
void unhold(in String callID);
+ void lookupName(in String account, in String nameserver, in String name);
+ void lookupAddress(in String account, in String nameserver, in String address);
+ void registerName(in String account, in String password, in String name);
+
List getAccountList();
String addAccount(in Map accountDetails);
void removeAccount(in String accoundId);
diff --git a/ring-android/app/src/main/java/cx/ring/service/LocalService.java b/ring-android/app/src/main/java/cx/ring/service/LocalService.java
index 31077f4..79c15b5 100644
--- a/ring-android/app/src/main/java/cx/ring/service/LocalService.java
+++ b/ring-android/app/src/main/java/cx/ring/service/LocalService.java
@@ -152,6 +152,27 @@
private boolean mAreConversationsLoaded = false;
+ public interface NameLookupCallback {
+ void onFound(String name, String address);
+
+ void onInvalidName(String name);
+
+ void onError(String name, String address);
+ }
+
+ ;
+ final private Map<String, ArrayList<NameLookupCallback>> currentNameLookup = new HashMap<>();
+ final private Map<String, ArrayList<NameLookupCallback>> currentAddressLookup = new HashMap<>();
+
+ public interface NameRegistrationCallback {
+ void onRegistered(String name);
+
+ void onError(String name, CharSequence err);
+ }
+
+ ;
+ final private Map<String, ArrayList<NameRegistrationCallback>> currentNameRegistrations = new HashMap<>();
+
public ContactsLoader.Result getSortedContacts() {
Log.w(TAG, "getSortedContacts " + lastContactLoaderResult.contacts.size() + " contacts, " + lastContactLoaderResult.starred.size() + " starred.");
return lastContactLoaderResult;
@@ -247,6 +268,54 @@
}
}
+ public void lookupName(final String account, final String name, final NameLookupCallback cb) {
+ try {
+ ArrayList<NameLookupCallback> cbs = currentNameLookup.get(name);
+ if (cbs == null) {
+ cbs = new ArrayList<>();
+ currentNameLookup.put(name, cbs);
+ }
+ cbs.add(cb);
+ mService.lookupName(account == null ? "" : account, "", name);
+ } catch (RemoteException e) {
+ cb.onError(name, null);
+ }
+ }
+
+ public void lookupAddress(final String account, final String address, final NameLookupCallback cb) {
+ try {
+ ArrayList<NameLookupCallback> cbs = currentAddressLookup.get(address);
+ if (cbs == null) {
+ cbs = new ArrayList<>();
+ currentAddressLookup.put(address, cbs);
+ }
+ cbs.add(cb);
+ mService.lookupAddress(account, null, address);
+ } catch (RemoteException e) {
+ cb.onError(null, address);
+ }
+ }
+
+ public void registerName(final Account account, final String password, final String name, final NameRegistrationCallback cb) {
+ if (account.registeringUsername) {
+ Log.w(TAG, "Already trying to register username");
+ return;
+ }
+ try {
+ ArrayList<NameRegistrationCallback> cbs = currentNameRegistrations.get(name);
+ if (cbs == null) {
+ cbs = new ArrayList<>();
+ currentNameRegistrations.put(name, cbs);
+ }
+ cbs.add(cb);
+ account.registeringUsername = true;
+ mService.registerName(account.getAccountID(), password, name);
+ } catch (RemoteException e) {
+ account.registeringUsername = false;
+ }
+ account.notifyObservers();
+ }
+
public void sendTextMessage(Conference conf, String txt) {
try {
mService.sendTextMessage(conf.getId(), txt);
@@ -1418,6 +1487,79 @@
}
break;
}
+ case ConfigurationManagerCallback.NAME_LOOKUP_ENDED: {
+ String name = intent.getStringExtra("name");
+ String address = intent.getStringExtra("address");
+ int state = intent.getIntExtra("state", -1);
+ ArrayList<NameLookupCallback> name_cbs = currentNameLookup.get(name);
+ ArrayList<NameLookupCallback> addr_cbs = currentAddressLookup.get(address);
+ if (name_cbs != null) {
+ for (NameLookupCallback cb : name_cbs) {
+ if (state == 0)
+ cb.onFound(name, address);
+ else if (state == 1)
+ cb.onInvalidName(name);
+ else
+ cb.onError(name, address);
+ }
+ name_cbs.clear();
+ }
+ if (addr_cbs != null) {
+ for (NameLookupCallback cb : addr_cbs) {
+ if (state == 0)
+ cb.onFound(name, address);
+ else if (state == 1)
+ cb.onInvalidName(name);
+ else
+ cb.onError(name, address);
+ }
+ addr_cbs.clear();
+ }
+ break;
+ }
+ case ConfigurationManagerCallback.NAME_REGISTRATION_ENDED: {
+ Account acc = getAccount(intent.getStringExtra("account"));
+ if (acc == null) {
+ Log.w(TAG, "Can't find account for name registration callback");
+ break;
+ }
+ String name = intent.getStringExtra("name");
+ int state = intent.getIntExtra("state", -1);
+ acc.registeringUsername = false;
+ ArrayList<NameRegistrationCallback> reg_cbs = currentNameRegistrations.get(name);
+ if (reg_cbs != null) {
+ for (NameRegistrationCallback cb : reg_cbs) {
+ if (state == 0) {
+ try {
+ acc.setVolatileDetails((Map<String, String>) mService.getVolatileAccountDetails(acc.getAccountID()));
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ cb.onRegistered(name);
+ } else {
+ int res = -1;
+ switch (state) {
+ case 1:
+ res = R.string.register_name_wrong_password;
+ break;
+ case 2:
+ res = R.string.register_name_invalid;
+ break;
+ case 3:
+ res = R.string.register_name_already_taken;
+ break;
+ case 4:
+ res = R.string.register_name_network_error;
+ break;
+ }
+ cb.onError(name, getText(res));
+ }
+ }
+ reg_cbs.clear();
+ }
+ acc.notifyObservers();
+ break;
+ }
case CallManagerCallBack.INCOMING_CALL: {
String callId = intent.getStringExtra("call");
String accountId = intent.getStringExtra("account");
@@ -1545,6 +1687,8 @@
intentFilter.addAction(ConfigurationManagerCallback.ACCOUNTS_DEVICES_CHANGED);
intentFilter.addAction(ConfigurationManagerCallback.INCOMING_TEXT);
intentFilter.addAction(ConfigurationManagerCallback.MESSAGE_STATE_CHANGED);
+ intentFilter.addAction(ConfigurationManagerCallback.NAME_LOOKUP_ENDED);
+ intentFilter.addAction(ConfigurationManagerCallback.NAME_REGISTRATION_ENDED);
intentFilter.addAction(CallManagerCallBack.INCOMING_CALL);
intentFilter.addAction(CallManagerCallBack.INCOMING_TEXT);
diff --git a/ring-android/app/src/main/java/cx/ring/utils/BlockchainTextWatcher.java b/ring-android/app/src/main/java/cx/ring/utils/BlockchainTextWatcher.java
new file mode 100644
index 0000000..6e43d3e
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/utils/BlockchainTextWatcher.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2016 Savoir-faire Linux Inc.
+ *
+ * Author: Thibault Wittemberg <thibault.wittemberg@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package cx.ring.utils;
+
+import android.support.annotation.NonNull;
+import android.support.design.widget.TextInputLayout;
+import android.text.Editable;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.widget.EditText;
+
+import java.lang.ref.WeakReference;
+
+import cx.ring.R;
+import cx.ring.service.LocalService;
+
+public class BlockchainTextWatcher implements TextWatcher, LocalService.NameLookupCallback {
+
+ private static final String TAG = BlockchainTextWatcher.class.getName();
+
+ private WeakReference<TextInputLayout> mInputLayout;
+ private WeakReference<EditText> mInputText;
+ private WeakReference<LocalService> mLocalService;
+ private BlockchainInputHandler mBlockchainInputHandler;
+ private String mUserNameAlreadyTaken;
+ private String mInvalidUsername;
+ private String mLookinForAvailability;
+
+ public BlockchainTextWatcher(final LocalService.Callbacks callbacks, final TextInputLayout inputLayout, final EditText inputText) {
+ mInputLayout = new WeakReference<>(inputLayout);
+ mInputText = new WeakReference<>(inputText);
+
+ if (callbacks != null && callbacks.getService() != null) {
+ mLocalService = new WeakReference<>(callbacks.getService());
+ LocalService localService = callbacks.getService();
+ mUserNameAlreadyTaken = localService.getString(R.string.username_already_taken);
+ mInvalidUsername = localService.getString(R.string.invalid_username);
+ mLookinForAvailability = localService.getString(R.string.looking_for_username_availability);
+ mBlockchainInputHandler = new BlockchainInputHandler(mLocalService, this);
+ } else {
+ mLocalService = new WeakReference<>(null);
+ mBlockchainInputHandler = new BlockchainInputHandler(mLocalService, this);
+ }
+ }
+
+ @Override
+ public void onFound(String name, String address) {
+ if (mInputText.get() != null) {
+ String searchedText = mInputText.get().getText().toString();
+ Log.w(TAG, "Name lookup UI : onFound " + name + " " + address + " (current " + searchedText + ")");
+ if (name.equals(searchedText)) {
+ mInputLayout.get().setErrorEnabled(true);
+ mInputLayout.get().setError(mUserNameAlreadyTaken);
+ }
+ }
+ }
+
+ @Override
+ public void onInvalidName(String name) {
+ if (mInputText.get() != null) {
+ String searchedText = mInputText.get().getText().toString();
+ Log.w(TAG, "Name lookup UI : onInvalidName " + name + " (current " + searchedText + ")");
+ if (name.equals(searchedText)) {
+
+ if (TextUtils.isEmpty(name)) {
+ mInputLayout.get().setErrorEnabled(false);
+ mInputLayout.get().setError(null);
+ } else {
+ mInputLayout.get().setErrorEnabled(true);
+ mInputLayout.get().setError(mInvalidUsername);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onError(String name, String address) {
+ if (mInputText.get() != null) {
+ String searchedText = mInputText.get().getText().toString();
+ Log.w(TAG, "Name lookup UI : onError " + name + " " + address + " (current " + searchedText + ")");
+ if (name.equals(searchedText)) {
+ mInputLayout.get().setErrorEnabled(false);
+ mInputLayout.get().setError(null);
+ }
+ }
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ if (mInputText.get() != null) {
+ mInputText.get().setError(null);
+ }
+ }
+
+ @Override
+ public void afterTextChanged(final Editable txt) {
+ final String name = txt.toString();
+
+ if (mInputLayout.get() == null || mInputText.get() == null) {
+ return;
+ }
+
+ if (TextUtils.isEmpty(name)) {
+ mInputLayout.get().setErrorEnabled(false);
+ mInputLayout.get().setError(null);
+ } else {
+ mInputLayout.get().setErrorEnabled(true);
+ mInputLayout.get().setError(mLookinForAvailability);
+ }
+
+ if (mBlockchainInputHandler.isAlive()) {
+ mBlockchainInputHandler.enqueueNextLookup(name);
+ } else {
+ mBlockchainInputHandler = new BlockchainInputHandler(mLocalService, this);
+ mBlockchainInputHandler.enqueueNextLookup(name);
+ }
+ }
+
+ private class BlockchainInputHandler extends Thread {
+
+ private WeakReference<LocalService> mLocalService;
+ private String mTextToLookup;
+ private LocalService.NameLookupCallback mLookupCallback;
+
+ private boolean mIsWaitingForInputs = false;
+ private long mLastEnqueuedInputTimeStamp = -1;
+
+ public BlockchainInputHandler(@NonNull WeakReference<LocalService> localService, @NonNull LocalService.NameLookupCallback lookupCallback) {
+ mLocalService = localService;
+ mLookupCallback = lookupCallback;
+ }
+
+ public void enqueueNextLookup(String text) {
+
+ if (mLocalService.get() == null) {
+ return;
+ }
+
+ mLastEnqueuedInputTimeStamp = System.currentTimeMillis();
+ mTextToLookup = text;
+
+ if (!mIsWaitingForInputs) {
+ mIsWaitingForInputs = true;
+ start();
+ }
+ }
+
+ @Override
+ public void run() {
+ while (mIsWaitingForInputs) {
+ try {
+ Thread.sleep(100);
+
+ long timeFromLastEnqueuedInput = System.currentTimeMillis() - mLastEnqueuedInputTimeStamp;
+ if (timeFromLastEnqueuedInput >= 6000) {
+ // we've been waiting for a long time, stop the wait
+ // the next user input will trigger the next wait
+ mIsWaitingForInputs = false;
+ } else if (timeFromLastEnqueuedInput >= 3000) {
+ // trigger the blockchain lookup
+ final LocalService localService = mLocalService.get();
+ localService.lookupName("", mTextToLookup, mLookupCallback);
+ // stop the wait
+ mIsWaitingForInputs = false;
+ }
+
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Error while waiting for next Blockchain lookup", e);
+ }
+ }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/ring-android/app/src/main/java/cx/ring/utils/BlockchainUtils.java b/ring-android/app/src/main/java/cx/ring/utils/BlockchainUtils.java
new file mode 100644
index 0000000..c3d1a84
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/utils/BlockchainUtils.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 Savoir-faire Linux Inc.
+ *
+ * Author: Thibault Wittemberg <thibault.wittemberg@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package cx.ring.utils;
+
+import android.support.design.widget.TextInputLayout;
+import android.text.InputFilter;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.TextWatcher;
+import android.widget.EditText;
+
+import cx.ring.service.LocalService;
+
+public class BlockchainUtils {
+
+ public static TextWatcher attachUsernameTextWatcher(final LocalService.Callbacks callbacks, final TextInputLayout inputLayout, final EditText inputText) {
+ TextWatcher textWatcher = new BlockchainTextWatcher(callbacks, inputLayout, inputText);
+ inputText.addTextChangedListener(textWatcher);
+ return textWatcher;
+ }
+
+ public static void attachUsernameTextFilter(final EditText inputText) {
+ InputFilter filter = new InputFilter() {
+
+ @Override
+ public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
+ boolean keepOriginal = true;
+ StringBuilder sb = new StringBuilder(end - start);
+ for (int i = start; i < end; i++) {
+ char c = source.charAt(i);
+ if (isCharAllowed(c)) {
+ sb.append(c);
+ } else {
+ keepOriginal = false;
+ }
+ }
+ if (keepOriginal) {
+ return null;
+ } else {
+ if (source instanceof Spanned) {
+ SpannableString sp = new SpannableString(sb);
+ return sp;
+ } else {
+ return sb;
+ }
+ }
+ }
+
+ private boolean isCharAllowed(char c) {
+ String textToTest = "" + c;
+ return textToTest.matches("[a-z0-9_\\-]");
+ }
+ };
+
+ inputText.setFilters(new InputFilter[]{filter});
+ }
+}
diff --git a/ring-android/app/src/main/java/cx/ring/views/BoundedLinearLayout.java b/ring-android/app/src/main/java/cx/ring/views/BoundedLinearLayout.java
index f19dbee..fc49ba1 100644
--- a/ring-android/app/src/main/java/cx/ring/views/BoundedLinearLayout.java
+++ b/ring-android/app/src/main/java/cx/ring/views/BoundedLinearLayout.java
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2016 Savoir-faire Linux Inc.
+ *
+ * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
package cx.ring.views;
import android.content.Context;
@@ -8,9 +27,7 @@
import cx.ring.R;
public class BoundedLinearLayout extends LinearLayout {
-
private final int mBoundedWidth;
-
private final int mBoundedHeight;
public BoundedLinearLayout(Context context) {
@@ -31,13 +48,13 @@
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Adjust width as necessary
int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
- if(mBoundedWidth > 0 && mBoundedWidth < measuredWidth) {
+ if (mBoundedWidth > 0 && mBoundedWidth < measuredWidth) {
int measureMode = MeasureSpec.getMode(widthMeasureSpec);
widthMeasureSpec = MeasureSpec.makeMeasureSpec(mBoundedWidth, measureMode);
}
// Adjust height as necessary
int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
- if(mBoundedHeight > 0 && mBoundedHeight < measuredHeight) {
+ if (mBoundedHeight > 0 && mBoundedHeight < measuredHeight) {
int measureMode = MeasureSpec.getMode(heightMeasureSpec);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(mBoundedHeight, measureMode);
}
diff --git a/ring-android/app/src/main/java/cx/ring/views/BoundedRelativeLayout.java b/ring-android/app/src/main/java/cx/ring/views/BoundedRelativeLayout.java
new file mode 100644
index 0000000..712501d
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/views/BoundedRelativeLayout.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 Savoir-faire Linux Inc.
+ *
+ * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package cx.ring.views;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.widget.RelativeLayout;
+
+import cx.ring.R;
+
+public class BoundedRelativeLayout extends RelativeLayout {
+ private final int mBoundedWidth;
+ private final int mBoundedHeight;
+
+ public BoundedRelativeLayout(Context context) {
+ super(context);
+ mBoundedWidth = 0;
+ mBoundedHeight = 0;
+ }
+
+ public BoundedRelativeLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BoundedView);
+ mBoundedWidth = a.getDimensionPixelSize(R.styleable.BoundedView_bounded_width, 0);
+ mBoundedHeight = a.getDimensionPixelSize(R.styleable.BoundedView_bounded_height, 0);
+ a.recycle();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // Adjust width as necessary
+ int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
+ if (mBoundedWidth > 0 && mBoundedWidth < measuredWidth) {
+ int measureMode = MeasureSpec.getMode(widthMeasureSpec);
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(mBoundedWidth, measureMode);
+ }
+ // Adjust height as necessary
+ int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
+ if (mBoundedHeight > 0 && mBoundedHeight < measuredHeight) {
+ int measureMode = MeasureSpec.getMode(heightMeasureSpec);
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(mBoundedHeight, measureMode);
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+}
\ No newline at end of file
diff --git a/ring-android/app/src/main/java/cx/ring/views/BoundedScrollView.java b/ring-android/app/src/main/java/cx/ring/views/BoundedScrollView.java
new file mode 100644
index 0000000..20a69b3
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/views/BoundedScrollView.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 Savoir-faire Linux Inc.
+ *
+ * Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+package cx.ring.views;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.widget.ScrollView;
+
+import cx.ring.R;
+
+public class BoundedScrollView extends ScrollView {
+ private final int mBoundedWidth;
+ private final int mBoundedHeight;
+
+ public BoundedScrollView(Context context) {
+ super(context);
+ mBoundedWidth = 0;
+ mBoundedHeight = 0;
+ }
+
+ public BoundedScrollView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BoundedView);
+ mBoundedWidth = a.getDimensionPixelSize(R.styleable.BoundedView_bounded_width, 0);
+ mBoundedHeight = a.getDimensionPixelSize(R.styleable.BoundedView_bounded_height, 0);
+ a.recycle();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ // Adjust width as necessary
+ int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
+ if (mBoundedWidth > 0 && mBoundedWidth < measuredWidth) {
+ int measureMode = MeasureSpec.getMode(widthMeasureSpec);
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(mBoundedWidth, measureMode);
+ }
+ // Adjust height as necessary
+ int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
+ if (mBoundedHeight > 0 && mBoundedHeight < measuredHeight) {
+ int measureMode = MeasureSpec.getMode(heightMeasureSpec);
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(mBoundedHeight, measureMode);
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+}
\ No newline at end of file
diff --git a/ring-android/app/src/main/jni/configurationmanager.i b/ring-android/app/src/main/jni/configurationmanager.i
index 384a039..45f8415 100644
--- a/ring-android/app/src/main/jni/configurationmanager.i
+++ b/ring-android/app/src/main/jni/configurationmanager.i
@@ -47,6 +47,9 @@
virtual void errorAlert(int alert){}
virtual void getHardwareAudioFormat(std::vector<int32_t>* /*params_ret*/){}
virtual void getAppDataPath(const std::string& /* name */, std::vector<std::string>* /*path_ret*/){}
+
+ virtual void nameRegistrationEnded(const std::string& /*account_id*/, int state, const std::string& /*name*/){}
+ virtual void registeredNameFound(const std::string& /*account_id*/, int state, const std::string& /*address*/, const std::string& /*name*/){}
};
%}
@@ -67,6 +70,10 @@
uint64_t sendAccountTextMessage(const std::string& accountID, const std::string& to, const std::map<std::string, std::string>& message);
int getMessageStatus(uint64_t id);
+bool lookupName(const std::string& account, const std::string& nameserver, const std::string& name);
+bool lookupAddress(const std::string& account, const std::string& nameserver, const std::string& address);
+bool registerName(const std::string& account, const std::string& password, const std::string& name);
+
std::map<std::string, std::string> getTlsDefaultSettings();
std::vector<unsigned> getCodecList();
@@ -200,4 +207,7 @@
virtual void errorAlert(int alert){}
virtual void getHardwareAudioFormat(std::vector<int32_t>* /*params_ret*/){}
virtual void getAppDataPath(const std::string& /* name */, std::vector<std::string>* /*path_ret*/){}
+
+ virtual void nameRegistrationEnded(const std::string& /*account_id*/, int state, const std::string& /*name*/){}
+ virtual void registeredNameFound(const std::string& /*account_id*/, int state, const std::string& /*address*/, const std::string& /*name*/){}
};
diff --git a/ring-android/app/src/main/jni/jni_interface.i b/ring-android/app/src/main/jni/jni_interface.i
index bdf7767..41cf43e 100644
--- a/ring-android/app/src/main/jni/jni_interface.i
+++ b/ring-android/app/src/main/jni/jni_interface.i
@@ -61,22 +61,26 @@
public static $javaclassname toSwig(java.util.Map<String,String> in) {
$javaclassname n = new $javaclassname();
for (java.util.Map.Entry<String, String> entry : in.entrySet()) {
- n.set(entry.getKey(), entry.getValue());
+ if (entry.getValue() != null) {
+ n.set(entry.getKey(), entry.getValue());
+ }
}
return n;
}
public java.util.HashMap<String,String> toNative() {
java.util.HashMap<String,String> out = new java.util.HashMap<>((int)size());
StringVect keys = keys();
- for (String s : keys)
- out.put(s, get(s));
+ for (String s : keys) {
+ out.put(s, get(s));
+ }
return out;
}
public java.util.HashMap<String,String> toNativeFromUtf8() {
java.util.HashMap<String,String> out = new java.util.HashMap<>((int)size());
StringVect keys = keys();
- for (String s : keys)
- out.put(s, getRaw(s).toJavaString());
+ for (String s : keys) {
+ out.put(s, getRaw(s).toJavaString());
+ }
return out;
}
%}
@@ -84,8 +88,9 @@
std::vector<std::string> keys() const {
std::vector<std::string> k;
k.reserve($self->size());
- for (const auto& i : *$self)
+ for (const auto& i : *$self) {
k.push_back(i.first);
+ }
return k;
}
void setRaw(std::string key, const vector<uint8_t>& value) {
@@ -119,8 +124,9 @@
%typemap(javacode) vector< map<string,string> > %{
public java.util.ArrayList<java.util.Map<String, String>> toNative() {
java.util.ArrayList<java.util.Map<String, String>> out = new java.util.ArrayList<>();
- for (int i = 0; i < size(); ++i)
- out.add(get(i).toNative());
+ for (int i = 0; i < size(); ++i) {
+ out.add(get(i).toNative());
+ }
return out;
}
%}
@@ -138,14 +144,16 @@
dat = in.getBytes();
}
Blob n = new Blob(dat.length);
- for (int i=0; i<dat.length; i++)
+ for (int i=0; i<dat.length; i++) {
n.set(i, dat[i]);
+ }
return n;
}
public String toJavaString() {
byte[] dat = new byte[(int)size()];
- for (int i=0; i<dat.length; i++)
+ for (int i=0; i<dat.length; i++) {
dat[i] = (byte)get(i);
+ }
try {
return new String(dat, "utf-8");
} catch (java.io.UnsupportedEncodingException e) {
@@ -229,28 +237,11 @@
exportable_callback<ConfigurationSignal::CertificateExpired>(bind(&ConfigurationCallback::certificateExpired, confM, _1 )),
exportable_callback<ConfigurationSignal::CertificateStateChanged>(bind(&ConfigurationCallback::certificateStateChanged, confM, _1, _2, _3 )),
exportable_callback<ConfigurationSignal::GetHardwareAudioFormat>(bind(&ConfigurationCallback::getHardwareAudioFormat, confM, _1 )),
- exportable_callback<ConfigurationSignal::GetAppDataPath>(bind(&ConfigurationCallback::getAppDataPath, confM, _1, _2 ))
+ exportable_callback<ConfigurationSignal::GetAppDataPath>(bind(&ConfigurationCallback::getAppDataPath, confM, _1, _2 )),
+ exportable_callback<ConfigurationSignal::RegisteredNameFound>(bind(&ConfigurationCallback::registeredNameFound, confM, _1, _2, _3, _4 )),
+ exportable_callback<ConfigurationSignal::NameRegistrationEnded>(bind(&ConfigurationCallback::nameRegistrationEnded, confM, _1, _2, _3 ))
};
-/*
- // Presence event handlers
- const std::map<std::string, SharedCallback> presEvHandlers = {
- exportable_callback<PresenceSignal::NewServerSubscriptionRequest>(bind(&DBusPresenceManager::newServerSubscriptionRequest, presM, _1)),
- exportable_callback<PresenceSignal::ServerError>(bind(&DBusPresenceManager::serverError, presM, _1, _2, _3)),
- exportable_callback<PresenceSignal::NewBuddyNotification>(bind(&DBusPresenceManager::newBuddyNotification, presM, _1, _2, _3, _4)),
- exportable_callback<PresenceSignal::SubscriptionStateChanged>(bind(&DBusPresenceManager::subscriptionStateChanged, presM, _1, _2, _3)),
- };
-
-#ifdef RING_VIDEO
- // Video event handlers
- const std::map<std::string, SharedCallback> videoEvHandlers = {
- exportable_callback<VideoSignal::DeviceEvent>(bind(&DBusVideoManager::deviceEvent, videoM)),
- exportable_callback<VideoSignal::DecodingStarted>(bind(&DBusVideoManager::startedDecoding, videoM, _1, _2, _3, _4, _5)),
- exportable_callback<VideoSignal::DecodingStopped>(bind(&DBusVideoManager::stoppedDecoding, videoM, _1, _2, _3)),
- };
-#endif
-*/
-
const std::map<std::string, SharedCallback> videoEvHandlers = {
exportable_callback<VideoSignal::GetCameraInfo>(bind(&VideoCallback::getCameraInfo, videoM, _1, _2, _3, _4)),
exportable_callback<VideoSignal::SetParameters>(bind(&VideoCallback::setParameters, videoM, _1, _2, _3, _4, _5)),
@@ -265,7 +256,6 @@
registerCallHandlers(callEvHandlers);
registerConfHandlers(configEvHandlers);
-/* registerPresHandlers(presEvHandlers); */
registerVideoHandlers(videoEvHandlers);
DRing::start();
diff --git a/ring-android/app/src/main/res/drawable-hdpi/ic_edit_black_24dp.png b/ring-android/app/src/main/res/drawable-hdpi/ic_edit_black_24dp.png
new file mode 100644
index 0000000..e531d72
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-hdpi/ic_edit_black_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-mdpi/ic_edit_black_24dp.png b/ring-android/app/src/main/res/drawable-mdpi/ic_edit_black_24dp.png
new file mode 100644
index 0000000..9efbaae
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-mdpi/ic_edit_black_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xhdpi/ic_edit_black_24dp.png b/ring-android/app/src/main/res/drawable-xhdpi/ic_edit_black_24dp.png
new file mode 100644
index 0000000..87f8de1
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xhdpi/ic_edit_black_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxhdpi/ic_edit_black_24dp.png b/ring-android/app/src/main/res/drawable-xxhdpi/ic_edit_black_24dp.png
new file mode 100644
index 0000000..4af4ae6
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxhdpi/ic_edit_black_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable-xxxhdpi/ic_edit_black_24dp.png b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_edit_black_24dp.png
new file mode 100644
index 0000000..d6761ba
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable-xxxhdpi/ic_edit_black_24dp.png
Binary files differ
diff --git a/ring-android/app/src/main/res/drawable/background_tabs.xml b/ring-android/app/src/main/res/drawable/background_tabs.xml
index 885cf03..53e85df 100644
--- a/ring-android/app/src/main/res/drawable/background_tabs.xml
+++ b/ring-android/app/src/main/res/drawable/background_tabs.xml
@@ -2,7 +2,6 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android" android:exitFadeDuration="@android:integer/config_shortAnimTime">
<item android:state_pressed="true" android:drawable="@color/background_tab_pressed" />
- <item android:state_focused="true" android:drawable="@color/background_tab_pressed"/>
- <item android:drawable="@android:color/transparent"/>
-
+ <item android:state_focused="true" android:drawable="@color/background_tab_pressed" />
+ <item android:drawable="@android:color/transparent" />
</selector>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/activity_account_settings.xml b/ring-android/app/src/main/res/layout/activity_account_settings.xml
index 41475d2..22f98d5 100644
--- a/ring-android/app/src/main/res/layout/activity_account_settings.xml
+++ b/ring-android/app/src/main/res/layout/activity_account_settings.xml
@@ -1,4 +1,4 @@
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
@@ -14,14 +14,15 @@
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:background="@color/color_primary_light"
- android:orientation="vertical"
android:elevation="4dp"
- app:elevation="4dp">
+ android:orientation="vertical">
+
<android.support.v7.widget.Toolbar
android:id="@+id/main_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:background="@color/color_primary_light"
android:minHeight="?attr/actionBarSize"
android:popupTheme="@style/Theme.AppCompat.Light.NoActionBar"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
@@ -50,4 +51,9 @@
android:layout_alignParentBottom="true"
android:layout_below="@id/header_container" />
-</RelativeLayout>
\ No newline at end of file
+ <FrameLayout
+ android:id="@+id/fragment_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/activity_home.xml b/ring-android/app/src/main/res/layout/activity_home.xml
index 67d25c5..71646e5 100644
--- a/ring-android/app/src/main/res/layout/activity_home.xml
+++ b/ring-android/app/src/main/res/layout/activity_home.xml
@@ -57,7 +57,7 @@
android:elevation="@dimen/toolbar_elevation"
android:layout_below="@+id/main_toolbar"
android:background="@color/color_primary_light"
- android:visibility="visible"
+ android:visibility="gone"
android:paddingLeft="@dimen/toolbar_content_inset"
android:gravity="center_vertical">
@@ -97,11 +97,7 @@
app:elevation="6dp"
app:fabSize="mini"
app:pressedTranslationZ="12dp"
- app:rippleColor="@android:color/white">
-
-
-
- </android.support.design.widget.FloatingActionButton>
+ app:rippleColor="@android:color/white" />
</RelativeLayout>
diff --git a/ring-android/app/src/main/res/layout/activity_wizard.xml b/ring-android/app/src/main/res/layout/activity_wizard.xml
index 37d0c24..abc4a41 100644
--- a/ring-android/app/src/main/res/layout/activity_wizard.xml
+++ b/ring-android/app/src/main/res/layout/activity_wizard.xml
@@ -18,8 +18,8 @@
app:elevation="4dp"
app:titleTextAppearance="@style/ToolbarTitle" />
- <android.support.v4.view.ViewPager
- android:id="@+id/pager"
+ <FrameLayout
+ android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
diff --git a/ring-android/app/src/main/res/layout/dialog_new_device.xml b/ring-android/app/src/main/res/layout/dialog_new_device.xml
index 268b2a4..039f4d3 100644
--- a/ring-android/app/src/main/res/layout/dialog_new_device.xml
+++ b/ring-android/app/src/main/res/layout/dialog_new_device.xml
@@ -4,16 +4,21 @@
android:layout_height="wrap_content"
android:orientation="vertical">
- <EditText
- android:id="@+id/pwd_txt"
+ <android.support.design.widget.TextInputLayout
+ android:id="@+id/ring_password_txt_box"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal"
- android:layout_marginLeft="20dp"
- android:layout_marginRight="20dp"
- android:layout_marginTop="8dp"
- android:ems="10"
- android:hint="@string/account_new_device_password"
- android:inputType="textPassword" />
+ android:layout_height="wrap_content">
+ <android.support.design.widget.TextInputEditText
+ android:id="@+id/pwd_txt"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginLeft="20dp"
+ android:layout_marginRight="20dp"
+ android:layout_marginTop="8dp"
+ android:ems="10"
+ android:hint="@string/account_new_device_password"
+ android:inputType="textPassword" />
+ </android.support.design.widget.TextInputLayout>
</LinearLayout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/dialog_username_registration.xml b/ring-android/app/src/main/res/layout/dialog_username_registration.xml
new file mode 100644
index 0000000..e8d5deb
--- /dev/null
+++ b/ring-android/app/src/main/res/layout/dialog_username_registration.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/ring_username_box"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <android.support.design.widget.TextInputLayout
+ android:id="@+id/ring_username_txt_box"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginLeft="12dp"
+ android:layout_marginRight="12dp">
+
+ <android.support.design.widget.TextInputEditText
+ android:id="@+id/ring_username"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/prompt_new_username"
+ android:imeOptions="actionNext"
+ android:inputType="textVisiblePassword"
+ android:lines="1"
+ android:maxLines="1" />
+ </android.support.design.widget.TextInputLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/frag_acc_ring_create.xml b/ring-android/app/src/main/res/layout/frag_acc_ring_create.xml
new file mode 100644
index 0000000..c6e16fd
--- /dev/null
+++ b/ring-android/app/src/main/res/layout/frag_acc_ring_create.xml
@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/activity_account_creation"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#eeeeee"
+ tools:context="cx.ring.client.AccountWizard">
+
+ <cx.ring.views.BoundedScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_centerHorizontal="true"
+ android:layout_gravity="center_horizontal"
+ android:background="@color/cardview_light_background"
+ app:bounded_width="500dp"
+ android:layout_above="@+id/add_action_panel">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin">
+
+ <ImageView
+ android:id="@+id/imageView6"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
+ android:layout_margin="16dp"
+ android:contentDescription="@string/app_name"
+ android:src="@drawable/ring_logo_48dp" />
+
+ <TextView
+ android:id="@+id/ring_acc_descr_txt"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_toLeftOf="@+id/imageView6"
+ android:layout_toStartOf="@+id/imageView6"
+ android:paddingBottom="16dp"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp"
+ android:paddingTop="16dp"
+ android:text="@string/help_ring"
+ android:textColor="@color/text_color_primary"
+ android:textSize="14sp" />
+
+ <LinearLayout
+ android:id="@+id/newAccountLayout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_below="@+id/ring_acc_descr_txt"
+ android:animateLayoutChanges="true"
+ android:orientation="vertical">
+
+ <Switch
+ android:id="@+id/switch_ring_username"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:checked="true"
+ android:padding="16dp"
+ android:text="@string/register_username"
+ android:textColor="@color/text_color_secondary" />
+
+ <LinearLayout
+ android:id="@+id/ring_username_box"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <android.support.design.widget.TextInputLayout
+ android:id="@+id/ring_username_txt_box"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginLeft="12dp"
+ android:layout_marginRight="12dp">
+
+ <android.support.design.widget.TextInputEditText
+ android:id="@+id/ring_username"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/prompt_new_username"
+ android:imeOptions="actionNext"
+ android:inputType="textVisiblePassword"
+ android:lines="1"
+ android:maxLines="1" />
+ </android.support.design.widget.TextInputLayout>
+
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/ring_password_help_txt"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="8dp"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp"
+ android:paddingTop="16dp"
+ android:text="@string/help_password_choose"
+ android:textColor="@color/text_color_secondary"
+ android:textSize="14sp" />
+
+ <android.support.design.widget.TextInputLayout
+ android:id="@+id/ring_password_txt_box"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="12dp"
+ android:layout_marginRight="12dp">
+
+ <android.support.design.widget.TextInputEditText
+ android:id="@+id/ring_password"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/prompt_new_password"
+ android:imeOptions="actionNext"
+ android:inputType="textPassword" />
+ </android.support.design.widget.TextInputLayout>
+
+ <android.support.design.widget.TextInputLayout
+ android:id="@+id/ring_password_repeat_txt_box"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="12dp"
+ android:layout_marginRight="12dp">
+
+ <android.support.design.widget.TextInputEditText
+ android:id="@+id/ring_password_repeat"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/prompt_new_password_repeat"
+ android:imeActionId="@integer/register_sip_account_actionid"
+ android:imeActionLabel="@string/action_create_short"
+ android:inputType="textPassword" />
+ </android.support.design.widget.TextInputLayout>
+
+ </LinearLayout>
+ </RelativeLayout>
+ </cx.ring.views.BoundedScrollView>
+
+ <LinearLayout
+ android:id="@+id/add_action_panel"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:background="@color/color_primary_dark">
+
+ <android.support.v7.widget.AppCompatButton
+ android:id="@+id/add_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?attr/selectableItemBackground"
+ android:paddingBottom="5dp"
+ android:paddingTop="5dp"
+ android:text="@string/action_create"
+ android:textColor="@color/white" />
+
+ </LinearLayout>
+
+</RelativeLayout>
diff --git a/ring-android/app/src/main/res/layout/frag_acc_ring_login.xml b/ring-android/app/src/main/res/layout/frag_acc_ring_login.xml
new file mode 100644
index 0000000..93fe72c
--- /dev/null
+++ b/ring-android/app/src/main/res/layout/frag_acc_ring_login.xml
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/activity_account_creation"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#eeeeee">
+
+ <cx.ring.views.BoundedScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_centerHorizontal="true"
+ android:layout_gravity="center_horizontal"
+ android:background="@color/cardview_light_background"
+ app:bounded_width="500dp">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin">
+
+ <ImageView
+ android:id="@+id/imageView6"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
+ android:layout_margin="16dp"
+ android:contentDescription="@string/app_name"
+ android:src="@drawable/ring_logo_48dp" />
+
+ <TextView
+ android:id="@+id/ring_acc_descr_txt"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
+ android:layout_toLeftOf="@+id/imageView6"
+ android:layout_toStartOf="@+id/imageView6"
+ android:paddingBottom="24dp"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp"
+ android:paddingTop="16dp"
+ android:text="@string/help_ring"
+ android:textColor="@color/text_color_primary"
+ android:textSize="14sp" />
+
+ <LinearLayout
+ android:id="@+id/newAccountLayout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_below="@+id/ring_acc_descr_txt"
+ android:animateLayoutChanges="true"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="8dp"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp"
+ android:paddingTop="16dp"
+ android:text="@string/help_password_enter"
+ android:textColor="@color/text_color_secondary"
+ android:textSize="14sp" />
+
+ <EditText
+ android:id="@+id/ring_password"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="8dp"
+ android:layout_marginLeft="12dp"
+ android:layout_marginRight="12dp"
+ android:hint="@string/prompt_password"
+ android:imeOptions="actionNext"
+ android:inputType="textPassword" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="8dp"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp"
+ android:paddingTop="16dp"
+ android:text="@string/help_pin_enter"
+ android:textColor="@color/text_color_secondary"
+ android:textSize="14sp" />
+
+ <EditText
+ android:id="@+id/ring_add_pin"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="8dp"
+ android:layout_marginEnd="12dp"
+ android:layout_marginLeft="12dp"
+ android:layout_marginRight="12dp"
+ android:layout_marginStart="12dp"
+ android:digits="0123456789abcdefABCDEF"
+ android:hint="Enter PIN"
+ android:imeOptions="actionNext"
+ android:inputType="text"
+ android:maxLines="1" />
+ </LinearLayout>
+ </RelativeLayout>
+ </cx.ring.views.BoundedScrollView>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:background="@color/color_primary_dark">
+
+ <android.support.v7.widget.AppCompatButton
+ android:id="@+id/link_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?attr/selectableItemBackground"
+ android:paddingBottom="5dp"
+ android:paddingTop="5dp"
+ android:text="@string/account_link_button"
+ android:textColor="@color/white" />
+
+ </LinearLayout>
+
+</RelativeLayout>
diff --git a/ring-android/app/src/main/res/layout/frag_account_creation.xml b/ring-android/app/src/main/res/layout/frag_account_creation.xml
index 52485f2..6d0697e 100644
--- a/ring-android/app/src/main/res/layout/frag_account_creation.xml
+++ b/ring-android/app/src/main/res/layout/frag_account_creation.xml
@@ -23,24 +23,26 @@
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/login_form"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:background="#eeeeee"
tools:context=".client.AccountWizard">
<cx.ring.views.BoundedLinearLayout
style="@style/AccountFormContainer"
+ android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:animateLayoutChanges="false"
android:descendantFocusability="beforeDescendants"
android:focusableInTouchMode="true"
android:orientation="vertical"
+ android:padding="0dp"
app:bounded_width="320dp">
<android.support.v7.widget.CardView
android:id="@+id/ring_card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="16dp"
+ android:layout_margin="16dp"
android:animateLayoutChanges="false">
<RelativeLayout
@@ -65,11 +67,11 @@
android:id="@+id/ring_acc_title_txt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
+ android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
- android:layout_toLeftOf="@+id/imageView6"
android:layout_toStartOf="@+id/imageView6"
+ android:layout_toLeftOf="@+id/imageView6"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="24dp"
@@ -78,11 +80,11 @@
android:textSize="24sp" />
<TextView
- android:id="@+id/textView"
+ android:id="@+id/ring_acc_descr_txt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
+ android:layout_alignParentLeft="true"
android:layout_below="@+id/ring_acc_title_txt"
android:paddingBottom="24dp"
android:paddingLeft="16dp"
@@ -92,70 +94,13 @@
android:textColor="@color/text_color_primary"
android:textSize="14sp" />
- <LinearLayout
- android:id="@+id/addAccountLayout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_below="@id/textView"
- android:orientation="vertical"
- android:visibility="gone">
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingBottom="24dp"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:paddingTop="16dp"
- android:text="@string/account_link_infos"
- android:textColor="@color/text_color_primary"
- android:textSize="14sp" />
-
- <android.support.design.widget.TextInputLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- app:passwordToggleEnabled="true">
-
- <android.support.design.widget.TextInputEditText
- android:id="@+id/ring_add_pin"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="8dp"
- android:layout_marginEnd="12dp"
- android:layout_marginLeft="12dp"
- android:layout_marginRight="12dp"
- android:layout_marginStart="12dp"
- android:hint="@string/account_link_prompt_pin"
- android:imeOptions="actionNext"
- android:inputType="text"
- android:maxLines="1" />
- </android.support.design.widget.TextInputLayout>
-
- <android.support.design.widget.TextInputLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- app:passwordToggleEnabled="true">
-
- <android.support.design.widget.TextInputEditText
- android:id="@+id/ring_add_password"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="8dp"
- android:layout_marginEnd="12dp"
- android:layout_marginLeft="12dp"
- android:layout_marginRight="12dp"
- android:layout_marginStart="12dp"
- android:hint="@string/account_link_prompt_password"
- android:inputType="textPassword" />
- </android.support.design.widget.TextInputLayout>
- </LinearLayout>
<Button
android:id="@+id/ring_add_account"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@id/addAccountLayout"
+ android:layout_below="@id/ring_acc_descr_txt"
android:background="?android:attr/selectableItemBackground"
android:text="@string/account_link_button" />
@@ -166,68 +111,11 @@
android:background="@color/color_primary_light"
android:orientation="vertical">
- <LinearLayout
- android:id="@+id/newAccountLayout"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@color/color_primary_light"
- android:orientation="vertical"
- android:visibility="gone">
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingBottom="24dp"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
- android:paddingTop="16dp"
- android:text="@string/account_new_infos"
- android:textColor="@color/text_color_primary"
- android:textSize="14sp" />
-
- <android.support.design.widget.TextInputLayout
- android:id="@+id/password_layout"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- app:passwordToggleEnabled="true">
-
- <android.support.design.widget.TextInputEditText
- android:id="@+id/ring_password"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="8dp"
- android:layout_marginLeft="12dp"
- android:layout_marginRight="12dp"
- android:hint="@string/prompt_new_password"
- android:imeOptions="actionNext"
- android:inputType="textPassword" />
- </android.support.design.widget.TextInputLayout>
-
- <android.support.design.widget.TextInputLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- app:passwordToggleEnabled="true">
-
- <android.support.design.widget.TextInputEditText
- android:id="@+id/ring_password_repeat"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="8dp"
- android:layout_marginLeft="12dp"
- android:layout_marginRight="12dp"
- android:hint="@string/prompt_new_password_repeat"
- android:imeActionId="@integer/register_sip_account_actionid"
- android:imeActionLabel="@string/action_create_short"
- android:inputType="textPassword" />
- </android.support.design.widget.TextInputLayout>
- </LinearLayout>
-
<Button
android:id="@+id/ring_create_btn"
style="?attr/borderlessButtonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1"
android:background="?android:attr/selectableItemBackground"
android:text="@string/account_new_button"
android:textColor="@color/text_color_primary_dark" />
@@ -237,12 +125,12 @@
</android.support.v7.widget.CardView>
- <android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
+ <android.support.v7.widget.CardView
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:layout_marginBottom="8dp"
+ android:layout_margin="16dp"
android:animateLayoutChanges="false"
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground">
diff --git a/ring-android/app/src/main/res/layout/frag_device_list.xml b/ring-android/app/src/main/res/layout/frag_device_list.xml
index 8f6a3b8..05a2317 100644
--- a/ring-android/app/src/main/res/layout/frag_device_list.xml
+++ b/ring-android/app/src/main/res/layout/frag_device_list.xml
@@ -16,55 +16,212 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <RelativeLayout
+
+ <cx.ring.views.BoundedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical">
+ android:layout_gravity="center_horizontal"
+ app:bounded_width="360dp">
- <TextView
- android:id="@+id/headerText"
- style="@style/Subheader"
- android:layout_width="match_parent"
- android:layout_height="48dp"
- android:layout_alignParentTop="true"
- android:gravity="center_vertical"
- android:paddingEnd="72dp"
- android:paddingStart="72dp"
- android:text="@string/normal_devices_titles" />
-
- <FrameLayout
+ <android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_below="@id/headerText"
- android:background="@color/white"
- android:elevation="2dp">
+ android:layout_marginBottom="16dp"
+ android:layout_marginEnd="8dp"
+ android:layout_marginStart="8dp"
+ android:layout_marginTop="16dp">
- <ListView
- android:id="@+id/device_list"
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="match_parent"
+ android:orientation="vertical">
- <TextView
- android:id="@+id/empty_account_list"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:gravity="center"
- android:text="@string/empty_account_list"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textColor="@color/text_color_secondary"
- android:visibility="gone" />
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
- </FrameLayout>
+ <TextView
+ android:id="@+id/account_alias_txt"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingBottom="8dp"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp"
+ android:paddingTop="24dp"
+ android:text="@string/ring_account"
+ android:textAppearance="@style/Base.TextAppearance.AppCompat.Large" />
- </RelativeLayout>
+ <ImageButton
+ android:id="@+id/account_edit_btn"
+ style="@style/Widget.AppCompat.Button.Borderless"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:background="?selectableItemBackgroundBorderless"
+ app:srcCompat="@drawable/ic_settings_black_24dp" />
+
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/account_id_txt"
+ style="@style/Subheader"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ellipsize="middle"
+ android:gravity="center_vertical"
+ android:lines="1"
+ android:paddingBottom="8dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="16dp"
+ android:paddingTop="4dp"
+ android:textIsSelectable="false"
+ tools:text="ring:8F29045378ACA68F2ACA2346078ACA68F2ACA290" />
+
+ <LinearLayout
+ android:id="@+id/group_register_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="16dp"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/register_name_help_txt"
+ style="@style/Subheader"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:paddingBottom="8dp"
+ android:paddingTop="8dp"
+ android:text="@string/no_registered_name_for_account" />
+
+ <Button
+ android:id="@+id/register_name_btn"
+ style="@style/Widget.AppCompat.Button.Colored"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp"
+ android:text="@string/register_name" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/group_registering_name"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="16dp"
+ android:orientation="horizontal"
+ android:visibility="gone">
+
+ <TextView
+ android:id="@+id/textView"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/trying_to_register_name" />
+
+ <ProgressBar
+ android:id="@+id/progressBar"
+ style="?android:attr/progressBarStyleSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/group_registered_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="16dp"
+ android:orientation="horizontal"
+ android:visibility="gone">
+
+ <TextView
+ android:id="@+id/registred_name_help_txt"
+ style="@style/Subheader"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:paddingBottom="16dp"
+ android:paddingEnd="16dp"
+ android:paddingRight="16dp"
+ android:paddingTop="4dp"
+ android:text="@string/registered_username" />
+
+ <TextView
+ android:id="@+id/registered_name_txt"
+ style="@style/Base.TextAppearance.AppCompat.Title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="16dp"
+ android:paddingEnd="8dp"
+ android:paddingLeft="16dp"
+ android:paddingRight="8dp"
+ android:paddingStart="16dp"
+ android:paddingTop="4dp"
+ tools:text="Wagaf"
+ android:textAlignment="viewStart"
+ android:layout_gravity="start"/>
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/headerText"
+ style="@style/Subheader"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:paddingBottom="8dp"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp"
+ android:paddingTop="8dp"
+ android:text="@string/normal_devices_titles" />
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dip"
+ android:background="?android:attr/listDivider" />
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <ListView
+ android:id="@+id/device_list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:divider="#CCCCCC"
+ android:dividerHeight="1dp"
+ android:footerDividersEnabled="true"
+ android:headerDividersEnabled="true" />
+
+ <TextView
+ android:id="@+id/empty_account_list"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:text="@string/empty_account_list"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/text_color_secondary"
+ android:visibility="gone" />
+
+ </FrameLayout>
+
+ </LinearLayout>
+ </android.support.v7.widget.CardView>
+ </cx.ring.views.BoundedScrollView>
<include
layout="@layout/add_new_device_layout"
- android:layout_gravity="bottom"
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
-</FrameLayout>
\ No newline at end of file
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom" />
+</FrameLayout>
diff --git a/ring-android/app/src/main/res/layout/frag_register_name.xml b/ring-android/app/src/main/res/layout/frag_register_name.xml
new file mode 100644
index 0000000..f03ce48
--- /dev/null
+++ b/ring-android/app/src/main/res/layout/frag_register_name.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:paddingTop="16dp">
+
+ <android.support.design.widget.TextInputLayout
+ android:id="@+id/ring_username_txt_box"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginLeft="12dp"
+ android:layout_marginRight="12dp">
+
+ <android.support.design.widget.TextInputEditText
+ android:id="@+id/ring_username"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/prompt_new_username"
+ android:imeOptions="actionNext"
+ android:inputType="text"
+ android:lines="1"
+ android:maxLines="1" />
+ </android.support.design.widget.TextInputLayout>
+
+ <android.support.design.widget.TextInputLayout
+ android:id="@+id/ring_password_txt_box"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:layout_marginLeft="12dp"
+ android:layout_marginRight="12dp">
+
+ <android.support.design.widget.TextInputEditText
+ android:id="@+id/ring_password_txt"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/account_new_device_password"
+ android:imeOptions="actionDone"
+ android:inputType="textPassword"
+ android:lines="1"
+ android:maxLines="1" />
+ </android.support.design.widget.TextInputLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/item_device.xml b/ring-android/app/src/main/res/layout/item_device.xml
index e340b3d..59e0dc3 100644
--- a/ring-android/app/src/main/res/layout/item_device.xml
+++ b/ring-android/app/src/main/res/layout/item_device.xml
@@ -25,7 +25,6 @@
android:id="@+id/icon_device"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
app:srcCompat="@drawable/ic_desktop_windows_black_24dp" />
@@ -34,10 +33,8 @@
android:id="@+id/txt_device_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
- android:layout_marginLeft="56dp"
android:layout_marginStart="56dp"
android:text="8E24CCF4"
android:textAppearance="@style/ListPrimary" />
@@ -48,10 +45,8 @@
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/txt_device_label"
android:layout_alignParentEnd="true"
- android:layout_alignParentRight="true"
- android:layout_marginLeft="24dp"
android:layout_marginStart="24dp"
- android:layout_toRightOf="@+id/txt_device_label"
+ android:layout_toEndOf="@+id/txt_device_label"
android:ellipsize="middle"
android:maxLines="1"
android:text="e3806a4963993ed1e8adc5c0ed9809c354dfc872"
diff --git a/ring-android/app/src/main/res/values-w820dp/dimens.xml b/ring-android/app/src/main/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000..63fc816
--- /dev/null
+++ b/ring-android/app/src/main/res/values-w820dp/dimens.xml
@@ -0,0 +1,6 @@
+<resources>
+ <!-- Example customization of dimensions originally defined in res/values/dimens.xml
+ (such as screen margins) for screens with more than 820dp of available width. This
+ would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
+ <dimen name="activity_horizontal_margin">64dp</dimen>
+</resources>
diff --git a/ring-android/app/src/main/res/values/colors.xml b/ring-android/app/src/main/res/values/colors.xml
index 3f90077..c2e8bcf 100644
--- a/ring-android/app/src/main/res/values/colors.xml
+++ b/ring-android/app/src/main/res/values/colors.xml
@@ -17,7 +17,7 @@
<color name="sfl_light_blue">#006f82</color>
<color name="lighter_gray">#ddd</color>
- <color name="darker_gray">#aaa</color>
+ <color name="darker_gray">#aaaaaa</color>
<color name="light">#eee</color>
<color name="text_shadow">#054b55</color>
diff --git a/ring-android/app/src/main/res/values/strings.xml b/ring-android/app/src/main/res/values/strings.xml
index 76f4a73..e6c6059 100644
--- a/ring-android/app/src/main/res/values/strings.xml
+++ b/ring-android/app/src/main/res/values/strings.xml
@@ -170,6 +170,14 @@
<string name="add_call_contact_number_to_contacts">Add %1$s ?</string>
<string name="prompt_new_password">New password</string>
<string name="prompt_new_password_repeat">Repeat new password</string>
+ <string name="account_create_title">Create a Ring account</string>
+ <string name="help_username_register">Choose a Ring username that will be registered in the public blockchain-based registry.</string>
+ <string name="prompt_new_username">Enter new username</string>
+ <string name="help_password_choose">Choose a strong password you will remember to protect your Ring account.</string>
+ <string name="btn_use_existing_account">Use an existing Ring account instead</string>
+ <string name="btn_create_account">Create new account instead</string>
+ <string name="help_password_enter">Enter your main Ring account password</string>
+ <string name="help_pin_enter">Enter the PIN from another configured Ring account. Use the \"export account on Ring\" feature to obtain a PIN.</string>
<string name="account_device_updated_message">You have successfully updated your Ring account.</string>
diff --git a/ring-android/app/src/main/res/values/strings_account.xml b/ring-android/app/src/main/res/values/strings_account.xml
index c5136f2..1d816ec 100644
--- a/ring-android/app/src/main/res/values/strings_account.xml
+++ b/ring-android/app/src/main/res/values/strings_account.xml
@@ -25,7 +25,7 @@
<string name="prompt_hostname">Hostname</string>
<string name="prompt_username">Username</string>
<string name="prompt_password">Password</string>
- <string name="action_create">Add account</string>
+ <string name="action_create">Create account</string>
<string name="action_create_short">Register</string>
<string name="error_field_required">This field is required</string>
<string name="dialog_wait_create">Adding account</string>
@@ -146,7 +146,7 @@
<string name="account_restore_decryption_password">Decryption password</string>
<string name="account_new_device">Add new device</string>
<string name="account_new_device_message">Unlock Ring account to associate new device.</string>
- <string name="account_new_device_password">Enter main account password</string>
+ <string name="account_new_device_password">Enter main password to unlock account</string>
<string name="restore_dialog_title">Restoring</string>
<string name="restore_backup_wait">Please wait…</string>
@@ -190,6 +190,7 @@
<string name="account_device_updated_title">Account device updated</string>
<string name="account_link_button">Link this device to an account</string>
+ <string name="account_import_title">Link to an existing account</string>
<string name="account_link_prompt_password">Enter your password</string>
<string name="account_link_prompt_pin">Enter PIN</string>
<string name="account_wizard_title">Ring account</string>
@@ -201,4 +202,20 @@
<string name="account_start_export_button">Generate Pin</string>
<string name="account_end_export_button">close</string>
<string name="account_end_export_infos">Your Pin is:\n\n%%\n\nTo complete the process, you need to open Ring on the new device. Create a new account with \"Link this device to an account\". Your pin is valid for 10 minutes.</string>
+
+ <!-- Name registration -->
+ <string name="register_name_wrong_password">Can\'t register name: wrong account password.</string>
+ <string name="register_name_invalid">Can\'t register name: invalid name.</string>
+ <string name="register_name_already_taken">Can\'t register name: name already taken.</string>
+ <string name="register_name_network_error">Can\'t register name: network or server error.</string>
+ <string name="error_username_empty">Enter a username</string>
+ <string name="no_registered_name_for_account">No registered name found for this account</string>
+ <string name="register_name">Register name</string>
+ <string name="trying_to_register_name">Trying to register name</string>
+ <string name="registered_username">Registered username</string>
+ <string name="register_username">Register a public Ring username that will be stored in the public blockchain registry</string>
+ <string name="username_already_taken">Username already taken</string>
+ <string name="invalid_username">Invalid username</string>
+ <string name="looking_for_username_availability">Looking for username availability ...</string>
+
</resources>