Skip to content

Instantly share code, notes, and snippets.

@loretoparisi
Created June 13, 2012 14:47
Show Gist options
  • Save loretoparisi/2924535 to your computer and use it in GitHub Desktop.
Save loretoparisi/2924535 to your computer and use it in GitHub Desktop.
Android - Gracenote Implementation
package com.designfuture.music.ui.fragment;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.Vibrator;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.TextView;
import com.designfuture.framework.util.BitmapUtils;
import com.designfuture.framework.util.ConnectivityHelper;
import com.designfuture.framework.util.LogHelper;
import com.designfuture.framework.util.MediaHelper;
import com.designfuture.framework.util.NotifyingAsyncQueryHandler;
import com.designfuture.framework.util.StorageHelper;
import com.designfuture.framework.util.UIUtils;
import com.designfuture.framework.util.sensor.PCMConfig;
import com.designfuture.framework.util.sensor.PCMrecorderShort;
import com.designfuture.framework.util.sensor.PCMrecorderShort.PCMrecorderListener;
import com.designfuture.framework.widget.DiscProgressView;
import com.designfuture.framework.widget.DiscProgressView.FixedTimeAnimationListener;
import com.designfuture.music.IMediaPlaybackService;
import com.designfuture.music.MediaPlaybackService;
import com.designfuture.music.MusicUtils;
import com.designfuture.music.MusicUtils.ServiceToken;
import com.designfuture.music.api.config.Constants;
import com.designfuture.music.api.config.StatusCode;
import com.designfuture.music.global.Global;
import com.designfuture.music.global.MXMConfig;
import com.designfuture.music.global.MXMSettingHolder;
import com.designfuture.music.model.MXMFingerprint;
import com.designfuture.music.model.MXMTrack;
import com.designfuture.music.model.MXMUniqueId;
import com.designfuture.music.model.ModelTrack;
import com.designfuture.music.provider.MusicContract.Tracks;
import com.designfuture.music.provider.MusicDatabase.Tables;
import com.designfuture.music.ui.adapter.SearchPagerChild;
import com.designfuture.music.ui.fragment.mxm.MXMFragment;
import com.designfuture.music.ui.fragment.plbl.FingerprintResultFragment;
import com.designfuture.music.ui.phone.BLBLActivity;
import com.designfuture.music.ui.phone.MusicSinglePaneActivity;
import com.designfuture.music.util.AnalyticsHelper;
import com.designfuture.music.util.MusicHelper;
import com.designfuture.music.util.holder.MXMFragmentViewHolder;
import com.gracenote.mmid.MobileSDK.GNConfig;
import com.gracenote.mmid.MobileSDK.GNOperationStatusChanged;
import com.gracenote.mmid.MobileSDK.GNOperations;
import com.gracenote.mmid.MobileSDK.GNSampleBuffer;
import com.gracenote.mmid.MobileSDK.GNSearchResponse;
import com.gracenote.mmid.MobileSDK.GNSearchResult;
import com.gracenote.mmid.MobileSDK.GNSearchResultReady;
import com.gracenote.mmid.MobileSDK.GNStatus;
import com.gracenote.mmid.MobileSDK.GNStatusEnum;
import com.musixmatch.android.lyrify.R;
public class FingerprintFragment extends MXMFragment implements
NotifyingAsyncQueryHandler.AsyncQueryListener, SearchPagerChild {
public static final String PARAM_NAME_FROM_MUSICID = "com.designfuture.music.FROM_MUSICID";
private static final String TAG = "FingerprintFragment";
public static final String FINGERPRINT_FRAGMENT_PARAM_FROM_WIDGET = "com.musixmatch.android.lyrify.ui.fragment.from_widget";
public static final String FINGERPRINT_FRAGMENT_PARAM_AUTOSTART = "com.musixmatch.android.lyrify.ui.fragment.autostart";
private static int VOICE_STRING_REQUEST = 17;
private ViewHolder mHolder;
private GNConfig config;
private PCMrecorderShort recorder;
private GNSearchResult latestSearchResult;
private RecognizePCMStreamTask lastUsedTask;
private NotifyingAsyncQueryHandler mHandler;
private boolean mAutoStart = false;
long start;
private ServiceToken mToken;
private IMediaPlaybackService mService;
private long mEndLastRecordTime;
private PowerManager.WakeLock mWakeLock;
protected byte[] recordedBuffer;
//UpdateModelTask modelTask = null;
//BackgroundUpdateDataTask bgTask = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new NotifyingAsyncQueryHandler(getActivity().getContentResolver(), this);
config = Global.getGracenoteConfig();
if ( config == null ) {
initGracenoteConfig( Global.isDebuggable() );
}
String s = config.getProperty("version");
LogHelper.i(TAG, "version: " + s);
PowerManager pm = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "My Tag");
//Dato che nella onSelected del pager non viene chiamato la prima volta devo farlo io
AnalyticsHelper.logEvent(getString(R.string.flurry_musicid_click_musicid));
}
private void initGracenoteConfig( boolean isDebugMode ) {
try {
config = GNConfig.init( Global.getGracenoteClientID(isDebugMode),
getActivity().getApplicationContext());
// Set configuration properties
config.setProperty("debugEnabled", (isDebugMode)?"1":"0");
config.setProperty("content.genre", "0");
config.setProperty("content.mood", "0");
config.setProperty("content.tempo", "0");
config.setProperty("content.origin", "0");
config.setProperty("content.era", "0");
config.setProperty("content.artistType", "0");
config.setProperty("content.contributor.biography", "0");
config.setProperty("content.review", "0");
config.setProperty("content.contributor.images", "0");
config.setProperty("content.coverArt.genreCoverArt", "1");
config.setProperty("content.coverArt", "1");
config.setProperty("content.coverArt.sizePreference", "SMALL");
} catch (Exception e) {
LogHelper.i(TAG, "flurry_musicid_gnconfigfail");
AnalyticsHelper.logEvent( getActivity().getString(R.string.flurry_musicid_gnconfigfail) );
LogHelper.e("GracenoteMusicID", e.getMessage());
}
}
@Override
protected MXMFragmentViewHolder<? extends MXMFragment> onViewHolderInit(
LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return mHolder = new ViewHolder((ViewGroup) inflater.inflate(R.layout.fragment_search, null), this);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if ( isMicrophoneAvailable() ) {
mHolder.showContent(true);
} else {
mHolder.onNoMicrophone();
}
recorder = new PCMrecorderShort(getActivity(), Global.isDebuggable());
}
private boolean isMicrophoneAvailable() {
Boolean existMic = MediaHelper.getMicrophoneExists(getActivity());
if ( existMic != null && existMic ) {
//LogHelper.i(TAG, "isMicrophoneAvailable: MediaHelper.getMicrophoneExists(getActivity()) TRUE");
return true;
} else {
//if it's null it means that the user OS is before FROYO, check in another way
//if it's null it means that the device hasn't an internal mic so we've to check for
//an external one
boolean isAvailable = MediaHelper.getMicrophoneAvailable(getActivity());
//LogHelper.i(TAG, "isMicrophoneAvailable: MediaHelper.getMicrophoneAvailable(getActivity()): " + isAvailable);
//return MediaHelper.getTTSAvailable(getActivity());
return isAvailable;
}
}
@Override
public void onStart() {
super.onStart();
mToken = MusicUtils.bindToService(getActivity(), osc);
}
@Override
public void onResume() {
super.onResume();
mAutoStart = getActivity().getIntent().getBooleanExtra(FINGERPRINT_FRAGMENT_PARAM_AUTOSTART, false);
//prima di tutto si leva quasto dall'intent
if(getActivity().getIntent().getBooleanExtra(FINGERPRINT_FRAGMENT_PARAM_FROM_WIDGET, false)){
//significa che viene dalla widget quindi si manda evento flurry
AnalyticsHelper.logEvent(getString(R.string.flurry_musicid_widget));
}
//Resetto il flag in modo che non rifaccia l'autoStart
getActivity().getIntent().putExtra(FINGERPRINT_FRAGMENT_PARAM_AUTOSTART, false);
getActivity().getIntent().putExtra(FINGERPRINT_FRAGMENT_PARAM_FROM_WIDGET, false);
if ( config == null ) {
updateStatus( getActivity().getString(R.string.fingerprint_config_err) , true);
//TODO: aprire il search
getActivity().startSearch("Type songs words here",true , null, false);
if(UIUtils.isTablet(getActivity()))
UIUtils.enableRotation(getActivity());
if(mWakeLock.isHeld())
mWakeLock.release();
mHolder.circle.setClickable(false);
mHolder.circle.setCenterIconDrawable(mHolder.center_warning);
} else {
if (!ConnectivityHelper.isOnline(getActivity())) {
mHolder.circle.setClickable(true);
mHolder.circle.setOnClickListener(startAnimationAndRecording);
mHolder.circle.setCenterIconDrawable(mHolder.center_warning);
mHolder.statusText.setText( MXMConfig.getRandomString(MXMConfig.CONFIG_KEYS.ERROR_NO_CONNECTION) );
} else {
mHolder.circle.setClickable(true);
if(mAutoStart){
mHolder.circle.startFixedTimeAnimation(500, 0, mPreRecordAnimationListener);
//mHolder.circle.setOnClickListener(stopAnimationAndRecording);
mHolder.statusText.setText("");
mAutoStart = !mAutoStart;
} else {
mHolder.statusText.setText( MXMConfig.getRandomString(MXMConfig.CONFIG_KEYS.FINGER_STRING_START) );
mHolder.circle.setOnClickListener(startAnimationAndRecording);
mHolder.statusText.setOnClickListener(startAnimationAndRecording);
mHolder.circle.setCenterIconDrawable(mHolder.center_tap_to_start);
}
}
}
}
public void onPause() {
super.onPause();
if(mHolder.circle.isRunning() || recorder.isRunning() || (lastUsedTask != null && lastUsedTask.isSearching()))
stopAnimationAndRecording();
if( mWakeLock.isHeld() )
mWakeLock.release();
}
@Override
public void onStop() {
super.onStop();
MusicUtils.unbindFromService(mToken);
mService = null;
}
@Override
public void onDestroyView() {
//if (modelTask != null)
// modelTask.cancel(true);
/*if (bgTask != null)
bgTask.cancel(true);*/
super.onDestroyView();
}
@Override
public void onDestroy() {
if(UIUtils.isTablet(getActivity()) && !(Boolean)Global.getSettingsHolder().getSetting(MXMSettingHolder.PORTRAIT_LOCK))
UIUtils.enableRotation( getActivity() );
super.onDestroy();
}
/**
* Show current status of audio fingerprinting process.
*/
private void updateStatus(String status, boolean clearStatus) {
mHolder.statusText.setVisibility(View.VISIBLE);
if (clearStatus) {
mHolder.statusText.setText(status);
} else {
mHolder.statusText.setText((String) mHolder.statusText.getText()
+ "\n" + status);
}
}
private ServiceConnection osc = new ServiceConnection() {
public void onServiceConnected(ComponentName classname, IBinder obj) {
mService = IMediaPlaybackService.Stub.asInterface(obj);
}
public void onServiceDisconnected(ComponentName classname) {
mService = null;
}
};
private FixedTimeAnimationListener mPreRecordAnimationListener = new FixedTimeAnimationListener() {
@Override
public void onStep() {
}
@Override
public void onStart() {
if(UIUtils.isTablet(getActivity()) && !(Boolean)Global.getSettingsHolder().getSetting(MXMSettingHolder.PORTRAIT_LOCK))
UIUtils.disableRotation(getActivity());
LogHelper.i(TAG, "flurry_musicid_start");
AnalyticsHelper.logEvent(getString(R.string.flurry_musicid_start));
if(!mWakeLock.isHeld())
mWakeLock.acquire();
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
//TODO abbiamo eliminato l'animazione
mHolder.circle.setCenterIconDrawable(mHolder.center_listening);
mHolder.statusText.setOnClickListener(null);
mHolder.statusText.setText("");
}
});
}
@Override
public void onInterrupt() {
if(mWakeLock.isHeld())
mWakeLock.release();
if(UIUtils.isTablet(getActivity()) && !(Boolean)Global.getSettingsHolder().getSetting(MXMSettingHolder.PORTRAIT_LOCK))
UIUtils.enableRotation(getActivity());
updateMusicStatus(true);
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mHolder.circle.setOnClickListener(startAnimationAndRecording);
mHolder.circle.setCenterIconDrawable(mHolder.center_tap_to_start);
updateStatus(MXMConfig.getRandomString(MXMConfig.CONFIG_KEYS.FINGER_STRING_INTERRUPTED), true);
}
});
}
@Override
public void onEnd() {
if(getActivity() == null)
return;
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mHolder.circle.setClickable(false);
try {
recorder.startRecording(7, recorderListener);
mHolder.circle.startFixedTimeAnimation(0, 7000, animationListener);
} catch ( IllegalArgumentException e ) {
//Qui e' principalmente dovuto al fatto che non c'e' il microfono
showError( getActivity().getString(R.string.error_no_microphone) );
}
}
});
}
};
private FixedTimeAnimationListener animationListener = new FixedTimeAnimationListener() {
double max;
double current_ratio;
double goal_ratio;
double ratio_change;
@Override
public void onStep() {
int progress = mHolder.circle.getProgress();
progress = (progress > 98 ? 100 : ((int)( progress / 10))*10);
mHolder.statusText.setText(new StringBuilder( MXMConfig.getRandomString(MXMConfig.CONFIG_KEYS.FINGER_STRING_LISTENING) ).append(" ").append( progress ).append('%'));
double temp_vol = recorder.getAmplitude();
// se � stato registrato un valore si salva e si imposta il ratio da
// raggiungere
if (temp_vol != 0) {
max = recorder.getMaxVolEverRecoded();
goal_ratio = temp_vol / max;
}
// si calcola il ratio change in base alla distanza fra current e
// goal ratio
ratio_change = (goal_ratio - current_ratio) / 2;
// si applica il cambiamento
current_ratio += ratio_change;
// si aggiunge noise al ratio per dare l'effetto di realt�, in linea
// con il suono limitandolo ovviamente ad 1
double ratio = current_ratio + 0.01 * (2 - Math.random() * 4);
mHolder.circle.setNegativeProgressRatio(ratio);
}
@Override
public void onStart() {
current_ratio = 0;
ratio_change = 0;
recorder.getAmplitude();
max = recorder.getMaxVolEverRecoded();
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mHolder.statusText.setText(new StringBuilder( MXMConfig.getRandomString(MXMConfig.CONFIG_KEYS.FINGER_STRING_LISTENING) ).append(" ").append(0).append('%'));
}
});
}
@Override
public void onEnd() {
recorder.pushMinMaxUpdate();
if(getActivity() == null)
return;
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// init dots animation
mHolder.circle.startCenterIconAnimation(mHolder.center_matching);
mHolder.center_matching.start();
}
});
}
@Override
public void onInterrupt() {
mHolder.onInterrupt();
}
};
private PCMrecorderListener recorderListener = new PCMrecorderListener() {
@Override
public void onStartRecording() {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mHolder.circle.invalidate();
//mHolder.circle.setOnClickListener(stopAnimationAndRecording);
mHolder.circle.setClickable(true);
}
});
}
@Override
public void onEndRecord(byte[] buff) {
if(getActivity() == null)
return;
recordedBuffer = buff;
updateMusicStatus(true);
if ( Global.isDebuggable() ) {
}
//quando finisce il recording vibra per 0.2s
Vibrator vibrator_manager = (Vibrator) getActivity().getSystemService(Context.VIBRATOR_SERVICE);
vibrator_manager.vibrate(200);
mEndLastRecordTime = System.currentTimeMillis();
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mHolder.circle.setClickable(false);
mHolder.circle.setOnClickListener(null);
lastUsedTask = new RecognizePCMStreamTask();
lastUsedTask.recognizePCMStream();
}
});
}
@Override
public void onInterrupt() {
mHolder.onInterrupt();
updateMusicStatus(true);
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
//BUGFIX ha dato null pointer su: mHolder.circle.setOnClickListener(startAnimationAndRecording);
if(mHolder == null || mHolder.circle == null)
return;
mHolder.circle.setOnClickListener(startAnimationAndRecording);
mHolder.circle.setCenterIconDrawable(mHolder.center_tap_to_start);
updateStatus(MXMConfig.getRandomString(MXMConfig.CONFIG_KEYS.FINGER_STRING_INTERRUPTED), true);
}
});
}
};
private OnClickListener stopAnimationAndRecording = new OnClickListener() {
@Override
public void onClick(View v) {
stopAnimationAndRecording();
}
};
private OnClickListener startAnimationAndRecording = new OnClickListener() {
@Override
public void onClick(View v) {
if (!ConnectivityHelper.isOnline(getActivity()))
return;
mHolder.statusText.setClickable(false);
updateMusicStatus(false);
//mHolder.circle.setOnClickListener(stopAnimationAndRecording);
mHolder.circle.startFixedTimeAnimation(0, 0, mPreRecordAnimationListener);
}
};
private boolean mMusicPaused = false;
/**
* start/stop music
*
* @param play
*/
private void updateMusicStatus(boolean play){
if( ! (Boolean) Global.getSettingsHolder().getSetting(MXMSettingHolder.PAUSE_MUSIC_ON_RECORD) )
return;
if(mService == null)
return;
try {
if(mService.isPlaying() && !play) {
mMusicPaused = true;
mService.pause();
}
else if(!mService.isPlaying() && play && mMusicPaused) {
mService.play();
mMusicPaused = false;
}
} catch (RemoteException e) {
//e.printStackTrace();
}
final ComponentName serviceName = new ComponentName(getActivity(), MediaPlaybackService.class);
Intent intent = new Intent(MediaPlaybackService.TOGGLEPAUSE_ACTION);
intent.setComponent(serviceName);
}
/**
* Fingerprint sample.pcm files stored in /res/raw/. Then, create a
* fingerprint and search for song metadata.
*/
public class RecognizePCMStreamTask implements GNSearchResultReady,
GNOperationStatusChanged {
private boolean searching = false;
public boolean isSearching(){
return searching;
}
private GNSampleBuffer loadSamplePCM() {
// recoderd_buff
if (recordedBuffer == null)
return null;
PCMConfig config = recorder.getLastConfig();
return new GNSampleBuffer(recordedBuffer, config.getBytePerSample(), config.getChannelCount(), (int) config.getSampleRate());
}
public void recognizePCMStream() {
updateStatus(MXMConfig.getRandomString(MXMConfig.CONFIG_KEYS.FINGER_STRING_MATCHING), true);
LogHelper.i(TAG, "flurry_musicid_gnstart");
AnalyticsHelper.logEvent(getString(R.string.flurry_musicid_gnstart));
latestSearchResult = null;
GNSampleBuffer samplePCMBuffer = loadSamplePCM();
searching = true;
GNOperations.recognizeMIDStreamFromPcm(this, config, samplePCMBuffer);
}
/**
* When the fingeprint/lookup operation is finished, this method will be
* invoked in the UI thread to report results.
*/
public void GNResultReady(GNSearchResult result) {
searching = false;
mHolder.center_matching.stop();
//ERRORE IO CONTETTANDO GN
if (result == null || result.isFailure()) {
// An error occurred so display the error to the user.
//String msg = String.format("[%d] %s", result.getErrCode(), result.getErrMessage());
//updateStatus(MXMConfig.getRandomString(MXMConfig.CONFIG_KEYS.ERROR_GN_NO_MATCH), false);
//Log.i("TUMA", "errCode: " + result.getErrCode());
//Log.i("TUMA", "errMessage: " + result.getErrMessage());
//updateStatus( MXMConfig.getRandomString(MXMConfig.CONFIG_KEYS.ERROR_GN_NO_MATCH2) , true);
//BUG FIX https://market.android.com/publish/Home#CrashDetailsPlace:p=com.musixmatch.android.lyrify&ex=java.lang.NullPointerException&c=com.designfuture.music.ui.fragment.FingerprintFragment$RecognizePCMStreamTask&f=FingerprintFragment.java&m=GNResultReady&em
updateStatus( getActivity().getString(R.string.fingerprint_server_err, result == null ? "9999" : result.getErrCode()) , true);
//viene aperto il search in caso di errore del server
getActivity().startSearch("Type songs words here",true , null, false);
if(UIUtils.isTablet(getActivity()) && !(Boolean)Global.getSettingsHolder().getSetting(MXMSettingHolder.PORTRAIT_LOCK))
UIUtils.enableRotation(getActivity());
if(mWakeLock.isHeld())
mWakeLock.release();
mHolder.circle.setCenterIconDrawable(mHolder.center_warning);
Map<String, String> params = new HashMap<String, String>();
params.put("error_code", String.valueOf(result.getErrCode()));
params.put("error_message", result.getErrMessage());
LogHelper.i(TAG, "flurry_musicid_gnfail");
AnalyticsHelper.logEvent(getString(R.string.flurry_musicid_gnfail), params);
// prior status update
} else {
//ERRORE GN NON HA UN RISULTATO
if (result.isFingerprintSearchNoMatchStatus()) {
// Handle special case of webservices lookup with no match
updateMetaDataFields((GNSearchResponse) null);
if(UIUtils.isTablet(getActivity()) && !(Boolean)Global.getSettingsHolder().getSetting(MXMSettingHolder.PORTRAIT_LOCK))
UIUtils.enableRotation(getActivity());
if(mWakeLock.isHeld())
mWakeLock.release();
LogHelper.i(TAG, "flurry_musicid_gnnotmatch");
AnalyticsHelper.logEvent(getString(R.string.flurry_musicid_gnnotmatch));
mHolder.circle.setCenterIconDrawable(mHolder.center_warning);
} else {
//GN HAS A RESULT
LogHelper.i(TAG, "flurry_musicid_success");
AnalyticsHelper.logEvent(getString(R.string.flurry_musicid_success));
loadLyrics(result);
//commentato questa riga che mette il titolo nello status
//updateMetaDataFields(bestResponse);
return;
}
}
mHolder.circle.setClickable(true);
mHolder.circle.setOnClickListener(startAnimationAndRecording);
}
public void interrupt(){
if( !searching )
return;
//stop the animation
mHolder.center_matching.stop();
searching = false;
}
/**
* Intermediate status update from the fingerprinter
*/
public void GNStatusChanged(GNStatus status) {
//qui arrivano gli aggiornamenti di stato di GN
}
}
/**
*
* It will initiate the process to insert values into database.
*
* @param row
* - It contains all the information to be inserted into DB,
* except location.
*/
private void loadLyrics(GNSearchResult row) {
latestSearchResult = row;
final GNSearchResponse latestResponse = row.getBestResponse();
// Ho il finger, cerco sul db se il finger esiste gia' e carico quei
// dati
// altrimenti faccio la query a MXMSERVER
final String query = Tables.TRACKS + "." + Tracks.TRACK_TITLE
+ "=? COLLATE NOCASE AND " + Tables.TRACKS + "."
+ Tracks.TRACK_ARTIST_TITLE + "=? COLLATE NOCASE";
String[] params = new String[] { latestResponse.getTrackTitle(),
latestResponse.getArtist() };
mHandler.startQuery(
ModelTrack.TracksQuery._TOKEN,
null,
Tracks.buildSearchUri("NOTHING"),
ModelTrack.TracksQuery.PROJECTION,
query,
new String[] { latestResponse.getTrackTitle(),
latestResponse.getArtist() }, Tables.TRACKS + "."
+ Tracks.DEFAULT_SORT);
// We will take care only of the row.getBestResponse() case
}
public void stopAnimationAndRecording() {
mHolder.statusText.setClickable(true);
LogHelper.i(TAG, "flurry_musicid_interrupt");
AnalyticsHelper.logEvent(getString(R.string.flurry_musicid_interrupt));
if (recorder.isRunning())
recorder.stopRecording();
if (mHolder.circle.isRunning())
mHolder.circle.stopAnimation();
mHolder.circle.setProgress(0);
mHolder.circle.setNegativeProgressRatio(0.0);
if(lastUsedTask != null && lastUsedTask.isSearching()) {
GNOperations.cancel(lastUsedTask);
lastUsedTask.interrupt();
mHolder.circle.setOnClickListener(startAnimationAndRecording);
mHolder.circle.setCenterIconDrawable(mHolder.center_tap_to_start);
updateStatus(MXMConfig.getRandomString(MXMConfig.CONFIG_KEYS.FINGER_STRING_INTERRUPTED), true);
}
}
/** {@inheritDoc} */
@Override
public void onQueryComplete(int token, Object cookie, Cursor cursor) {
if (this == null) {
return;
}
if (token == ModelTrack.TracksQuery._TOKEN) {
onTrackSearchQueryComplete(cursor);
} else {
cursor.close();
}
}
/**
* Handle {@link PostsQuery} {@link Cursor}.
*/
private void onTrackSearchQueryComplete(Cursor cursor) {
//modelTask = (UpdateModelTask) new UpdateModelTask().execute(cursor);
//Adesso viene fatto tutto da XLBL
MXMConfig.addFinger();
final boolean needSave = (cursor == null || !cursor
.moveToFirst()) ? true : false;
ModelTrack model = new ModelTrack();
try {
if ( !needSave )
model.setData(cursor);
} finally {
if ( cursor != null )
cursor.close();
}
//Ricreo il fingerprint
final MXMFingerprint finger = new MXMFingerprint(
latestSearchResult, recorder.getLastConfig().getJSONRappresentation() );
String uniqueFingerID = null;
//Il fingerprint adesso lo salviamo anche se non abbiamo un riferimento alla track, tanto non ci interessa
uniqueFingerID = UUID.randomUUID() + "-" + finger.getTrackId() + ".pcm";
if ( (Boolean) MXMConfig.getConfigValue(MXMConfig.CONFIG_KEYS.MXM_SAVE_PCM) ) {
StorageHelper.updateExternalStorageState();
boolean result = StorageHelper.createExternalStoragePrivateFile(getActivity(), uniqueFingerID, getActivity().getPackageName(), FingerprintFragment.this.recordedBuffer );
if ( result )
finger.setPcmFileName(uniqueFingerID);
}
final Intent intent = new Intent(getActivity(),
BLBLActivity.class);
if ( model.getTrack() != null && model.getTrack().hasContent() ) {
Global.cacheModelTrack(
new MXMUniqueId(null, model.getTrack().getTrackMxmId()), model);
intent.putExtra(ModelTrack.PARAM_NAME_MXMID,
model.getTrack().getTrackMxmId());
intent.putExtra(FingerprintResultFragment.SONG_LENGHT_PARAM, model.getTrack().getTrackLength());
finger.setTrackMXMId(model.getTrack().getTrackMxmId());
finger.setArtistMXMId(model.getTrack().getArtistMxmId());
intent.putExtra(MXMTrack.PARAM_NAME_OBJECT, model.getTrack());
}
intent.putExtra(FingerprintFragment.PARAM_NAME_FROM_MUSICID,
true);
intent.putExtra(MXMFingerprint.PARAM_NAME_OBJECT, finger);
intent.putExtra(FingerprintResultFragment.RECORD_END_SYSTEM_TIME, mEndLastRecordTime);
if(mWakeLock.isHeld())
mWakeLock.release();
if(UIUtils.isTablet(getActivity()) && !(Boolean)Global.getSettingsHolder().getSetting(MXMSettingHolder.PORTRAIT_LOCK))
UIUtils.enableRotation(getActivity());
// faccio partire backgroundupdatetask
// controlla se il ttl ti fa aggiornare o meno
/*bgTask = (BackgroundUpdateDataTask) new BackgroundUpdateDataTask(
Constants.TAG_FINGERPRINTING, getActivity()).execute(model);*/
startActivity(intent);
}
protected class TaskResult {
MXMTrack track = null;
ModelTrack model = null;
String uniquePCMId = null;
public TaskResult(ModelTrack model, MXMTrack track, String uniquePCMId) {
this.model = model;
this.track = track;
this.uniquePCMId = uniquePCMId;
}
}
private class UpdateModelTask extends
AsyncTask<Cursor, Integer, TaskResult> {
protected TaskResult doInBackground(Cursor... cursors) {
final Cursor cursor = cursors[0];
MXMConfig.addFinger();
try {
final boolean needSave = (cursor == null || !cursor
.moveToFirst()) ? true : false;
// In ogni caso va messo il cash il ModelTrack
ModelTrack model = new ModelTrack();
MXMTrack track = null;
if (needSave) {
// Fa sempre la ricerca su internet
final GNSearchResponse latestResponse = latestSearchResult
.getBestResponse();
track = MusicHelper.getMatchingTrack(
getActivity(),
latestResponse.getTrackTitle(),
latestResponse.getArtist(),
latestResponse.getAlbumTitle(), -1,
Constants.TAG_FINGERPRINTING
);
model = Global.getModelTrack(new MXMUniqueId(null, track
.getTrackMxmId()));
if (model != null) {
model.setTrack(track);
}
} else {
model.setData(cursor);
}
String uniqueFingerID = null;
if( track != null && track.hasContent() ) {
uniqueFingerID = UUID.randomUUID() + "-" + track.getTrackMxmId() + ".pcm";
StorageHelper.updateExternalStorageState();
boolean result = StorageHelper.createExternalStoragePrivateFile(getActivity(), uniqueFingerID, getActivity().getPackageName(), FingerprintFragment.this.recordedBuffer );
MXMConfig.addSuccessFinger();
}
return new TaskResult(model, track, uniqueFingerID);
} finally {
if ( cursor != null )
cursor.close();
}
}
@Override
protected void onPostExecute(TaskResult result) {
//if ( result == null ) {
// showError( MXMConfig.getRandomString(MXMConfig.CONFIG_KEYS.ERROR_CONNECTION_LOW) );
//} else {
final ModelTrack model = result.model;
final MXMTrack track = (model != null && model.getTrack() != null) ? model.getTrack() : result.track;
if (track != null) {
if ( track.hasContent() ) {
MXMConfig.addSuccessFinger();
AnalyticsHelper.logEvent(getString(R.string.flurry_musicid_success));
// salvo e lancio l'activity
final MXMFingerprint finger = new MXMFingerprint(
latestSearchResult, recorder.getLastConfig().getJSONRappresentation());
finger.setTrackMXMId(track.getTrackMxmId());
finger.setPcmFileName(result.uniquePCMId);
final Intent intent = new Intent(getActivity(),
BLBLActivity.class);
intent.putExtra(MXMFingerprint.PARAM_NAME_OBJECT, finger);
intent.putExtra(FingerprintResultFragment.SONG_LENGHT_PARAM, track.getTrackLength());
intent.putExtra(FingerprintResultFragment.RECORD_END_SYSTEM_TIME, mEndLastRecordTime);
if (model != null) {
Global.cacheModelTrack(
new MXMUniqueId(null, track.getTrackMxmId()), model);
intent.putExtra(ModelTrack.PARAM_NAME_MXMID,
track.getTrackMxmId());
}
intent.putExtra(MXMTrack.PARAM_NAME_OBJECT, track);
// faccio partire backgroundupdatetask
// controlla se il ttl ti fa aggiornare o meno
/*bgTask = (BackgroundUpdateDataTask) new BackgroundUpdateDataTask(
Constants.TAG_FINGERPRINTING, getActivity()).execute(model);*/
startActivity(intent);
} else if ( track.getStatus() != null && track.getStatus().getStatusCode() == StatusCode.REQUEST_TIMEOUT_CODE ) {
showError( MXMConfig.getRandomString(MXMConfig.CONFIG_KEYS.ERROR_CONNECTION_LOW) );
} else {
showError( getString(R.string.error_mxm_no_lyrics_single) );
AnalyticsHelper.logEvent(getString(R.string.flurry_musicid_mxmfail));
}
} else {
showError( getString(R.string.error_mxm_no_lyrics_single) );
AnalyticsHelper.logEvent(getString(R.string.flurry_musicid_mxmfail));
}
//}
if(mWakeLock.isHeld())
mWakeLock.release();
if(UIUtils.isTablet(getActivity()) && !(Boolean)Global.getSettingsHolder().getSetting(MXMSettingHolder.PORTRAIT_LOCK))
UIUtils.enableRotation(getActivity());
}
}
private void showError( String error ) {
mHolder.circle.setCenterIconDrawable(mHolder.center_warning);
mHolder.circle.setClickable(true);
mHolder.circle.setOnClickListener(startAnimationAndRecording);
// Display errore
mHolder.statusText.setText(error);
}
private boolean last_gn_query_no_result = false;
private long last_no_result_time = 0;
/**
* Adds a new row of audio details including cover art to the UI for a
* GNSearchResponse result from the SDK. If the lookup was successful but
* failed to match a known track, then this method will be invoked with a
* null argument. This method is not invoked in the error case.
*/
private void updateMetaDataFields(final GNSearchResponse bestResponse) {
if (bestResponse == null) {
long current = System.currentTimeMillis();
if( last_gn_query_no_result && (current - last_no_result_time ) < 3*60*1e3 ) {
updateStatus( MXMConfig.getRandomString(MXMConfig.CONFIG_KEYS.ERROR_GN_NO_MATCH2) , true);
//TODO: aprire il search
getActivity().startSearch("Type songs words here",true , null, false);
//InputMethodManager imm = (InputMethodManager)getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
//imm.hideSoftInputFromWindow(holder.root.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY);
//holder.search_button.setFocusableInTouchMode(true);
//holder.search_button.requestFocus();
} else{
updateStatus( MXMConfig.getRandomString(MXMConfig.CONFIG_KEYS.ERROR_GN_NO_MATCH) , true);
}
last_no_result_time = current;
last_gn_query_no_result = true;
} else {
last_gn_query_no_result = false;
updateStatus( bestResponse.getTrackTitle(), true);
}
}
private static class ViewHolder extends MXMFragmentViewHolder<FingerprintFragment>{
DiscProgressView circle;
TextView statusText;
ViewGroup content;
View search_button;
AnimationDrawable center_matching;
Drawable center_tap_to_start;
Drawable center_warning;
Drawable center_listening;
Bitmap bg;
Bitmap gradient;
ViewGroup messageErrLayout;
TextView error_msg;
public ViewHolder(ViewGroup root, FingerprintFragment fragment) {
super(fragment.getActivity(), fragment, root);
content = (ViewGroup) root.findViewById(R.id.content);
statusText = (TextView) content.findViewById(R.id.statusText);
statusText.setTypeface(Global.getTypeface(getActivity()));
circle = (DiscProgressView) content.findViewById(R.id.fingerprint_button);
try {
initBitmaps();
} catch (FileNotFoundException e) {
//e.printStackTrace();
}
circle.setAnimationBitmap(bg, gradient);
circle.setCenterBackground(R.drawable.fingerprint_center_background);
search_button = ((MusicSinglePaneActivity)getActivity()).findViewById(R.id.menu_search);
center_matching = (AnimationDrawable)getActivity().getResources().getDrawable(R.drawable.fingerprint_sync_anim);
center_warning = getActivity().getResources().getDrawable(R.drawable.fingerprint_warning);
center_tap_to_start = getActivity().getResources().getDrawable(R.drawable.fingerprint_start);
center_listening = getActivity().getResources().getDrawable(R.drawable.fingerprint_listening_d);
//center_listening = getActivity().getR
messageErrLayout = (ViewGroup) root.findViewById(R.id.error_msg_layout);
error_msg = (TextView) messageErrLayout.findViewById(R.id.error_msg_text);
}
private void onNoMicrophone() {
//imposta il messaggio di errore
showMessageError( getActivity().getString(R.string.error_no_microphone) );
}
public void showContent(boolean show) {
messageErrLayout.setVisibility(View.GONE);
content.setVisibility((show? View.VISIBLE : View.GONE));
}
public void showMessageError( String error ){
messageErrLayout.setVisibility(View.VISIBLE);
error_msg.setText( error );
content.setVisibility(View.GONE);
}
@Override
public void bindValues() {
circle.setOnClickListener(mFragment.startAnimationAndRecording);
}
@Override
public void onDestroy() {
bg.recycle();
bg = null;
gradient.recycle();
gradient = null;
circle = null;
mFragment.mHolder = null;
super.onDestroy();
}
private void initBitmaps() throws FileNotFoundException{
WindowManager window_manager = mFragment.getActivity().getWindowManager();
int w = window_manager.getDefaultDisplay().getWidth();
int h = window_manager.getDefaultDisplay().getHeight();
ContentResolver res = mFragment.getActivity().getContentResolver();
Uri bg_uri = Uri.parse("android.resource://com.musixmatch.android.lyrify/" + R.drawable.fingerprint_anim_big);
Uri blur_uri = Uri.parse("android.resource://com.musixmatch.android.lyrify/" + R.drawable.fingerprint_anim_blur);
gradient = BitmapUtils.decodeStream(res, blur_uri, Math.min(w, h), Math.min(w, h), true);
bg = BitmapUtils.decodeStream(res, bg_uri, Math.min(w, h), Math.min(w, h), true);
}
public void onInterrupt(){
if(UIUtils.isTablet(getActivity()) && !(Boolean)Global.getSettingsHolder().getSetting(MXMSettingHolder.PORTRAIT_LOCK))
UIUtils.enableRotation(getActivity());
if (mFragment.mWakeLock.isHeld())
mFragment.mWakeLock.release();
}
}
@Override
public void onDeleteComplete(int token, Object cookie, int result) {
}
@Override
public void onUpdateComplete(int token, Object cookie, int result) {
}
@Override
public void onInsertComplete(int token, Object cookie, Uri uri) {
}
@Override
public void updateSearchPagerChild(Intent intent) {
}
public boolean onBackEvent() {
if ( !ConnectivityHelper.isOnline(getActivity()) )
return true;
if(mHolder.circle.isRunning() || recorder.isRunning() || (lastUsedTask != null && lastUsedTask.isSearching()) ) {
LogHelper.i(TAG, "onBackEvent: mHolder.circle.isRunning() || recorder.isRunning()");
stopAnimationAndRecording();
return true;
} else {
LogHelper.i(TAG, "can do back");
return false;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment