Created
June 13, 2012 14:47
-
-
Save loretoparisi/2924535 to your computer and use it in GitHub Desktop.
Android - Gracenote Implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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