Skip to content
Snippets Groups Projects
Commit 99f5cade authored by Thibault Wittemberg's avatar Thibault Wittemberg Committed by gerrit2
Browse files

blockchain: search in toolbar

Search adapts to the type of selected account:
- SIP account, then no specific lookup
- Ring account, lookup through the blockchain. If the query is
a RingID pattern then the search is done with lookupAdress (lookupName otherwise)

Lookup/Search delay between 2 inputs is now of 2s

Change-Id: If9d9c3374d952539ad88607e1be490b74298d47c
Tuleap: #1157
parent ef28a315
Branches
Tags
No related merge requests found
......@@ -475,6 +475,10 @@ public class HomeActivity extends AppCompatActivity implements LocalService.Call
if (fContent == null) {
fContent = new SmartListFragment();
fragmentManager.beginTransaction().replace(R.id.main_frame, fContent, HOME_TAG).addToBackStack(HOME_TAG).commit();
if (fMenuHead != null) {
fMenuHead.registerAccountSelectionListener((MenuHeaderView.MenuHeaderAccountSelectionListener) fContent);
}
} else if (fContent instanceof Refreshable) {
fragmentManager.beginTransaction().replace(R.id.main_frame, fContent).addToBackStack(HOME_TAG).commit();
((Refreshable) fContent).refresh();
......
......@@ -83,7 +83,7 @@ public class ShareFragment extends Fragment implements MenuHeaderView.MenuHeader
}
private void updateView() {
if (!TextUtils.isEmpty(mUriToShow)) {
if (!TextUtils.isEmpty(mUriToShow) && mQrImage != null) {
Bitmap qrBitmap = QRCodeUtils.encodeStringAsQrBitmap(mUriToShow, mQrImage.getMeasuredWidth());
mQrImage.setImageBitmap(qrBitmap);
}
......
......@@ -59,6 +59,8 @@ import android.widget.Toast;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
import java.lang.ref.WeakReference;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
......@@ -70,14 +72,19 @@ import cx.ring.client.QRCodeScannerActivity;
import cx.ring.model.CallContact;
import cx.ring.model.Conference;
import cx.ring.model.Conversation;
import cx.ring.model.account.Account;
import cx.ring.service.LocalService;
import cx.ring.utils.BlockchainInputHandler;
import cx.ring.utils.ClipboardHelper;
import cx.ring.views.MenuHeaderView;
public class SmartListFragment extends Fragment implements SearchView.OnQueryTextListener,
HomeActivity.Refreshable,
SmartListAdapter.SmartListAdapterCallback,
Conversation.ConversationActionCallback,
ClipboardHelper.ClipboardHelperCallback {
ClipboardHelper.ClipboardHelperCallback,
LocalService.NameLookupCallback,
MenuHeaderView.MenuHeaderAccountSelectionListener {
private static final String TAG = SmartListFragment.class.getSimpleName();
private static final int USER_INPUT_DELAY = 300;
......@@ -85,6 +92,8 @@ public class SmartListFragment extends Fragment implements SearchView.OnQueryTex
private LocalService.Callbacks mCallbacks = LocalService.DUMMY_CALLBACKS;
private SmartListAdapter mSmartListAdapter;
private BlockchainInputHandler mBlockchainInputHandler;
private Account mCurrentAccount;
@BindView(R.id.newconv_fab)
FloatingActionButton mFloatingActionButton;
......@@ -286,10 +295,29 @@ public class SmartListFragment extends Fragment implements SearchView.OnQueryTex
if (TextUtils.isEmpty(query)) {
mNewContact.setVisibility(View.GONE);
} else {
if (mCurrentAccount == null) {
return false;
}
if (mCurrentAccount.isSip()) {
// sip search
((TextView) mNewContact.findViewById(R.id.display_name)).setText(query);
CallContact contact = CallContact.buildUnknown(query);
mNewContact.setTag(contact);
mNewContact.setVisibility(View.VISIBLE);
} else {
// Ring search
if (mBlockchainInputHandler == null) {
mBlockchainInputHandler = new BlockchainInputHandler(new WeakReference<>(mCallbacks.getService()), this);
}
// searching for a ringId or a blockchained username
if (!mBlockchainInputHandler.isAlive()) {
mBlockchainInputHandler = new BlockchainInputHandler(new WeakReference<>(mCallbacks.getService()), this);
}
mBlockchainInputHandler.enqueueNextLookup(query);
}
mUserInputHandler.removeCallbacksAndMessages(null);
......@@ -306,6 +334,7 @@ public class SmartListFragment extends Fragment implements SearchView.OnQueryTex
}
}
}, USER_INPUT_DELAY);
}
return true;
}
......@@ -637,4 +666,27 @@ public class SmartListFragment extends Fragment implements SearchView.OnQueryTex
mErrorImageView.setImageResource(imageResId);
}
}
@Override
public void onFound(String name, String address) {
((TextView) mNewContact.findViewById(R.id.display_name)).setText(name);
CallContact contact = CallContact.buildUnknown(name);
mNewContact.setTag(contact);
mNewContact.setVisibility(View.VISIBLE);
}
@Override
public void onInvalidName(String name) {
mNewContact.setVisibility(View.GONE);
}
@Override
public void onError(String name, String address) {
mNewContact.setVisibility(View.GONE);
}
@Override
public void accountSelected(Account account) {
mCurrentAccount = account;
}
}
......@@ -290,7 +290,7 @@ public class LocalService extends Service implements SharedPreferences.OnSharedP
currentAddressLookup.put(address, cbs);
}
cbs.add(cb);
mService.lookupAddress(account, null, address);
mService.lookupAddress(account == null ? "" : account, "", address);
} catch (RemoteException e) {
cb.onError(null, address);
}
......
/*
* 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.util.Log;
import java.lang.ref.WeakReference;
import cx.ring.service.LocalService;
public class BlockchainInputHandler extends Thread {
private static final String TAG = BlockchainInputHandler.class.getName();
private static final String RINGID_PATTERN = "^[a-f0-9]{40}$";
private static final int WAIT_DELAY= 2000;
private static final int KILL_DELAY = 6000;
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();
}
}
private boolean isRingId(String text) {
return text.matches(RINGID_PATTERN);
}
@Override
public void run() {
while (mIsWaitingForInputs) {
try {
Thread.sleep(100);
long timeFromLastEnqueuedInput = System.currentTimeMillis() - mLastEnqueuedInputTimeStamp;
if (timeFromLastEnqueuedInput >= KILL_DELAY) {
// 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 >= WAIT_DELAY) {
// trigger the blockchain lookup
final LocalService localService = mLocalService.get();
if (isRingId(mTextToLookup)) {
localService.lookupAddress("", mTextToLookup, mLookupCallback);
} else {
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
......@@ -18,7 +18,6 @@
*/
package cx.ring.utils;
import android.support.annotation.NonNull;
import android.support.design.widget.TextInputLayout;
import android.text.Editable;
import android.text.TextUtils;
......@@ -130,67 +129,10 @@ public class BlockchainTextWatcher implements TextWatcher, LocalService.NameLook
mInputLayout.get().setError(mLookinForAvailability);
}
if (mBlockchainInputHandler.isAlive()) {
mBlockchainInputHandler.enqueueNextLookup(name);
} else {
if (!mBlockchainInputHandler.isAlive()) {
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);
}
}
}
mBlockchainInputHandler.enqueueNextLookup(name);
}
}
\ No newline at end of file
......@@ -135,6 +135,7 @@ public class MenuHeaderView extends FrameLayout {
public void registerAccountSelectionListener(MenuHeaderAccountSelectionListener listener) {
mListeners.add(new WeakReference<>(listener));
listener.accountSelected(getSelectedAccount());
}
public void updateUserView() {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment