diff options
46 files changed, 2203 insertions, 1741 deletions
diff --git a/native/android/avatar/src/main/AndroidManifest.xml b/native/android/avatar/src/main/AndroidManifest.xml index 9268c3316e..8aa98315c6 100644 --- a/native/android/avatar/src/main/AndroidManifest.xml +++ b/native/android/avatar/src/main/AndroidManifest.xml @@ -2,8 +2,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.ford.avarsdl" android:installLocation="preferExternal" - android:versionCode="1" - android:versionName="E4" > + android:versionCode="2" + android:versionName="E5" > <!-- Required to access Android Market Licensing --> <uses-permission android:name="com.android.vending.CHECK_LICENSE" /> @@ -18,6 +18,9 @@ <!-- Required to read and write the expansion files on shared storage --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.GET_TASKS" /> + <uses-permission android:name="android.permission.BLUETOOTH" /> + <!-- Required to pair Bluetooth devices --> + <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-sdk android:minSdkVersion="12" @@ -29,7 +32,7 @@ android:name=".business.MainApp" android:theme="@android:style/Theme.NoTitleBar.Fullscreen" > <activity - android:name=".activity.AvatarActivity" + android:name=".views.AvatarActivity" android:configChanges="keyboardHidden|orientation" android:label="@string/app_name" android:screenOrientation="landscape" > @@ -39,7 +42,7 @@ </intent-filter> </activity> <activity - android:name=".activity.EulaActivity" + android:name=".views.EulaActivity" android:label="@string/app_name" android:screenOrientation="landscape" /> diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/activity/AvatarActivity.java b/native/android/avatar/src/main/java/com/ford/avarsdl/activity/AvatarActivity.java deleted file mode 100644 index 7f3ee4b863..0000000000 --- a/native/android/avatar/src/main/java/com/ford/avarsdl/activity/AvatarActivity.java +++ /dev/null @@ -1,1145 +0,0 @@ -package com.ford.avarsdl.activity; - -import java.io.File; -import java.io.IOException; -import java.util.Timer; -import java.util.TimerTask; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.res.AssetFileDescriptor; -import android.content.res.AssetManager; -import android.graphics.Rect; -import android.media.AudioManager; -import android.media.MediaPlayer; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.StrictMode; -import android.preference.PreferenceManager; -import android.util.DisplayMetrics; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.SurfaceHolder; -import android.view.SurfaceView; -import android.view.View; -import android.view.Window; -import android.view.animation.Animation; -import android.view.animation.AnimationUtils; -import android.webkit.WebChromeClient; -import android.webkit.WebSettings.RenderPriority; -import android.webkit.WebView; -import android.widget.EditText; -import android.widget.ImageView; -import android.widget.ProgressBar; -import android.widget.RelativeLayout; -import android.widget.RelativeLayout.LayoutParams; -import android.widget.Toast; - -import com.android.vending.expansion.zipfile.APKExpansionSupport; -import com.android.vending.expansion.zipfile.ZipResourceFile; - -import com.ford.avarsdl.R; -import com.ford.avarsdl.downloader.DownloaderClient; -import com.ford.avarsdl.downloader.XAPKFile; -import com.ford.avarsdl.exception.ExtensionFileException; -import com.ford.avarsdl.exception.MediaPlayerException; -import com.ford.avarsdl.jsoncontroller.JSONBackendController; -import com.ford.avarsdl.jsoncontroller.JSONRateController; -import com.ford.avarsdl.jsoncontroller.JSONRevSDLController; -import com.ford.avarsdl.jsoncontroller.JSONVideoController; -import com.ford.avarsdl.jsonserver.JSONServer; -import com.ford.avarsdl.media.AvatarOnPreparedListener; -import com.ford.avarsdl.rater.AppRater; -import com.ford.avarsdl.service.ISDLServiceConnection; -import com.ford.avarsdl.service.SDLService; -import com.ford.avarsdl.service.SDLServiceBinder; -import com.ford.avarsdl.service.SDLServiceConnectionProxy; -import com.ford.avarsdl.util.ActivityUtils; -import com.ford.avarsdl.util.Const; -import com.ford.avarsdl.util.ExtStorageUtils; -import com.ford.avarsdl.util.Logger; -import com.ford.avarsdl.util.MessageConst; -import com.ford.avarsdl.util.Utils; -import com.ford.avarsdl.util.WebViewUtils; -import com.ford.syncV4.proxy.interfaces.IProxyListenerALM; - -/** - * Title: AvatarActivity.java<br> - * Description: Main application activity, responsible for webview content load - * and video handling<br> - * - * @author vsaenko/Eugene Sagan - * @co-author Yuriy Chernyshov - */ -public class AvatarActivity extends Activity implements SurfaceHolder.Callback, - ISDLServiceConnection { - - private final SDLServiceConnectionProxy mSDLServiceConnectionProxy = new SDLServiceConnectionProxy(this); - private IProxyListenerALM mBoundSDLService; - - // for monkey testing - // adb shell monkey -p com.ford.avarsdl -v 100 - - public static Boolean fullscreenPreferenceChanged = false; - public static Boolean vehiclePreferenceChanged = false; - public static Boolean navigationPreferenceChanged = false; - - public static Boolean ratePreferenceEnabled; - - @Override - public void onStart() { - super.onStart(); - - Logger.i(getClass().getSimpleName() + " onStart "); - - if (mBoundSDLService != null) { - - } else { - bindSDLService(this, mSDLServiceConnectionProxy); - } - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Logger.i(getClass().getSimpleName() + " onCreate, hash:" + hashCode()); - - // FIXME: the old code with new SDK crashes with - // android.os.NetworkOnMainThreadException - // this hotfix is a bad idea. Don't try this at home! - StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder(). - permitAll().build(); - StrictMode.setThreadPolicy(policy); - - if (isFirstStart()) { - Intent intent = new Intent(this, EulaActivity.class); - startActivityForResult(intent, Const.REQUESTCODE_EULA); - } else { - startAvatarActivity(); - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (resultCode == RESULT_OK && requestCode == Const.REQUESTCODE_EULA) { - startAvatarActivity(); - resumeAvatarActivity(); - } else { - finish(); - } - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) { - return true; - } - return super.onKeyDown(keyCode, event); - } - - @Override - public void onBackPressed() { - // do something on back. - this.moveTaskToBack(true); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.optionsmenu, menu); - return true; - } - public void bindSDLService(Context context, SDLServiceConnectionProxy connectionProxy) { - Logger.i("BindStorageService(), connection proxy: " + connectionProxy); - context.bindService(new Intent(context, SDLService.class), connectionProxy, BIND_AUTO_CREATE); - } - - public void unbindSDLService(Context context, SDLServiceConnectionProxy connectionProxy) { - if (!connectionProxy.isConnected()) { - Logger.v("ServiceConnection is not connected, ignoring unbindService: " + connectionProxy); - return; - } - try { - Logger.i("Unbind Service(), connection proxy: " + connectionProxy); - context.unbindService(connectionProxy); - } catch (IllegalArgumentException iae) { - // sometimes this exception is still thrown, in spite of isConnected() check above - // simply ignore this exception - Logger.w("Unbind IllegalArgumentException: " + iae); - } catch (Exception e) { - Logger.e("Error unbinding from connection: " + connectionProxy, e); - } - } - - - public boolean onOptionsItemSelected(MenuItem item) { - final int itemId = item.getItemId(); - switch (itemId) { - case R.id.mnuQuit: - exitApp(); - break; - default: - break; - } - return false; - } - - private void exitApp() { - Logger.d("Exiting application"); - - finish(); - // the delay should be long enough, so that UnregisterAppInterface and - // EndSession messages are sent - new Timer().schedule(new TimerTask() { - @Override - public void run() { - android.os.Process.killProcess(android.os.Process.myPid()); - } - }, 2000); - } - - public boolean isFirstStart() { - SharedPreferences prefs = getSharedPreferences(Const.SHPREF_FIRST_LAUNCH, 0); - int previousCodeVersion = prefs.getInt(Const.SHPREF_PREVIOUS_CODE_VERSION, 0); - int currentCodeVersion = Utils.getAppVersionCode(this); - if (previousCodeVersion < currentCodeVersion) { - return true; - } - return false; - } - - public void surfaceCreated(SurfaceHolder holder) { - Logger.i("surface created"); - playVideo(holder); - - } - - public void surfaceDestroyed(SurfaceHolder holder) { - Logger.i("surface destroyed"); - } - - // ============================================================= - // GETTERS - // ============================================================= - public WebView getWebView() { - return mWebView; - } - - public MediaPlayer getMediaPlayer() { - return mMediaPlayer; - } - - // get value from application settings - public Boolean getFullscreenStatus() { - return mPreferences.getBoolean("FULLSCREEN", true); - } - - // get value from application settings - public Boolean getMapsStatus() { - return mPreferences.getBoolean("MAPS", true); - } - - // get value from application settings - public String getVehicleStatus() { - return mPreferences.getString("VEHICLES", "Ford"); - } - - // get value from application settings - public Boolean getRateStatus() { - return mPreferences.getBoolean("RATE", true); - } - - // set value to application settings - public Boolean setMapsStatus(boolean value) { - SharedPreferences.Editor editor = mPreferences.edit(); - editor.putBoolean("MAPS", value); - editor.commit(); - return true; - } - - // set value to application settings - public boolean setVehicleStatus(String value) { - SharedPreferences.Editor editor = mPreferences.edit(); - editor.putString("VEHICLES", value); - editor.commit(); - return true; - } - - public double audioGetPosition() { - return mediaGetPosition(); - } - - public String getPathToDownloadedAudioFile(String fileName) { - final File file = new File(getExternalFilesDir(null), fileName + ".mp3"); - return file.getAbsolutePath(); - } - - public Handler getMainHandler() { - return handler; - } - - public int getVideoPausedPosition() { - return mVideoPauseTime; - } - - public double videoGetPosition() { - return mediaGetPosition(); - } - - public boolean videoWasPaused() { - return mVideoWasPaused; - } - - public boolean getVideoPlayed() { - return mVideoPlayed; - } - - public JSONVideoController getVideoController() { - return mVideoController; - } - - public boolean getVideoPrepared() { - return mVideoPrepared; - } - - public JSONBackendController getBEController() { - return mBEController; - } - - // setters - - public void setVideoPlayed(boolean value) { - mVideoPlayed = value; - } - - public void setVideoPrepared(boolean value) { - mVideoPrepared = value; - } - - // ============================================================== - // OTHER METHODS - // ============================================================== - - public void startVideoTimer() { - // start timer to send every N ms current time position of video - Logger.i("Start Timer"); - int N = 500; - - stopVideoTimer(); - - mVideoTimer = new Timer(); - TimerTask timerTask = new TimerTask() { - @Override - public void run() { - // current position in MP never reaches duration value - // check difference on 500 msec - if (mVideoPrepared) { - if ((mMediaPlayer.getDuration() - mMediaPlayer.getCurrentPosition()) < 500) - mVideoController.sendPositionNotification(mMediaPlayer.getDuration()); - else - mVideoController.sendPositionNotification(mMediaPlayer.getCurrentPosition()); - } - } - }; - mVideoTimer.schedule(timerTask, N, N); - } - - public void setProgresbarVisibility(boolean value) { - int v = value ? ProgressBar.VISIBLE : ProgressBar.GONE; - mProgressBar.setVisibility(v); - } - - // ===================================================================== - // private section - // ===================================================================== - - // private Context ctx; - - private MediaPlayer mMediaPlayer; - - private SharedPreferences mPreferences; - private WebView mWebView; - private SurfaceView mPreview; - private SurfaceHolder mHolder; - private ProgressBar mProgressBar; - private RelativeLayout mVideoLayout; - private ImageView mLogo; - - private int mSeekTo; - - private int mVideoWidth; - private int mVideoHeight; - private int mLeftMargin; - private int mTopMargin; - - private String mPath; - - private Animation mAnimationShow; - - // for JSON communication - private JSONServer mServerThread; - private JSONBackendController mBEController; - private JSONVideoController mVideoController; - - // for video time visualization - private Timer mVideoTimer;// timer to send notifications about current video - // time - private boolean mVideoWasPaused = false;// indicate if video was on paused - // before starting activity - private int mVideoPauseTime = 0;// time in msec when video was paused before - // starting activity - private boolean mVideoPlayed = false;// indicate if video played before - // starting activity - // to measure 5 seconds for splash screen; - private long mStartTime; - private boolean mVideoPrepared = false; // indicate that video in MP is - // prepared and timer can be started - - private AppRater mAppRater; - - private ZipResourceFile apkExpansionZipFile = null; - private Context mContext; - - private final Handler handler = new Handler() { - @Override - public void handleMessage(Message msg) { - - super.handleMessage(msg); - - switch (msg.what) { - - // /// VIDEO - case Const.VIDEO_START: - Logger.i("mMediaPlayer.play handler"); - Object[] obj = (Object[]) msg.obj; - String videoFile = (String) obj[0]; - Double scale = (Double) obj[1]; - int x = (Integer) obj[2]; - int y = (Integer) obj[3]; - videoViewResize(scale, y, x); - mPath = videoFile; - initVideoSurface(); - break; - case Const.VIDEO_PAUSE: - Logger.i("mMediaPlayer.pause handler"); - stopVideoTimer(); - if (mMediaPlayer != null) - mMediaPlayer.pause(); - mVideoWasPaused = true; - mVideoPauseTime = mMediaPlayer.getCurrentPosition(); - break; - case Const.VIDEO_SET_POSITION: - Double newPos = (Double) msg.obj * 1000; - newPos = newPos == 0 ? 1 : newPos; // because media player can - // not set zero value - if (mMediaPlayer != null) - mediaSetPosition(newPos); - break; - case Const.VIDEO_SET_POSITION_PAUSED: - newPos = (Double) msg.obj * 1000; - newPos = newPos == 0 ? 1 : newPos; // because media player can - // not set zero value - if (mMediaPlayer != null) - mediaSetPositionPaused(newPos); - break; - case Const.VIDEO_PLAY: - startVideoTimer(); - mVideoWasPaused = false; - Logger.i("mMediaPlayer.start case Const.VIDEO_PLAY"); - if (null != mMediaPlayer) { - mMediaPlayer.start(); - } else { - Logger.i("mMediaPlayer == null"); - } - break; - case Const.VIDEO_STOP: - mVideoLayout.setVisibility(View.INVISIBLE); - stopVideoTimer(); - releaseMediaPlayer(); - mVideoWidth = 0; - mVideoHeight = 0; - mLeftMargin = 0; - mTopMargin = 0; - mPath = null; - mVideoWasPaused = false; - mVideoPlayed = false; - mVideoPauseTime = 0; - break; - case Const.VIDEO_PLAY_AFTER_SCALE: - Logger.i("mMediaPlayer.play after scale handler"); - obj = (Object[]) msg.obj; - scale = (Double) obj[0]; - int left = (Integer) obj[1]; - int top = (Integer) obj[2]; - videoViewResize(scale, top, left); - initVideoSurface(); - break; - - case Const.CONTENT_CHECKER_START: - verifyContent(); - break; - - case Const.WEBVIEW_SHOW: - hideSplashScreen(); - setProgresbarVisibility(false); - mWebView.startAnimation(mAnimationShow); - mWebView.setVisibility(View.VISIBLE); - if (Const.DEBUG) { - long currTime = System.currentTimeMillis(); - String str = "Application loading time = " - + String.valueOf(currTime - mStartTime); - Toast.makeText(getApplicationContext(), str, - Toast.LENGTH_LONG).show(); - Logger.i(str); - } - showSDLSetupDialog(); - break; - - default: - break; - } - } - - }; - - private void verifyContent() { - - removeOldVideoFiles(); - - // check main expansion file - int mainVersionCode = expFileIsDelivered(true); - - SharedPreferences prefs = getSharedPreferences( - Const.SHPREF_DOWNLOADER_PREFS, 0); - boolean mainMD5IsCalculated = prefs.getBoolean( - Const.SHPREF_MAIN_EXPFILE_VALID, false); - - // check patch expansion file - int patchVersionCode = expFileIsDelivered(false); - - boolean patchMD5IsCalculated = prefs.getBoolean( - Const.SHPREF_PATCH_EXPFILE_VALID, false); - - if (mainVersionCode > 0 && mainMD5IsCalculated - && (patchVersionCode > 0 || Const.PATCH_EXP_FILE_SIZE == 0) - && patchMD5IsCalculated) { - try { - apkExpansionZipFile = APKExpansionSupport - .getAPKExpansionZipFile(this, mainVersionCode, - patchVersionCode); - } catch (IOException e) { - Logger.e(e.getMessage(), e); - } - - } else { - // no expansion file - SharedPreferences.Editor editor = prefs.edit(); - if (editor != null) { - editor.putBoolean(Const.SHPREF_MAIN_EXPFILE_VALID, false); - editor.putBoolean(Const.SHPREF_PATCH_EXPFILE_VALID, false); - } - editor.commit(); - // create downloader client - new DownloaderClient(this, mainVersionCode, mainMD5IsCalculated, - patchVersionCode, patchMD5IsCalculated); - - } - - Utils.sendMessageToHandler(Const.WEBVIEW_SHOW, - MessageConst.NET_DOWNLOAD_FINISHED_SUCC, handler); - } - - /** - * checks if expansion file was downloaded previously - * - * @param isMain - * - is a main expansion file or a patch - * @return version code if file exists or 0 - */ - - private int expFileIsDelivered(boolean isMain) { - int codeVersion = Utils.getAppVersionCode(getApplicationContext()); - long size = isMain ? Const.MAIN_EXP_FILE_SIZE - : Const.PATCH_EXP_FILE_SIZE; - while (codeVersion > 0) { - XAPKFile xFile = new XAPKFile(isMain, codeVersion, size); - if (ExtStorageUtils.expansionFilesDelivered(mContext, xFile)) { - return codeVersion; - } - codeVersion--; - } - return codeVersion; - } - - public void setExpantionFile(ZipResourceFile file) { - apkExpansionZipFile = file; - } - - /** - * removes video files of MFTG 2, that is apart of expansion file - */ - private boolean removeOldVideoFiles() { - File oldVideoFilesDirectory = getExternalFilesDir(null); - if ((oldVideoFilesDirectory != null) && - oldVideoFilesDirectory.exists()) { - boolean success = true; - final File[] files = oldVideoFilesDirectory.listFiles(); - if (files != null) { - for (File file : files) { - success &= file.delete(); - } - return success; - } - } - Logger.i("Couldn't remove old video files"); - return false; - } - - @Override - protected void onPause() { - super.onPause(); - Logger.i(getClass().getSimpleName() + " onPause, hash:" + hashCode()); - if (!isFirstStart()) { - ActivityUtils.setAppIsForeground(false); - // switch of timer - stopVideoTimer(); - // remember last video position - if (mMediaPlayer != null) - mVideoPauseTime = mMediaPlayer.getCurrentPosition(); - // delete media player - releaseMediaPlayer(); - mVideoLayout.removeAllViews(); - } - } - - protected void onResume() { - super.onResume(); - Logger.i(getClass().getSimpleName() + " onResume, hash:" + hashCode()); - if (!isFirstStart()) { - resumeAvatarActivity(); - } - } - - private void startAvatarActivity() { - mStartTime = System.currentTimeMillis(); - mContext = this; - // Possible work around for market launches. See - // http://code.google.com/p/android/issues/detail?id=2373 - // for more details. Essentially, the market launches the main activity - // on top of other activities. - // we never want this to happen. Instead, we check if we are the root - // and if not, we finish. - if (!isTaskRoot()) { - final Intent intent = getIntent(); - final String intentAction = intent.getAction(); - if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && intentAction != null - && intentAction.equals(Intent.ACTION_MAIN)) { - Logger.w("Main Activity is not the root. Finishing Main Activity instead of launching."); - finish(); - return; - } - } - - mAppRater = new AppRater(this); - startRPCComponents(); - prepareMainView(); - WebViewUtils.initWebView(this); - initVideoSurface(); - } - - private void resumeAvatarActivity() { - ActivityUtils.setAppIsForeground(true); - - if (!fullscreenPreferenceChanged && !vehiclePreferenceChanged) - initVideoSurface(); // to init video after resuming but not - // after FullScreen or Vehicle changing - - if (mPreferences != null) { - if (fullscreenPreferenceChanged) { - fullscreenPreferenceChanged = false; - mBEController.sendFullScreenRequest(getFullscreenStatus()); - } - - if (vehiclePreferenceChanged) { - vehiclePreferenceChanged = false; - mBEController.sendVehicleNotification(getVehicleStatus()); - } - - if (navigationPreferenceChanged) { - navigationPreferenceChanged = false; - mBEController.sendHasMapsNotification(getMapsStatus()); - } - - if (mWebView.getUrl() == null) { - if (!loadContent()) { - Toast.makeText(this, R.string.toast_index_not_found, Toast.LENGTH_LONG).show(); - } - } - } - } - - private void showSDLSetupDialog() { - LayoutInflater inflater = getLayoutInflater(); - View dialogView = inflater.inflate(R.layout.sdl_settings, null); - - if (dialogView == null) { - return; - } - - final EditText ipAddressText = (EditText) dialogView.findViewById(R.id.sdl_ipAddr); - final EditText tcpPortText = (EditText) dialogView.findViewById(R.id.sdl_tcpPort); - - final SharedPreferences prefs = getSharedPreferences(Const.PREFS_NAME, 0); - String ipAddressString = prefs.getString(Const.PREFS_KEY_IPADDR, Const.PREFS_DEFAULT_IPADDR); - int tcpPortInt = prefs.getInt(Const.PREFS_KEY_TCPPORT, Const.PREFS_DEFAULT_TCPPORT); - - ipAddressText.setText(ipAddressString); - tcpPortText.setText(String.valueOf(tcpPortInt)); - - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setView(dialogView) - .setTitle("Please provide SDL address") - .setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - String ipAddressString = ipAddressText.getText().toString(); - int tcpPortInt; - try { - tcpPortInt = Integer.parseInt(tcpPortText.getText().toString()); - } catch (NumberFormatException e) { - Logger.i("Couldn't parse port number", e); - tcpPortInt = Const.PREFS_DEFAULT_TCPPORT; - } - - SharedPreferences.Editor prefsEditor = - getSharedPreferences(Const.PREFS_NAME, 0).edit(); - prefsEditor.putString(Const.PREFS_KEY_IPADDR, ipAddressString); - prefsEditor.putInt(Const.PREFS_KEY_TCPPORT, tcpPortInt); - prefsEditor.commit(); - - Intent intent = new Intent(getApplicationContext(), SDLService.class); - //intent.putExtra() - startService(intent); - } - }) - .show(); - } - - @Override - protected void onDestroy() { - Logger.i(getClass().getSimpleName() + " onDestroy, hash:" + hashCode()); - - unbindSDLService(getBaseContext(), mSDLServiceConnectionProxy); - stopService(new Intent(this, SDLService.class)); - - if (!isFirstStart()) { - // switch of timer - stopVideoTimer(); - - releaseMediaPlayer(); - doCleanUp(); - // close JSON server - try { - if (mServerThread != null) - mServerThread.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - super.onDestroy(); - } - - /** - * Checks if the filename exists in the assets. - * - * @param assetFilename Filename without any prefix - * @return true if the file exists - */ - private boolean assetExists(final String assetFilename) { - AssetManager am = getResources().getAssets(); - try { - am.open(assetFilename); - } catch (IOException e) { - return false; - } - return true; - } - - private boolean loadContent() { - Logger.i("loadContent"); - boolean successful = false; - if (assetExists(Const.INDEX_PAGE)) { - mWebView.loadUrl(Const.WEB_MAIN_PAGE_PATH); - successful = true; - } - return successful; - } - - private void startRPCComponents() { - Logger.i(getClass().getSimpleName() + " Start RPC Components"); - - mServerThread = new JSONServer(); - mServerThread.setName("ServerThread"); - mServerThread.start(); - - // wait for a while - while (!mServerThread.isReady()) { - try { - Thread.sleep(10); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - mBEController = new JSONBackendController(this); - mBEController.register(27); - // wait for a while - while (!mBEController.isRegistered()) { - try { - Thread.sleep(10); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - mVideoController = new JSONVideoController(this); - mVideoController.register(28); - // wait for a while - while (!mVideoController.isRegistered()) { - try { - Thread.sleep(10); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - JSONRateController mRateController = new JSONRateController(mAppRater); - mRateController.register(29); - // wait for a while - while (!mRateController.isRegistered()) { - try { - Thread.sleep(10); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - JSONRevSDLController mRevSDLController = new JSONRevSDLController(); - mRevSDLController.register(30); - // wait for a while - while (!mRevSDLController.isRegistered()) { - try { - Thread.sleep(10); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - - private void prepareMainView() { - Logger.i("prepareMainView"); - setContentView(R.layout.main); - - mPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - Boolean fullScreen = getFullscreenStatus(); - mLogo = (ImageView) findViewById(R.id.logo); - Logger.i("mFullScreen is " + fullScreen.toString()); - if (fullScreen) { - RelativeLayout.LayoutParams params = new LayoutParams( - LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); - mLogo.setLayoutParams(params); - // mLogo.setLayoutParams(params); - } else { - - RelativeLayout.LayoutParams params = new LayoutParams(800, 480); - params.addRule(RelativeLayout.CENTER_HORIZONTAL); - params.addRule(RelativeLayout.CENTER_VERTICAL); - mLogo.setLayoutParams(params); - } - mWebView = (WebView) findViewById(R.id.webView1); - mWebView.setWebChromeClient(new WebChromeClient()); - mWebView.getSettings().setRenderPriority(RenderPriority.HIGH); - // mWebView.getSettings().setLoadWithOverviewMode(true); - // mWebView.getSettings().setUseWideViewPort(true); - // mWebView.setInitialScale(10); - - mVideoLayout = (RelativeLayout) findViewById(R.id.videoLayout); - // set progress bar - mProgressBar = (ProgressBar) findViewById(R.id.pbProgress); - LayoutParams progressParams = (LayoutParams) mProgressBar - .getLayoutParams(); - double loaderHeight = Const.WEB_HEIGHT * getScale() * 0.07 * getWindowDensity(); - progressParams.height = (int) loaderHeight; - progressParams.width = progressParams.height; - double loaderVerticalCenter = getWindowHeight() * 0.5; - double loaderVerticalShift = Const.WEB_HEIGHT * getScale() * 0.5 * 0.41 * getWindowDensity(); - double top = (loaderVerticalCenter - 0.5 * loaderHeight) + loaderVerticalShift; - progressParams.topMargin = (int) Math.round(top); - mProgressBar.setLayoutParams(progressParams); - - mAnimationShow = AnimationUtils.loadAnimation(this, R.anim.show); - } - - private double getScale() { - double res = 1; - if (isFullScreen()) { - /** Calculate Scale Point */ - double scalePointW = (double) getWindowWidth() - / (double) Const.WEB_WIDTH / getWindowDensity(); - double scalePointH = (double) getWindowHeight() - / (double) Const.WEB_HEIGHT / getWindowDensity(); - /** Set calculated ScalePoint */ - res = (scalePointW >= scalePointH) ? scalePointH : scalePointW; - } else { - res /= getWindowDensity(); - } - return res; - } - - private boolean isFullScreen() { - SharedPreferences preferences = PreferenceManager - .getDefaultSharedPreferences(this.getApplicationContext()); - return preferences.getBoolean("FULLSCREEN", true); - } - - private Integer getWindowHeight() { - Integer height; - if ((Build.VERSION.SDK_INT > 10)/* && (Build.VERSION.SDK_INT < 14) */) { - // return height without tabs bar - Rect rectgle = new Rect(); - Window window = this.getWindow(); - window.getDecorView().getWindowVisibleDisplayFrame(rectgle); - height = rectgle.bottom; // height = - panel height - } else { - DisplayMetrics dm = new DisplayMetrics(); - this.getWindowManager().getDefaultDisplay().getMetrics(dm); - if (dm.heightPixels > dm.widthPixels) { - height = dm.widthPixels; - } else { - height = dm.heightPixels; - } - } - return height; - } - - private Integer getWindowWidth() { - Integer width; - DisplayMetrics dm = new DisplayMetrics(); - this.getWindowManager().getDefaultDisplay().getMetrics(dm); - if (dm.heightPixels > dm.widthPixels) { - width = dm.heightPixels; - } else { - width = dm.widthPixels; - } - return width; - } - - private void initVideoSurface() { - Logger.i("init surface"); - - mVideoLayout.setVisibility(View.INVISIBLE); - mVideoLayout.removeAllViews(); - - LayoutParams params = (LayoutParams) mVideoLayout.getLayoutParams(); - - params.height = mVideoHeight; - params.width = mVideoWidth; - params.leftMargin = mLeftMargin; - params.topMargin = mTopMargin; - - mVideoLayout.setLayoutParams(params); - mPreview = new SurfaceView(this); - - mVideoLayout.addView(mPreview); - mHolder = mPreview.getHolder(); - mHolder.addCallback(this); - mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); - mVideoLayout.forceLayout(); - mVideoLayout.setVisibility(View.VISIBLE); - - } - - private void hideSplashScreen() { - Logger.i("hide screen "); - mVideoLayout.setVisibility(View.VISIBLE); - mLogo.setVisibility(View.INVISIBLE); - } - - private double mediaGetPosition() { - // setIsGetPosition(true); - Logger.i("mediaGetPosition"); - // isDoubleSeek = true; - if (mMediaPlayer == null) { - return -1; - } - try { - return Utils - .getShortDouble(mMediaPlayer.getCurrentPosition() / 1000.0); - } catch (IllegalStateException e) { - Logger.e(e.getMessage(), e); - return -1; - } - } - - private void mediaSetPosition(double position) { - /* convert to milliseconds */ - // setIsGetPosition(false); - // position *= 1000; - mSeekTo = (int) position; - Logger.i("mediaSetPosition=" + position); - - try { - if (mSeekTo != 0) - mMediaPlayer.seekTo(mSeekTo); - } catch (IllegalStateException e) { - Logger.e(e.getMessage(), e); - } - } - - private void mediaSetPositionPaused(double position) { - /* convert to milliseconds */ - mSeekTo = (int) position; - - Logger.i("mediaSetPositionPaused=" + position); - - AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE); - audioManager.setStreamMute(AudioManager.STREAM_MUSIC, true); - try { - mMediaPlayer.seekTo(mSeekTo); - } catch (IllegalStateException e) { - Logger.e(e.getMessage(), e); - } - } - - private void releaseMediaPlayer() { - if (mMediaPlayer != null) { - mMediaPlayer.reset(); - mMediaPlayer.release(); - mMediaPlayer = null; - } - mVideoPrepared = false; - } - - private void videoViewResize(double scale, int top, int left) { - mVideoWidth = (int) (Const.ORIG_VIDEO_WIDTH * scale * getWindowDensity() - 1); - mVideoHeight = (int) (Const.ORIG_VIDEO_HEIGHT * scale * getWindowDensity() - 1); - mLeftMargin = (int) Math.round(left * getWindowDensity()); - mTopMargin = (int) Math.round(top * getWindowDensity()); - } - - private double getWindowDensity() { - DisplayMetrics dm = new DisplayMetrics(); - getWindowManager().getDefaultDisplay().getMetrics(dm); - return dm.density; - } - - private void playVideo(SurfaceHolder holder) { - Logger.i("playVideo"); - if (mPath != null) { - try { - if (mMediaPlayer != null) { - releaseMediaPlayer(); - } - // TODO : optimize MP instantiation - // Create a new media player and set the listeners - mMediaPlayer = new MediaPlayer(); - - initDatasourceWith(mPath); - - Logger.i("video file path : " + mPath); - - mMediaPlayer.setDisplay(holder); - - mMediaPlayer.setOnPreparedListener(new AvatarOnPreparedListener(this)); - mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); - - mMediaPlayer.prepare(); - } catch (Exception e) { - Logger.e("error: " + e.getMessage(), e); - // set duration of video - mVideoController.setVideoDuration(-1); - } - } else { - Logger.i("No video to play"); - } - } - - private void stopVideoTimer() { - if (mVideoTimer != null) { - mVideoTimer.cancel(); - mVideoTimer.purge(); - } - mVideoTimer = null; - } - - private void doCleanUp() { - mVideoWidth = 0; - mVideoHeight = 0; - if (mVideoLayout != null) - mVideoLayout.removeAllViews(); - mHolder = null; - mPreview = null; - mVideoWasPaused = false; - mVideoPauseTime = 0; - mVideoPlayed = false; - } - - private void initDatasourceWith(String fileName) - throws ExtensionFileException, MediaPlayerException { - - AssetFileDescriptor assetFileDescriptor; - // welcome orientation video is in raw resources - if (fileName.toLowerCase().compareTo(Const.WELCOME_VIDEO_FILE_NAME) == 0) { - assetFileDescriptor = getResources().openRawResourceFd(R.raw.faq_welcome_orientation); - } else { - // get file from expansion archive - if (apkExpansionZipFile == null) { - throw new ExtensionFileException("Expansion zip file variable is not initialized"); - } - assetFileDescriptor = apkExpansionZipFile.getAssetFileDescriptor(fileName); - } - - if (assetFileDescriptor == null) { - throw new ExtensionFileException("Assert file descriptor for file: " + fileName + - " not found"); - } - - try { - mMediaPlayer.setDataSource(assetFileDescriptor.getFileDescriptor(), - assetFileDescriptor.getStartOffset(), - assetFileDescriptor.getLength()); - } catch (IllegalArgumentException e) { - throw new MediaPlayerException(e); - } catch (IllegalStateException e) { - throw new MediaPlayerException(e); - } catch (IOException e) { - throw new MediaPlayerException(e); - } - } - - @Override - public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { - } - - @Override - public void onSDLServiceConnected(SDLServiceBinder service) { - Logger.i("SDLService connected " + service); - - mBoundSDLService = service.getService(); - } - - @Override - public void onSDLServiceDisconnected() { - Logger.i("SDLService disconnected"); - - mBoundSDLService = null; - } -}
\ No newline at end of file diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/activity/EulaActivity.java b/native/android/avatar/src/main/java/com/ford/avarsdl/activity/EulaActivity.java deleted file mode 100644 index 2bb9916006..0000000000 --- a/native/android/avatar/src/main/java/com/ford/avarsdl/activity/EulaActivity.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.ford.avarsdl.activity; - -import com.ford.avarsdl.R; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; - -public class EulaActivity extends Activity { - - private Button btnAgree; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.eula); - btnAgree=(Button)findViewById(R.id.btnAgree); - Bundle extras = getIntent().getExtras(); - if (extras != null && !extras.getBoolean("firstStart")){ - btnAgree.setText("Done"); - } - btnAgree.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - Intent intent = getIntent(); - setResult(Activity.RESULT_OK, intent); - finish(); - } - }); - } - - -} diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/downloader/DownloaderClient.java b/native/android/avatar/src/main/java/com/ford/avarsdl/downloader/DownloaderClient.java index 7a48f7880b..e2590e820a 100644 --- a/native/android/avatar/src/main/java/com/ford/avarsdl/downloader/DownloaderClient.java +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/downloader/DownloaderClient.java @@ -33,7 +33,7 @@ import android.widget.Toast; import com.android.vending.expansion.zipfile.APKExpansionSupport; import com.android.vending.expansion.zipfile.ZipResourceFile; import com.ford.avarsdl.R; -import com.ford.avarsdl.activity.AvatarActivity; +import com.ford.avarsdl.views.AvatarActivity; import com.ford.avarsdl.util.ActivityUtils; import com.ford.avarsdl.util.Const; import com.ford.avarsdl.util.LogUtils; diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/jsoncontroller/JSONAVAController.java b/native/android/avatar/src/main/java/com/ford/avarsdl/jsoncontroller/JSONAVAController.java index f3185ce582..e7f75dd6df 100644 --- a/native/android/avatar/src/main/java/com/ford/avarsdl/jsoncontroller/JSONAVAController.java +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/jsoncontroller/JSONAVAController.java @@ -1,84 +1,67 @@ package com.ford.avarsdl.jsoncontroller; -import android.util.Log; - -import com.ford.avarsdl.activity.AvatarActivity; -import com.ford.avarsdl.util.Const; +import com.ford.avarsdl.views.AvatarActivity; +import com.ford.avarsdl.util.Logger; import com.ford.avarsdl.util.RPCConst; -public class JSONAVAController extends JSONController{ - - private final boolean DEBUG = true; - private String mJSComponentName = null; - private final String TAG_NAME = "AVAController"; - private AvatarActivity mActivity; - - public JSONAVAController(AvatarActivity activity, String cname) { - super(RPCConst.CN_AVATAR); - mActivity = activity; - mJSComponentName = cname; - } - - public JSONAVAController(String cname, ITcpClient client) { - super(RPCConst.CN_AVATAR,client); - mJSComponentName = cname; - } - - - protected void processRequest(String request){ - processNotification(request); - } - - protected String processNotification(String notification){ - logMsg("Process notification"); - mJSONParser.putJSONObject(notification); - final String func = "FFW.WebSocketSimulator.receive('" + mJSComponentName - + "','" + notification + "')"; - //LogMsg(func); - logMsg("Send notification to JS"); - mActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - mActivity.getWebView().loadUrl("javascript:" + func); - } - }); - return null; - } - - protected void processResponse(String response){ - if (!processRegistrationResponse(response)){ - final String func = "FFW.WebSocketSimulator.receive('" + mJSComponentName - + "','" + response + "')"; - logMsg(func); - mActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - mActivity.getWebView().loadUrl("javascript:" + func); - } - }); - } - - - } - - public void sendJSMessage(String cName, String jsonMsg){ - logMsg("SendJSMessage : " + jsonMsg); - mJSONParser.putJSONObject(jsonMsg); - if(mJSONParser.getId()>=0 && - mJSONParser.getResult() == null && - mJSONParser.getError() == null){ - mJSComponentName = cName; - } - jsonMsg += System.getProperty("line.separator"); - sendJSONMsg(jsonMsg); - - } - - private void logMsg(String msg){ - if (DEBUG && Const.DEBUG){ - Log.i(TAG_NAME, msg); - } - } +public class JSONAVAController extends JSONController { + + private String mJSComponentName = null; + private AvatarActivity mActivity; + + public JSONAVAController(AvatarActivity activity, String cname) { + super(RPCConst.CN_AVATAR); + mActivity = activity; + mJSComponentName = cname; + } + + public JSONAVAController(String cname, ITcpClient client) { + super(RPCConst.CN_AVATAR, client); + mJSComponentName = cname; + } + + protected void processRequest(String request) { + processNotification(request); + } + + protected String processNotification(String notification) { + Logger.d(getClass().getSimpleName() + " Process notification: " + notification); + mJSONParser.putJSONObject(notification); + final String func = "FFW.WebSocketSimulator.receive('" + mJSComponentName + + "','" + notification + "')"; + Logger.d(getClass().getSimpleName() + " Send notification to JS"); + mActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + mActivity.getWebView().loadUrl("javascript:" + func); + } + }); + return null; + } + + protected void processResponse(String response) { + if (!processRegistrationResponse(response)) { + final String func = "FFW.WebSocketSimulator.receive('" + mJSComponentName + + "','" + response + "')"; + Logger.d(getClass().getSimpleName() + " : " + func); + mActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + mActivity.getWebView().loadUrl("javascript:" + func); + } + }); + } + } - -} + public void sendJSMessage(String cName, String jsonMsg) { + //Logger.d(getClass().getSimpleName() + " SendJSMessage : " + jsonMsg); + mJSONParser.putJSONObject(jsonMsg); + if (mJSONParser.getId() >= 0 && + mJSONParser.getResult() == null && + mJSONParser.getError() == null) { + mJSComponentName = cName; + } + jsonMsg += System.getProperty("line.separator"); + sendJSONMsg(jsonMsg); + } +}
\ No newline at end of file diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/jsoncontroller/JSONBackendController.java b/native/android/avatar/src/main/java/com/ford/avarsdl/jsoncontroller/JSONBackendController.java index e5592be997..2414cb46b7 100644 --- a/native/android/avatar/src/main/java/com/ford/avarsdl/jsoncontroller/JSONBackendController.java +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/jsoncontroller/JSONBackendController.java @@ -8,9 +8,9 @@ import android.os.Message; import android.util.DisplayMetrics; import android.view.Window; -import com.ford.avarsdl.activity.AvatarActivity; -import com.ford.avarsdl.activity.EulaActivity; -import com.ford.avarsdl.activity.SafeToast; +import com.ford.avarsdl.views.AvatarActivity; +import com.ford.avarsdl.views.EulaActivity; +import com.ford.avarsdl.views.SafeToast; import com.ford.avarsdl.jsonparser.EBEMethods; import com.ford.avarsdl.util.Const; import com.ford.avarsdl.util.Logger; @@ -166,18 +166,15 @@ public class JSONBackendController extends JSONController { * @return */ private String isFirstStart() { - boolean firstStart = mActivity.isFirstStart(); if (firstStart) { firstStart = true; // set new code version - SharedPreferences prefs = mActivity.getSharedPreferences( - Const.SHPREF_FIRST_LAUNCH, 0); + SharedPreferences prefs = mActivity.getSharedPreferences(Const.SHPREF_FIRST_LAUNCH, 0); SharedPreferences.Editor editor = prefs.edit(); if (editor != null) { int currentCodeVersion = Utils.getAppVersionCode(mActivity); - editor.putInt(Const.SHPREF_PREVIOUS_CODE_VERSION, - currentCodeVersion); + editor.putInt(Const.SHPREF_PREVIOUS_CODE_VERSION, currentCodeVersion); } editor.commit(); // set redownload counter to 0 diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/jsoncontroller/JSONController.java b/native/android/avatar/src/main/java/com/ford/avarsdl/jsoncontroller/JSONController.java index d6d86e3e32..f3b731b842 100644 --- a/native/android/avatar/src/main/java/com/ford/avarsdl/jsoncontroller/JSONController.java +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/jsoncontroller/JSONController.java @@ -126,7 +126,7 @@ public class JSONController { protected void sendJSONMsg(String jsonMsg) { mTCPClient.sendMsg(jsonMsg); - Logger.i(getClass().getSimpleName() + " sent: " + jsonMsg); + Logger.i(getClass().getSimpleName() + " JSON Msg sent: " + jsonMsg); } /** diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/jsoncontroller/JSONRevSDLController.java b/native/android/avatar/src/main/java/com/ford/avarsdl/jsoncontroller/JSONRevSDLController.java index 7c8dfbcad3..a498e9575b 100644 --- a/native/android/avatar/src/main/java/com/ford/avarsdl/jsoncontroller/JSONRevSDLController.java +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/jsoncontroller/JSONRevSDLController.java @@ -1,10 +1,13 @@ package com.ford.avarsdl.jsoncontroller; +import com.ford.avarsdl.requests.CancelAccessCommand; import com.ford.avarsdl.requests.GrantAccessCommand; import com.ford.avarsdl.requests.RequestCommand; import com.ford.avarsdl.requests.StartScanCommand; import com.ford.avarsdl.requests.StopScanCommand; +import com.ford.avarsdl.requests.TuneDownCommand; import com.ford.avarsdl.requests.TuneRadioCommand; +import com.ford.avarsdl.requests.TuneUpCommand; import com.ford.avarsdl.util.Logger; import com.ford.avarsdl.util.RPCConst; import com.ford.syncV4.proxy.constants.Names; @@ -45,6 +48,9 @@ public class JSONRevSDLController extends JSONController { GrantAccessCommand grantAccessCommand = new GrantAccessCommand(); commandsHashTable.put(Names.GrantAccess, grantAccessCommand); + CancelAccessCommand cancelAccessCommand = new CancelAccessCommand(); + commandsHashTable.put(Names.CancelAccess, cancelAccessCommand); + StartScanCommand startScanCommand = new StartScanCommand(); commandsHashTable.put(Names.StartScan, startScanCommand); @@ -53,5 +59,11 @@ public class JSONRevSDLController extends JSONController { TuneRadioCommand tuneRadioCommand = new TuneRadioCommand(); commandsHashTable.put(Names.TuneRadio, tuneRadioCommand); + + TuneUpCommand tuneUpCommand = new TuneUpCommand(); + commandsHashTable.put(Names.TuneUp, tuneUpCommand); + + TuneDownCommand tuneDownCommand = new TuneDownCommand(); + commandsHashTable.put(Names.TuneDown, tuneDownCommand); } }
\ No newline at end of file diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/jsoncontroller/JSONVideoController.java b/native/android/avatar/src/main/java/com/ford/avarsdl/jsoncontroller/JSONVideoController.java index 1af78f0b8c..adfc0ac732 100644 --- a/native/android/avatar/src/main/java/com/ford/avarsdl/jsoncontroller/JSONVideoController.java +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/jsoncontroller/JSONVideoController.java @@ -1,10 +1,11 @@ package com.ford.avarsdl.jsoncontroller; import java.io.File; + import android.content.SharedPreferences; import android.util.Log; -import com.ford.avarsdl.activity.AvatarActivity; +import com.ford.avarsdl.views.AvatarActivity; import com.ford.avarsdl.downloader.DownloaderClient; import com.ford.avarsdl.exception.SDCardException; import com.ford.avarsdl.jsonparser.EVideoMethods; @@ -20,398 +21,381 @@ import com.ford.avarsdl.util.WebViewUtils; * <b>File:</b> JSONVideoController.java <br> * <b>Description:</b> Controller that is responsible for video data * transferring through JSON RPC 2.0 protocol <br> - * + * * @author kbotnar - * */ public class JSONVideoController extends JSONController { - /** - * Constructor - * - * @param activity - * : the application main activity - */ - public JSONVideoController(AvatarActivity activity) { - super(RPCConst.CN_VIDEO); - mActivity = activity; - } + /** + * Constructor + * + * @param activity : the application main activity + */ + public JSONVideoController(AvatarActivity activity) { + super(RPCConst.CN_VIDEO); + mActivity = activity; + } - /** - * Send notification to web UI with video progress bar position - * - * @param position - * : video progress bar position - */ - public void sendPositionNotification(int position) { - String method = RPCConst.CN_VIDEO + "." - + EVideoMethods.positionChanged.toString(); - mJSONParser.putEmptyJSONObject(); - mJSONParser.putIntValue(RPCConst.TAG_VIDEO_CURRENT_POSITION, position); - this.sendNotification(method, mJSONParser.getJSONObject()); - } + /** + * Send notification to web UI with video progress bar position + * + * @param position : video progress bar position + */ + public void sendPositionNotification(int position) { + String method = RPCConst.CN_VIDEO + "." + + EVideoMethods.positionChanged.toString(); + mJSONParser.putEmptyJSONObject(); + mJSONParser.putIntValue(RPCConst.TAG_VIDEO_CURRENT_POSITION, position); + this.sendNotification(method, mJSONParser.getJSONObject()); + } - /** - * Set started video duration - * - * @param value - * : video duration - */ - public void setVideoDuration(int value) { - mVideoDuration = value; - } + /** + * Set started video duration + * + * @param value : video duration + */ + public void setVideoDuration(int value) { + mVideoDuration = value; + } - // =================================================================== - // private section - // =================================================================== - /** - * To show debug messages from current class - */ - private final boolean DEBUG = true; - private final String TAG_NAME = JSONVideoController.class.getSimpleName(); - private AvatarActivity mActivity; - /** - * Video file name in expansion file - */ - private String mVideoName; - private int mVideoDuration = 0; - private boolean mVideoIsStarted = false; // to prevent double start of video + // =================================================================== + // private section + // =================================================================== + /** + * To show debug messages from current class + */ + private final boolean DEBUG = true; + private final String TAG_NAME = JSONVideoController.class.getSimpleName(); + private AvatarActivity mActivity; + /** + * Video file name in expansion file + */ + private String mVideoName; + private int mVideoDuration = 0; + private boolean mVideoIsStarted = false; // to prevent double start of video - @Override - protected void processRequest(String request) { - logMsg("Process request"); - String result = processNotification(request); - if (result != null) { - mJSONParser.putJSONObject(request); - sendResponse(mJSONParser.getId(), result); - } - } + @Override + protected void processRequest(String request) { + logMsg("Process request"); + String result = processNotification(request); + if (result != null) { + mJSONParser.putJSONObject(request); + sendResponse(mJSONParser.getId(), result); + } + } - @Override - protected String processNotification(String notification) { - logMsg("Process notification : " + notification); - mJSONParser.putJSONObject(notification); - String method = mJSONParser.getMethod(); - method = method.substring(method.indexOf('.') + 1, method.length()); - String out = null; - switch (EVideoMethods.valueOf(method)) { - case start: - mJSONParser.putJSONObject(mJSONParser.getParams()); - mVideoName = mJSONParser - .getStringParam(RPCConst.TAG_VIDEO_FILE_NAME); - double scale = mJSONParser.getDoubleParam(RPCConst.TAG_SCALE); - mJSONParser.putJSONObject(mJSONParser - .getJSONObjectParam(RPCConst.TAG_VIDEO_POSITION)); - int left = mJSONParser.getIntParam(RPCConst.TAG_VIDEO_POSITION_X); - int top = mJSONParser.getIntParam(RPCConst.TAG_VIDEO_POSITION_Y); - out = start(scale, left, top); - break; - case stop: - out = stop(); - break; - case pause: - out = pause(); - break; - case resume: - out = resume(); - break; - case setPositionPaused: - mJSONParser.putJSONObject(mJSONParser.getParams()); - double pos = mJSONParser - .getDoubleParam(RPCConst.TAG_VIDEO_POSITION); - logMsg("POSITION = " + String.valueOf(pos)); - out = setPositionPaused(pos); - break; - case setPosition: - mJSONParser.putJSONObject(mJSONParser.getParams()); - pos = mJSONParser.getDoubleParam(RPCConst.TAG_VIDEO_POSITION); - logMsg("POSITION = " + String.valueOf(pos)); - out = setPosition(pos); - break; - case getPosition: - out = getPosition(); - break; - case stateChanged: - out = stateChanged(); - break; - case positionChanged: - out = positionChanged(); - break; - case setDragState: - mJSONParser.putJSONObject(mJSONParser.getParams()); - boolean state = mJSONParser - .getBooleanParam(RPCConst.TAG_VIDEO_DRAG_STATE); - out = setDragState(state); - break; - default: - mJSONParser.putEmptyJSONRPCObject(); - mJSONParser.putStringValue(RPCConst.TAG_ERROR, - "VideoController does not support function : " + method); - out = mJSONParser.getJSONObject(); - break; - } - return out; + @Override + protected String processNotification(String notification) { + logMsg("Process notification : " + notification); + mJSONParser.putJSONObject(notification); + String method = mJSONParser.getMethod(); + method = method.substring(method.indexOf('.') + 1, method.length()); + String out = null; + switch (EVideoMethods.valueOf(method)) { + case start: + mJSONParser.putJSONObject(mJSONParser.getParams()); + mVideoName = mJSONParser.getStringParam(RPCConst.TAG_VIDEO_FILE_NAME); + double scale = mJSONParser.getDoubleParam(RPCConst.TAG_SCALE); + mJSONParser.putJSONObject(mJSONParser.getJSONObjectParam(RPCConst.TAG_VIDEO_POSITION)); + int left = mJSONParser.getIntParam(RPCConst.TAG_VIDEO_POSITION_X); + int top = mJSONParser.getIntParam(RPCConst.TAG_VIDEO_POSITION_Y); + out = start(scale, left, top); + break; + case stop: + out = stop(); + break; + case pause: + out = pause(); + break; + case resume: + out = resume(); + break; + case setPositionPaused: + mJSONParser.putJSONObject(mJSONParser.getParams()); + double pos = mJSONParser + .getDoubleParam(RPCConst.TAG_VIDEO_POSITION); + logMsg("POSITION = " + String.valueOf(pos)); + out = setPositionPaused(pos); + break; + case setPosition: + mJSONParser.putJSONObject(mJSONParser.getParams()); + pos = mJSONParser.getDoubleParam(RPCConst.TAG_VIDEO_POSITION); + logMsg("POSITION = " + String.valueOf(pos)); + out = setPosition(pos); + break; + case getPosition: + out = getPosition(); + break; + case stateChanged: + out = stateChanged(); + break; + case positionChanged: + out = positionChanged(); + break; + case setDragState: + mJSONParser.putJSONObject(mJSONParser.getParams()); + boolean state = mJSONParser + .getBooleanParam(RPCConst.TAG_VIDEO_DRAG_STATE); + out = setDragState(state); + break; + default: + mJSONParser.putEmptyJSONRPCObject(); + mJSONParser.putStringValue(RPCConst.TAG_ERROR, + "VideoController does not support function : " + method); + out = mJSONParser.getJSONObject(); + break; + } + return out; - } + } - @Override - protected void processResponse(String response) { - logMsg("Process response"); - if (!processRegistrationResponse(response)) { - mJSONParser.putJSONObject(response); - mRequestResponse = mJSONParser.getResult(); - } - } + @Override + protected void processResponse(String response) { + logMsg("Process response"); + if (!processRegistrationResponse(response)) { + mJSONParser.putJSONObject(response); + mRequestResponse = mJSONParser.getResult(); + } + } - /** - * Subscription on properties - */ - protected void subscribeToProperties() { - subscribeTo("VideoPlayerClient.setDragState"); - } + /** + * Subscription on properties + */ + protected void subscribeToProperties() { + subscribeTo("VideoPlayerClient.setDragState"); + } - /** - * Start a video with parameters from web UI - * - * @param scale - * : video scale - * @param leftOffset - * : left video offset - * @param topOffset - * : top video offset - * @return result JSON object with video duration or error JSON object - */ - private String start(double scale, int leftOffset, int topOffset) { - // check if expansion files are available - SharedPreferences prefs = mActivity.getSharedPreferences( - Const.SHPREF_DOWNLOADER_PREFS, 0); - boolean expFielsAreValid = prefs.getBoolean( - Const.SHPREF_MAIN_EXPFILE_VALID, false) - && prefs.getBoolean(Const.SHPREF_PATCH_EXPFILE_VALID, false); + /** + * Start a video with parameters from web UI + * + * @param scale : video scale + * @param leftOffset : left video offset + * @param topOffset : top video offset + * @return result JSON object with video duration or error JSON object + */ + private String start(double scale, int leftOffset, int topOffset) { + // check if expansion files are available + SharedPreferences prefs = mActivity.getSharedPreferences(Const.SHPREF_DOWNLOADER_PREFS, 0); + boolean expFielsAreValid = prefs.getBoolean(Const.SHPREF_MAIN_EXPFILE_VALID, false) + && prefs.getBoolean(Const.SHPREF_PATCH_EXPFILE_VALID, false); - // additionally check if it is a welcome video - if (expFielsAreValid - || mVideoName.toLowerCase().compareTo( - Const.WELCOME_VIDEO_FILE_NAME) == 0) { - if (!mVideoIsStarted) { - mVideoIsStarted = true; - logMsg("Play video " + mVideoName); - Object obj[] = { mVideoName, scale, leftOffset, topOffset }; - Utils.sendMessageToHandler(Const.VIDEO_START, obj, - mActivity.getMainHandler()); - } - // wait for initializing video file and getting its duration - while (mVideoDuration == 0) { - try { - Thread.sleep(10); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } + // additionally check if it is a welcome video + if (expFielsAreValid || + mVideoName.toLowerCase().compareTo(Const.WELCOME_VIDEO_FILE_NAME) == 0) { + if (!mVideoIsStarted) { + mVideoIsStarted = true; + logMsg("Play video " + mVideoName); + Object obj[] = {mVideoName, scale, leftOffset, topOffset}; + Utils.sendMessageToHandler(Const.VIDEO_START, obj, mActivity.getMainHandler()); + } + // wait for initializing video file and getting its duration + while (mVideoDuration == 0) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } - if (mVideoDuration >= 0) { - mJSONParser.putEmptyJSONObject(); - mJSONParser.putIntValue(RPCConst._TAG_VIDEO_TOTAL_DURATION, - mVideoDuration); - return mJSONParser.getJSONObject(); - } - } - return findVideoPlayError(); - } + if (mVideoDuration >= 0) { + mJSONParser.putEmptyJSONObject(); + mJSONParser.putIntValue(RPCConst._TAG_VIDEO_TOTAL_DURATION, + mVideoDuration); + return mJSONParser.getJSONObject(); + } + } + return findVideoPlayError(); + } - /** - * Finds out what is wrong with video playing - * - * @return error JSON object - */ - private String findVideoPlayError() { - mJSONParser.putEmptyJSONObject(); - //put error value as an indicator for parser - mJSONParser.putStringValue(RPCConst.TAG_ERROR, ""); - // get redownload count - SharedPreferences prefs = mActivity.getSharedPreferences( - Const.SHPREF_DOWNLOADER_PREFS, 0); - int redownload_count = prefs.getInt(Const.SHPREF_REDOWNLOAD_COUNTER, 0); + /** + * Finds out what is wrong with video playing + * + * @return error JSON object + */ + private String findVideoPlayError() { + mJSONParser.putEmptyJSONObject(); + //put error value as an indicator for parser + mJSONParser.putStringValue(RPCConst.TAG_ERROR, ""); + // get redownload count + SharedPreferences prefs = mActivity.getSharedPreferences( + Const.SHPREF_DOWNLOADER_PREFS, 0); + int redownload_count = prefs.getInt(Const.SHPREF_REDOWNLOAD_COUNTER, 0); - // no network connection - if (!NetUtils.isOnline(mActivity)) { - mJSONParser.putStringValue(RPCConst.TAG_ERROR_MESSAGE, - MessageConst.NET_NET_NOT_AVAILABLE); - mJSONParser.putIntValue(RPCConst.TAG_ERROR_CODE, - Const.VC_NO_NETWORK_ERR_CODE); - } // video files are still downloading - else if (DownloaderClient.IS_PROCESSING_VIDEO) { - mJSONParser.putStringValue(RPCConst.TAG_ERROR_MESSAGE, - MessageConst.VC_VIDEO_IS_BEING_PROCESSED_ERR); - mJSONParser.putIntValue(RPCConst.TAG_ERROR_CODE, - Const.VC_VIDEO_IS_BEING_DOWNLOADED_ERR_CODE); - mJSONParser.putIntValue(RPCConst.TAG_ERROR_DATA, - DownloaderClient.DOWNLOADED_PERSENS); - DownloaderClient.FINISH_NOTIFY = true; - }// no space on SD card - else if (DownloaderClient.SDCARD_IS_FULL) { - mJSONParser.putStringValue(RPCConst.TAG_ERROR_MESSAGE, - MessageConst.VC_NO_SPACE_ERR); - mJSONParser.putIntValue(RPCConst.TAG_ERROR_CODE, - Const.VC_NO_SPACE_ERR_CODE); - }// video downloading count is exceeded - else if (redownload_count < Const.DOWNLOADER_LAUNCH_MAX_NUMBER) { - mJSONParser.putStringValue(RPCConst.TAG_ERROR_MESSAGE, - MessageConst.VC_VIDEO_IS_CORRUPTED_ERR); - mJSONParser.putIntValue(RPCConst.TAG_ERROR_CODE, - Const.VC_VIDEO_IS_CORRUPTED_ERR_CODE); - } // video is unavailable due to file corruption - else { - mJSONParser.putStringValue(RPCConst.TAG_ERROR_MESSAGE, - MessageConst.VC_VIDEO_IS_UNAVAILABLE_ERR); - mJSONParser.putIntValue(RPCConst.TAG_ERROR_CODE, - Const.VC_VIDEO_IS_UNAVAILABLE_ERR_CODE); - } - return mJSONParser.getJSONObject(); - } + // no network connection + if (!NetUtils.isOnline(mActivity)) { + mJSONParser.putStringValue(RPCConst.TAG_ERROR_MESSAGE, + MessageConst.NET_NET_NOT_AVAILABLE); + mJSONParser.putIntValue(RPCConst.TAG_ERROR_CODE, + Const.VC_NO_NETWORK_ERR_CODE); + } // video files are still downloading + else if (DownloaderClient.IS_PROCESSING_VIDEO) { + mJSONParser.putStringValue(RPCConst.TAG_ERROR_MESSAGE, + MessageConst.VC_VIDEO_IS_BEING_PROCESSED_ERR); + mJSONParser.putIntValue(RPCConst.TAG_ERROR_CODE, + Const.VC_VIDEO_IS_BEING_DOWNLOADED_ERR_CODE); + mJSONParser.putIntValue(RPCConst.TAG_ERROR_DATA, + DownloaderClient.DOWNLOADED_PERSENS); + DownloaderClient.FINISH_NOTIFY = true; + }// no space on SD card + else if (DownloaderClient.SDCARD_IS_FULL) { + mJSONParser.putStringValue(RPCConst.TAG_ERROR_MESSAGE, + MessageConst.VC_NO_SPACE_ERR); + mJSONParser.putIntValue(RPCConst.TAG_ERROR_CODE, + Const.VC_NO_SPACE_ERR_CODE); + }// video downloading count is exceeded + else if (redownload_count < Const.DOWNLOADER_LAUNCH_MAX_NUMBER) { + mJSONParser.putStringValue(RPCConst.TAG_ERROR_MESSAGE, + MessageConst.VC_VIDEO_IS_CORRUPTED_ERR); + mJSONParser.putIntValue(RPCConst.TAG_ERROR_CODE, + Const.VC_VIDEO_IS_CORRUPTED_ERR_CODE); + } // video is unavailable due to file corruption + else { + mJSONParser.putStringValue(RPCConst.TAG_ERROR_MESSAGE, + MessageConst.VC_VIDEO_IS_UNAVAILABLE_ERR); + mJSONParser.putIntValue(RPCConst.TAG_ERROR_CODE, + Const.VC_VIDEO_IS_UNAVAILABLE_ERR_CODE); + } + return mJSONParser.getJSONObject(); + } - /** - * stop video playing - * - * @return null, because it is a notification - */ - private String stop() { - logMsg("VideoStop"); - mVideoIsStarted = false; - Utils.sendMessageToHandler(Const.VIDEO_STOP, null, - mActivity.getMainHandler()); - mVideoDuration = 0; - return null; - } + /** + * stop video playing + * + * @return null, because it is a notification + */ + private String stop() { + logMsg("VideoStop"); + mVideoIsStarted = false; + Utils.sendMessageToHandler(Const.VIDEO_STOP, null, + mActivity.getMainHandler()); + mVideoDuration = 0; + return null; + } - /** - * pause video playing - * - * @return null, because it is a notification - */ - private String pause() { - logMsg("VideoPause"); - Utils.sendMessageToHandler(Const.VIDEO_PAUSE, null, - mActivity.getMainHandler()); - return null; - } + /** + * pause video playing + * + * @return null, because it is a notification + */ + private String pause() { + logMsg("VideoPause"); + Utils.sendMessageToHandler(Const.VIDEO_PAUSE, null, + mActivity.getMainHandler()); + return null; + } - /** - * resume video playing - * - * @return null, because it is a notification - */ - private String resume() { - logMsg("VideoPlay"); - Utils.sendMessageToHandler(Const.VIDEO_PLAY, null, - mActivity.getMainHandler()); - return null; - } + /** + * resume video playing + * + * @return null, because it is a notification + */ + private String resume() { + logMsg("VideoPlay"); + Utils.sendMessageToHandler(Const.VIDEO_PLAY, null, + mActivity.getMainHandler()); + return null; + } - /** - * Set a new position of video while it is paused - * - * @param position - * : new position - * @return null, because it is a notification - */ - private String setPositionPaused(double position) { - logMsg("VideoSetPositionPaused:" + position + " convert to=" + position); - Utils.sendMessageToHandler(Const.VIDEO_SET_POSITION_PAUSED, position, - mActivity.getMainHandler()); - return null; - } + /** + * Set a new position of video while it is paused + * + * @param position : new position + * @return null, because it is a notification + */ + private String setPositionPaused(double position) { + logMsg("VideoSetPositionPaused:" + position + " convert to=" + position); + Utils.sendMessageToHandler(Const.VIDEO_SET_POSITION_PAUSED, position, + mActivity.getMainHandler()); + return null; + } - /** - * Set a new position of video while it is playing - * - * @param position - * : new position - * @return null, because it is a notification - */ - private String setPosition(double position) { - logMsg("VideoSetPosition:" + position + " covert to=" + position); - Utils.sendMessageToHandler(Const.VIDEO_SET_POSITION, position, - mActivity.getMainHandler()); - return null; - } + /** + * Set a new position of video while it is playing + * + * @param position : new position + * @return null, because it is a notification + */ + private String setPosition(double position) { + logMsg("VideoSetPosition:" + position + " covert to=" + position); + Utils.sendMessageToHandler(Const.VIDEO_SET_POSITION, position, + mActivity.getMainHandler()); + return null; + } - /** - * Get current position in seconds - * - * @return current position in seconds - */ - private String getPosition() { - double out = mActivity.videoGetPosition(); - logMsg("VideoGetPosition Position=" + out); - return String.valueOf(out); - } + /** + * Get current position in seconds + * + * @return current position in seconds + */ + private String getPosition() { + double out = mActivity.videoGetPosition(); + logMsg("VideoGetPosition Position=" + out); + return String.valueOf(out); + } - /** - * Stub for future - * - * @return null - */ - private String stateChanged() { - return null; - } + /** + * Stub for future + * + * @return null + */ + private String stateChanged() { + return null; + } - /** - * Stub for future - * - * @return null - */ - private String positionChanged() { - return null; - } + /** + * Stub for future + * + * @return null + */ + private String positionChanged() { + return null; + } - /** - * Disable and enable dragging in the application. It should be available - * only during video playing - * - * @param activate - * : activates dragging - * @return null, because it is a notification - */ - private String setDragState(boolean activate) { - if (activate) { - // allow dragging only if dragging video - WebViewUtils.setOnTouchListener(mActivity, - WebViewUtils.NONBLOCKING_ACTION_MOVE_MODE); - } else { - // disable dragging when stop scrolling video - WebViewUtils.setOnTouchListener(mActivity, - WebViewUtils.BLOCKING_ACTION_MOVE_MODE); - } - return null; - } + /** + * Disable and enable dragging in the application. It should be available + * only during video playing + * + * @param activate : activates dragging + * @return null, because it is a notification + */ + private String setDragState(boolean activate) { + if (activate) { + // allow dragging only if dragging video + WebViewUtils.setOnTouchListener(mActivity, + WebViewUtils.NONBLOCKING_ACTION_MOVE_MODE); + } else { + // disable dragging when stop scrolling video + WebViewUtils.setOnTouchListener(mActivity, + WebViewUtils.BLOCKING_ACTION_MOVE_MODE); + } + return null; + } - /** - * Check if file exists on SD card. - * - * @param fileName - * : file name - * @return true if file exists and false otherwise. - */ - public boolean isFileExist(String fileName) { - if (fileName == null || "".equals(fileName.trim())) { - return false; - } - try { + /** + * Check if file exists on SD card. + * + * @param fileName : file name + * @return true if file exists and false otherwise. + */ + public boolean isFileExist(String fileName) { + if (fileName == null || "".equals(fileName.trim())) { + return false; + } + try { - File file = ExtStorageUtils.getFileOnSDCard(mActivity, - fileName.toLowerCase()); - return file.exists(); - } catch (SDCardException e) { - e.printStackTrace(); - return false; - } - } + File file = ExtStorageUtils.getFileOnSDCard(mActivity, + fileName.toLowerCase()); + return file.exists(); + } catch (SDCardException e) { + e.printStackTrace(); + return false; + } + } - private void logMsg(String msg) { - if (DEBUG && Const.DEBUG) { - Log.i(TAG_NAME, msg); - } - } + private void logMsg(String msg) { + if (DEBUG && Const.DEBUG) { + Log.i(TAG_NAME, msg); + } + } } diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/jssupport/JavaScriptFacade.java b/native/android/avatar/src/main/java/com/ford/avarsdl/jssupport/JavaScriptFacade.java index f0bb511a91..3480733826 100644 --- a/native/android/avatar/src/main/java/com/ford/avarsdl/jssupport/JavaScriptFacade.java +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/jssupport/JavaScriptFacade.java @@ -4,7 +4,7 @@ import java.util.HashMap; import android.util.Log; -import com.ford.avarsdl.activity.AvatarActivity; +import com.ford.avarsdl.views.AvatarActivity; import com.ford.avarsdl.jsoncontroller.JSONAVAController; import com.ford.avarsdl.util.Const; diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/media/AvatarOnPreparedListener.java b/native/android/avatar/src/main/java/com/ford/avarsdl/media/AvatarOnPreparedListener.java index 76984fcbeb..a335bde2c0 100644 --- a/native/android/avatar/src/main/java/com/ford/avarsdl/media/AvatarOnPreparedListener.java +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/media/AvatarOnPreparedListener.java @@ -4,7 +4,7 @@ import android.media.MediaPlayer; import android.media.MediaPlayer.OnPreparedListener; import android.util.Log; -import com.ford.avarsdl.activity.AvatarActivity; +import com.ford.avarsdl.views.AvatarActivity; import com.ford.avarsdl.util.Const; public class AvatarOnPreparedListener implements OnPreparedListener { diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/requests/CancelAccessCommand.java b/native/android/avatar/src/main/java/com/ford/avarsdl/requests/CancelAccessCommand.java new file mode 100644 index 0000000000..eb92b6fcc9 --- /dev/null +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/requests/CancelAccessCommand.java @@ -0,0 +1,32 @@ +package com.ford.avarsdl.requests; + +import com.ford.avarsdl.service.SDLService; +import com.ford.avarsdl.util.Logger; +import com.ford.syncV4.proxy.SyncProxyALM; +import com.ford.syncV4.proxy.rpc.CancelAccess; + +import org.json.JSONObject; + +/** + * Created with Android Studio. + * Author: Chernyshov Yuriy - Mobile Development + * Date: 11/26/13 + * Time: 11:41 AM + */ +public class CancelAccessCommand implements RequestCommand { + + @Override + public void execute(int id, JSONObject jsonParameters) { + SyncProxyALM proxy = SDLService.getProxyInstance(); + if (proxy != null) { + CancelAccess msg = new CancelAccess(); + msg.setCorrelationID(id); + try { + //Logger.d(getClass().getSimpleName() + " Sending Cancel Access: " + jsonParameters); + proxy.sendRPCRequest(msg); + } catch (Throwable e) { + Logger.e(getClass().getSimpleName() + " can't send message", e); + } + } + } +}
\ No newline at end of file diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/requests/GrantAccessCommand.java b/native/android/avatar/src/main/java/com/ford/avarsdl/requests/GrantAccessCommand.java index dd335f3cb4..25f01a5998 100644 --- a/native/android/avatar/src/main/java/com/ford/avarsdl/requests/GrantAccessCommand.java +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/requests/GrantAccessCommand.java @@ -22,6 +22,7 @@ public class GrantAccessCommand implements RequestCommand { GrantAccess msg = new GrantAccess(); msg.setCorrelationID(id); try { + //Logger.d(getClass().getSimpleName() + " Sending Grant Access: " + jsonParameters); proxy.sendRPCRequest(msg); } catch (Throwable e) { Logger.e(getClass().getSimpleName() + " can't send message", e); diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/requests/TuneDownCommand.java b/native/android/avatar/src/main/java/com/ford/avarsdl/requests/TuneDownCommand.java new file mode 100644 index 0000000000..9fbdc1f3fc --- /dev/null +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/requests/TuneDownCommand.java @@ -0,0 +1,35 @@ +package com.ford.avarsdl.requests; + +import com.ford.avarsdl.service.SDLService; +import com.ford.avarsdl.util.Logger; +import com.ford.syncV4.exception.SyncException; +import com.ford.syncV4.proxy.SyncProxyALM; +import com.ford.syncV4.proxy.rpc.TuneDown; + +import org.json.JSONObject; + +/** + * Created with Android Studio. + * Author: Chernyshov Yuriy - Mobile Development + * Date: 11/28/13 + * Time: 12:26 PM + */ +public class TuneDownCommand implements RequestCommand { + + @Override + public void execute(int id, JSONObject jsonParameters) { + SyncProxyALM proxy = SDLService.getProxyInstance(); + if (proxy != null) { + TuneDown msg = new TuneDown(); + msg.setCorrelationID(id); + + try { + proxy.sendRPCRequest(msg); + } catch (SyncException e) { + Logger.e(getClass().getSimpleName() + " can't send message", e); + } + } else { + Logger.e(getClass().getSimpleName() + " proxy is NULL"); + } + } +}
\ No newline at end of file diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/requests/TuneRadioCommand.java b/native/android/avatar/src/main/java/com/ford/avarsdl/requests/TuneRadioCommand.java index 5dd6b0d6d2..a9ea9f8706 100644 --- a/native/android/avatar/src/main/java/com/ford/avarsdl/requests/TuneRadioCommand.java +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/requests/TuneRadioCommand.java @@ -1,6 +1,5 @@ package com.ford.avarsdl.requests; -import com.ford.avarsdl.business.MainApp; import com.ford.avarsdl.service.SDLService; import com.ford.avarsdl.util.Logger; import com.ford.syncV4.exception.SyncException; diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/requests/TuneUpCommand.java b/native/android/avatar/src/main/java/com/ford/avarsdl/requests/TuneUpCommand.java new file mode 100644 index 0000000000..aaa71c2d72 --- /dev/null +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/requests/TuneUpCommand.java @@ -0,0 +1,36 @@ +package com.ford.avarsdl.requests; + +import com.ford.avarsdl.service.SDLService; +import com.ford.avarsdl.util.Logger; +import com.ford.syncV4.exception.SyncException; +import com.ford.syncV4.proxy.SyncProxyALM; +import com.ford.syncV4.proxy.rpc.TuneUp; + +import org.json.JSONObject; + +/** + * Created with Android Studio. + * Author: Chernyshov Yuriy - Mobile Development + * Date: 11/28/13 + * Time: 12:24 PM + */ +public class TuneUpCommand implements RequestCommand { + + @Override + public void execute(int id, JSONObject jsonParameters) { + SyncProxyALM proxy = SDLService.getProxyInstance(); + if (proxy != null) { + TuneUp msg = new TuneUp(); + msg.setCorrelationID(id); + + try { + //Logger.d(getClass().getSimpleName() + "Sending Tune Up: " + jsonParameters); + proxy.sendRPCRequest(msg); + } catch (SyncException e) { + Logger.e(getClass().getSimpleName() + " can't send message", e); + } + } else { + Logger.e(getClass().getSimpleName() + " proxy is NULL"); + } + } +}
\ No newline at end of file diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/responses/CancelAccessResponse.java b/native/android/avatar/src/main/java/com/ford/avarsdl/responses/CancelAccessResponse.java new file mode 100644 index 0000000000..391c755528 --- /dev/null +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/responses/CancelAccessResponse.java @@ -0,0 +1,24 @@ +package com.ford.avarsdl.responses; + +import com.ford.avarsdl.jsoncontroller.JSONController; +import com.ford.avarsdl.util.Logger; +import com.ford.avarsdl.util.RPCConst; + +/** + * Created with Android Studio. + * Author: Chernyshov Yuriy - Mobile Development + * Date: 11/29/13 + * Time: 2:34 PM + */ +public class CancelAccessResponse extends JSONController implements ResponseCommand { + + public CancelAccessResponse() { + super(RPCConst.CN_REVSDL); + } + + @Override + public void execute(int id, String result) { + //Logger.d(getClass().getSimpleName() + " id: " + id + ", result: " + result); + sendResponse(id, result); + } +}
\ No newline at end of file diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/service/SDLService.java b/native/android/avatar/src/main/java/com/ford/avarsdl/service/SDLService.java index c78178b936..eb17f98744 100644 --- a/native/android/avatar/src/main/java/com/ford/avarsdl/service/SDLService.java +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/service/SDLService.java @@ -1,15 +1,16 @@ package com.ford.avarsdl.service; import android.app.Service; +import android.bluetooth.BluetoothAdapter; import android.content.Intent; import android.content.SharedPreferences; import android.os.IBinder; +import android.util.Log; -import com.ford.avarsdl.activity.SafeToast; +import com.ford.avarsdl.views.SafeToast; import com.ford.avarsdl.notifications.NotificationCommand; import com.ford.avarsdl.notifications.NotificationCommandImpl; import com.ford.avarsdl.responses.ResponseCommand; -import com.ford.avarsdl.util.APIObjectsSimulator; import com.ford.avarsdl.util.Const; import com.ford.avarsdl.util.Logger; import com.ford.avarsdl.util.RPCConst; @@ -22,6 +23,7 @@ import com.ford.syncV4.proxy.rpc.AddCommandResponse; import com.ford.syncV4.proxy.rpc.AddSubMenuResponse; import com.ford.syncV4.proxy.rpc.AlertManeuverResponse; import com.ford.syncV4.proxy.rpc.AlertResponse; +import com.ford.syncV4.proxy.rpc.CancelAccessResponse; import com.ford.syncV4.proxy.rpc.ChangeRegistrationResponse; import com.ford.syncV4.proxy.rpc.CreateInteractionChoiceSetResponse; import com.ford.syncV4.proxy.rpc.DeleteCommandResponse; @@ -46,6 +48,7 @@ import com.ford.syncV4.proxy.rpc.OnHMIStatus; import com.ford.syncV4.proxy.rpc.OnKeyboardInput; import com.ford.syncV4.proxy.rpc.OnLanguageChange; import com.ford.syncV4.proxy.rpc.OnPermissionsChange; +import com.ford.syncV4.proxy.rpc.OnPresetsChanged; import com.ford.syncV4.proxy.rpc.OnRadioDetails; import com.ford.syncV4.proxy.rpc.OnSyncPData; import com.ford.syncV4.proxy.rpc.OnTBTClientState; @@ -107,10 +110,11 @@ public class SDLService extends Service implements IProxyListenerALM { @Override public int onStartCommand(Intent intent, int flags, int startId) { - Logger.d("onStartCommand " + intent + ", " + flags + ", " + startId); + Logger.d(getClass().getSimpleName() + " onStartCommand " + intent + ", " + flags + ", " + + startId); initializeCommandsHashTable(); - startProxy(); + startProxyIfNetworkConnected(); return START_STICKY; } @@ -124,17 +128,47 @@ public class SDLService extends Service implements IProxyListenerALM { @Override public IBinder onBind(Intent intent) { - Logger.d("onBind unsupported"); - // binding is not supported + Logger.d(getClass().getSimpleName() + " onBind, hash: " + hashCode()); return mBinder; } + private void startProxyIfNetworkConnected() { + final SharedPreferences prefs = getSharedPreferences(Const.PREFS_NAME, + MODE_PRIVATE); + final int transportType = prefs.getInt( + Const.PREFS_KEY_TRANSPORT_TYPE, + Const.PREFS_DEFAULT_TRANSPORT_TYPE); + + if (transportType == Const.KEY_BLUETOOTH) { + Logger.d(getClass().getSimpleName() + " ProxyService. onStartCommand(). Transport = Bluetooth."); + BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + if (bluetoothAdapter != null) { + if (bluetoothAdapter.isEnabled()) { + startProxy(); + } + } + } else { + //TODO: This code is commented out for simulator purposes + /* + Log.d(TAG, "ProxyService. onStartCommand(). Transport = WiFi."); + if (hasWiFiConnection() == true) { + Log.d(TAG, "ProxyService. onStartCommand(). WiFi enabled."); + startProxy(); + } else { + Log.w(TAG, + "ProxyService. onStartCommand(). WiFi is not enabled."); + } + */ + startProxy(); + } + } + private void startProxy() { - Logger.d("starting proxy"); + Logger.d(getClass().getSimpleName() + " Starting proxy ..."); - SharedPreferences prefs = getSharedPreferences(Const.PREFS_NAME, 0); - String ipAddressString = prefs.getString(Const.PREFS_KEY_IPADDR, Const.PREFS_DEFAULT_IPADDR); - int tcpPortInt = prefs.getInt(Const.PREFS_KEY_TCPPORT, Const.PREFS_DEFAULT_TCPPORT); + SharedPreferences sharedPreferences = getSharedPreferences(Const.PREFS_NAME, 0); + String ipAddressString = sharedPreferences.getString(Const.PREFS_KEY_IPADDR, Const.PREFS_DEFAULT_IPADDR); + int tcpPortInt = sharedPreferences.getInt(Const.PREFS_KEY_TCPPORT, Const.PREFS_DEFAULT_TCPPORT); SyncMsgVersion syncMsgVersion = new SyncMsgVersion(); syncMsgVersion.setMajorVersion(2); @@ -143,11 +177,23 @@ public class SDLService extends Service implements IProxyListenerALM { Vector<AppHMIType> appHMIType = new Vector<AppHMIType>(); appHMIType.add(AppHMIType.RADIO); + int transportType = sharedPreferences.getInt( + Const.PREFS_KEY_TRANSPORT_TYPE, + Const.PREFS_DEFAULT_TRANSPORT_TYPE); + try { - mSyncProxy = new SyncProxyALM(this, null, APPNAME, null, null, true, - appHMIType, syncMsgVersion, Language.EN_US, Language.EN_US, APPID, - null, false, false, 2, - new TCPTransportConfig(tcpPortInt, ipAddressString)); + if (transportType == Const.KEY_BLUETOOTH) { + Logger.i(getClass().getSimpleName() + " Start Bluetooth Proxy"); + mSyncProxy = new SyncProxyALM(this, null, APPNAME, null, null, true, + appHMIType, syncMsgVersion, Language.EN_US, Language.EN_US, APPID, + null, false, false, 2); + } else { + Logger.i(getClass().getSimpleName() + " Start WiFi Proxy"); + mSyncProxy = new SyncProxyALM(this, null, APPNAME, null, null, true, + appHMIType, syncMsgVersion, Language.EN_US, Language.EN_US, APPID, + null, false, false, 2, + new TCPTransportConfig(tcpPortInt, ipAddressString)); + } } catch (SyncException e) { Logger.e("Failed to start proxy", e); if (mSyncProxy == null) { @@ -443,9 +489,29 @@ public class SDLService extends Service implements IProxyListenerALM { } @Override + public void onCancelAccessResponse(CancelAccessResponse response) { + ResponseCommand command = new com.ford.avarsdl.responses.CancelAccessResponse(); + try { + byte serializeMethod = 2; + command.execute(response.getCorrelationID(), + response.serializeJSON(serializeMethod).toString()); + } catch (JSONException e) { + e.printStackTrace(); + Logger.e(getClass().getSimpleName() + " onCancelAccessResponse " + e); + } + } + + @Override public void onOnControlChanged(OnControlChanged notification) { - final String msg = "onControlChanged " + notification.getReason(); - SafeToast.showToastAnyThread(msg); + //SafeToast.showToastAnyThread("onControlChanged " + notification); + Logger.d(getClass().getSimpleName() + " onControlChanged " + notification); + NotificationCommand command = commandsHashTable.get(Names.OnControlChanged); + if (command != null) { + String method = RPCConst.CN_REVSDL + "." + Names.OnControlChanged; + command.execute(method, notification); + } else { + Logger.w(getClass().getSimpleName() + " NotificationCommand NULL"); + } } @Override @@ -474,6 +540,19 @@ public class SDLService extends Service implements IProxyListenerALM { } @Override + public void onOnPresetsChanged(OnPresetsChanged notification) { + //SafeToast.showToastAnyThread("OnPresetsChanged: " + notification); + + NotificationCommand command = commandsHashTable.get(Names.OnPresetsChanged); + if (command != null) { + String method = RPCConst.CN_REVSDL + "." + Names.OnPresetsChanged; + command.execute(method, notification); + } else { + Logger.w(getClass().getSimpleName() + " NotificationCommand NULL"); + } + } + + @Override public void onOnRadioDetails(OnRadioDetails notification) { // TODO: Expand notification information here final RadioStation radioStation = notification.getRadioStation(); @@ -518,7 +597,16 @@ public class SDLService extends Service implements IProxyListenerALM { } private void initializeCommandsHashTable() { - NotificationCommand command = new NotificationCommandImpl(); - commandsHashTable.put(Names.OnRadioDetails, command); + // TODO: Probably in the future version there will be differences between notification + // objects, but up to now they contain general information structure + + NotificationCommand onRadioDetailsNotification = new NotificationCommandImpl(); + commandsHashTable.put(Names.OnRadioDetails, onRadioDetailsNotification); + + NotificationCommand onControlChangedNotification = new NotificationCommandImpl(); + commandsHashTable.put(Names.OnControlChanged, onControlChangedNotification); + + NotificationCommand onPresetsChangedNotification = new NotificationCommandImpl(); + commandsHashTable.put(Names.OnPresetsChanged, onPresetsChangedNotification); } }
\ No newline at end of file diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/util/Const.java b/native/android/avatar/src/main/java/com/ford/avarsdl/util/Const.java index df16906e45..a3385bf989 100644 --- a/native/android/avatar/src/main/java/com/ford/avarsdl/util/Const.java +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/util/Const.java @@ -93,6 +93,12 @@ public class Const { public static final String PREFS_KEY_IPADDR = "ipAddr"; public static final String PREFS_KEY_TCPPORT = "tcpPort"; + public static final String PREFS_KEY_TRANSPORT_TYPE = "TransportType"; + public static final String TCP = "WiFi"; + public static final String BLUETOOTH = "Bluetooth"; + public static final int KEY_TCP = 1; + public static final int KEY_BLUETOOTH = 2; + public static final int PREFS_DEFAULT_TRANSPORT_TYPE = KEY_TCP; public static final String PREFS_DEFAULT_IPADDR = "10.10.0.1"; public static final Integer PREFS_DEFAULT_TCPPORT = 12345; diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/util/WebViewUtils.java b/native/android/avatar/src/main/java/com/ford/avarsdl/util/WebViewUtils.java index 4b4b92ec8f..43b37ec050 100644 --- a/native/android/avatar/src/main/java/com/ford/avarsdl/util/WebViewUtils.java +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/util/WebViewUtils.java @@ -16,7 +16,7 @@ import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; -import com.ford.avarsdl.activity.AvatarActivity; +import com.ford.avarsdl.views.AvatarActivity; import com.ford.avarsdl.jssupport.AvatarWebViewClient; import com.ford.avarsdl.jssupport.JavaScriptFacade; diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/views/AppSetupDialog.java b/native/android/avatar/src/main/java/com/ford/avarsdl/views/AppSetupDialog.java new file mode 100644 index 0000000000..c6ae3e66ec --- /dev/null +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/views/AppSetupDialog.java @@ -0,0 +1,106 @@ +package com.ford.avarsdl.views; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.view.View; +import android.widget.EditText; +import android.widget.RadioGroup; + +import com.ford.avarsdl.R; +import com.ford.avarsdl.service.SDLService; +import com.ford.avarsdl.util.Const; +import com.ford.avarsdl.util.Logger; + +/** + * Created with Android Studio. + * Author: Chernyshov Yuriy - Mobile Development + * Date: 11/28/13 + * Time: 4:11 PM + */ +public class AppSetupDialog extends DialogFragment { + + private static final String TITLE_KEY = "dialog_title"; + + public static AppSetupDialog newInstance(int title) { + AppSetupDialog appSetupDialog = new AppSetupDialog(); + Bundle bundle = new Bundle(); + bundle.putInt(TITLE_KEY, title); + appSetupDialog.setArguments(bundle); + return appSetupDialog; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + int title = getArguments().getInt(TITLE_KEY); + View dialogView = getActivity().getLayoutInflater().inflate(R.layout.sdl_settings, null); + final EditText ipAddressText = (EditText) dialogView.findViewById(R.id.sdl_ipAddr); + final EditText tcpPortText = (EditText) dialogView.findViewById(R.id.sdl_tcpPort); + final RadioGroup transportGroup = + (RadioGroup) dialogView.findViewById(R.id.selectprotocol_radioGroupTransport); + + ipAddressText.setEnabled(false); + tcpPortText.setEnabled(false); + + transportGroup + .setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(RadioGroup group, int checkedId) { + boolean transportOptionsEnabled = checkedId == R.id.selectprotocol_radioWiFi; + ipAddressText.setEnabled(transportOptionsEnabled); + tcpPortText.setEnabled(transportOptionsEnabled); + } + }); + + final SharedPreferences prefs = getActivity().getSharedPreferences(Const.PREFS_NAME, 0); + String ipAddressString = prefs.getString(Const.PREFS_KEY_IPADDR, Const.PREFS_DEFAULT_IPADDR); + int tcpPortInt = prefs.getInt(Const.PREFS_KEY_TCPPORT, Const.PREFS_DEFAULT_TCPPORT); + int transportType = prefs.getInt( + Const.PREFS_KEY_TRANSPORT_TYPE, + Const.PREFS_DEFAULT_TRANSPORT_TYPE); + + ipAddressText.setText(ipAddressString); + tcpPortText.setText(String.valueOf(tcpPortInt)); + + transportGroup.check(transportType == Const.KEY_TCP ? R.id.selectprotocol_radioWiFi : + R.id.selectprotocol_radioBT); + + return new AlertDialog.Builder(getActivity()) + .setTitle(title) + .setCancelable(false) + .setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + String ipAddressString = ipAddressText.getText().toString(); + int tcpPortInt; + try { + tcpPortInt = Integer.parseInt(tcpPortText.getText().toString()); + } catch (NumberFormatException e) { + Logger.i("Couldn't parse port number", e); + tcpPortInt = Const.PREFS_DEFAULT_TCPPORT; + } + int transportType = transportGroup.getCheckedRadioButtonId() == + R.id.selectprotocol_radioWiFi ? Const.KEY_TCP : + Const.KEY_BLUETOOTH; + + SharedPreferences.Editor prefsEditor = + getActivity().getSharedPreferences(Const.PREFS_NAME, 0).edit(); + prefsEditor.putString(Const.PREFS_KEY_IPADDR, ipAddressString); + prefsEditor.putInt(Const.PREFS_KEY_TCPPORT, tcpPortInt); + prefsEditor.putInt(Const.PREFS_KEY_TRANSPORT_TYPE, transportType); + prefsEditor.commit(); + + Intent intent = new Intent(getActivity().getApplicationContext(), SDLService.class); + getActivity().startService(intent); + } + } + ) + .setView(dialogView) + .create(); + } +}
\ No newline at end of file diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/views/AvatarActivity.java b/native/android/avatar/src/main/java/com/ford/avarsdl/views/AvatarActivity.java new file mode 100644 index 0000000000..19c6db1ef0 --- /dev/null +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/views/AvatarActivity.java @@ -0,0 +1,1097 @@ +package com.ford.avarsdl.views; + +import java.io.File; +import java.io.IOException; +import java.util.Timer; +import java.util.TimerTask; + +import android.app.Activity; +import android.app.DialogFragment; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.AssetFileDescriptor; +import android.content.res.AssetManager; +import android.graphics.Rect; +import android.media.AudioManager; +import android.media.MediaPlayer; +import android.os.Build; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.os.StrictMode; +import android.preference.PreferenceManager; +import android.util.DisplayMetrics; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.View; +import android.view.Window; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings.RenderPriority; +import android.webkit.WebView; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.RelativeLayout; +import android.widget.RelativeLayout.LayoutParams; + +import com.android.vending.expansion.zipfile.APKExpansionSupport; +import com.android.vending.expansion.zipfile.ZipResourceFile; + +import com.ford.avarsdl.R; +import com.ford.avarsdl.downloader.DownloaderClient; +import com.ford.avarsdl.downloader.XAPKFile; +import com.ford.avarsdl.exception.ExtensionFileException; +import com.ford.avarsdl.exception.MediaPlayerException; +import com.ford.avarsdl.jsoncontroller.JSONBackendController; +import com.ford.avarsdl.jsoncontroller.JSONRateController; +import com.ford.avarsdl.jsoncontroller.JSONRevSDLController; +import com.ford.avarsdl.jsoncontroller.JSONVideoController; +import com.ford.avarsdl.jsonserver.JSONServer; +import com.ford.avarsdl.media.AvatarOnPreparedListener; +import com.ford.avarsdl.rater.AppRater; +import com.ford.avarsdl.service.ISDLServiceConnection; +import com.ford.avarsdl.service.SDLService; +import com.ford.avarsdl.service.SDLServiceBinder; +import com.ford.avarsdl.service.SDLServiceConnectionProxy; +import com.ford.avarsdl.util.ActivityUtils; +import com.ford.avarsdl.util.Const; +import com.ford.avarsdl.util.ExtStorageUtils; +import com.ford.avarsdl.util.Logger; +import com.ford.avarsdl.util.MessageConst; +import com.ford.avarsdl.util.Utils; +import com.ford.avarsdl.util.WebViewUtils; +import com.ford.syncV4.proxy.interfaces.IProxyListenerALM; + +/** + * Title: AvatarActivity.java<br> + * Description: Main application activity, responsible for webview content load + * and video handling<br> + * + * @author vsaenko/Eugene Sagan + * @co-author Yuriy Chernyshov + */ +public class AvatarActivity extends Activity implements SurfaceHolder.Callback, + ISDLServiceConnection { + + private final static String APP_SETUP_DIALOG_TAG = "AppSetupDialogTag"; + private final SDLServiceConnectionProxy mSDLServiceConnectionProxy = new SDLServiceConnectionProxy(this); + private IProxyListenerALM mBoundSDLService; + + // for monkey testing + // adb shell monkey -p com.ford.avarsdl -v 100 + + public static Boolean fullscreenPreferenceChanged = false; + public static Boolean vehiclePreferenceChanged = false; + public static Boolean navigationPreferenceChanged = false; + + public static Boolean ratePreferenceEnabled; + + @Override + public void onStart() { + super.onStart(); + + Logger.i(getClass().getSimpleName() + " onStart "); + + if (mBoundSDLService != null) { + + } else { + bindSDLService(this, mSDLServiceConnectionProxy); + } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Logger.i(getClass().getSimpleName() + " onCreate, hash:" + hashCode()); + + // FIXME: the old code with new SDK crashes with + // android.os.NetworkOnMainThreadException + // this hotfix is a bad idea. Don't try this at home! + StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); + StrictMode.setThreadPolicy(policy); + + if (isFirstStart()) { + Intent intent = new Intent(this, EulaActivity.class); + startActivityForResult(intent, Const.REQUESTCODE_EULA); + } else { + startAvatarActivity(); + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == RESULT_OK && requestCode == Const.REQUESTCODE_EULA) { + startAvatarActivity(); + resumeAvatarActivity(); + } else { + finish(); + } + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) { + return true; + } + return super.onKeyDown(keyCode, event); + } + + @Override + public void onBackPressed() { + // do something on back. + this.moveTaskToBack(true); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.optionsmenu, menu); + return true; + } + + public void bindSDLService(Context context, SDLServiceConnectionProxy connectionProxy) { + Logger.i("BindStorageService(), connection proxy: " + connectionProxy); + context.bindService(new Intent(context, SDLService.class), connectionProxy, BIND_AUTO_CREATE); + } + + public void unbindSDLService(Context context, SDLServiceConnectionProxy connectionProxy) { + if (!connectionProxy.isConnected()) { + Logger.v("ServiceConnection is not connected, ignoring unbindService: " + connectionProxy); + return; + } + try { + Logger.i("Unbind Service(), connection proxy: " + connectionProxy); + context.unbindService(connectionProxy); + } catch (IllegalArgumentException iae) { + // sometimes this exception is still thrown, in spite of isConnected() check above + // simply ignore this exception + Logger.w("Unbind IllegalArgumentException: " + iae); + } catch (Exception e) { + Logger.e("Error unbinding from connection: " + connectionProxy, e); + } + } + + + public boolean onOptionsItemSelected(MenuItem item) { + final int itemId = item.getItemId(); + switch (itemId) { + case R.id.mnuQuit: + exitApp(); + break; + default: + break; + } + return false; + } + + private void exitApp() { + Logger.d("Exiting application"); + + finish(); + // the delay should be long enough, so that UnregisterAppInterface and + // EndSession messages are sent + new Timer().schedule(new TimerTask() { + @Override + public void run() { + android.os.Process.killProcess(android.os.Process.myPid()); + } + }, 2000); + } + + public boolean isFirstStart() { + // Commit according to REVSDL-116 + + /*SharedPreferences prefs = getSharedPreferences(Const.SHPREF_FIRST_LAUNCH, 0); + int previousCodeVersion = prefs.getInt(Const.SHPREF_PREVIOUS_CODE_VERSION, 0); + int currentCodeVersion = Utils.getAppVersionCode(this); + return previousCodeVersion < currentCodeVersion;*/ + + return false; + } + + public void surfaceCreated(SurfaceHolder holder) { + Logger.i("surface created"); + playVideo(holder); + } + + public void surfaceDestroyed(SurfaceHolder holder) { + Logger.i("surface destroyed"); + } + + // ============================================================= + // GETTERS + // ============================================================= + public WebView getWebView() { + return mWebView; + } + + public MediaPlayer getMediaPlayer() { + return mMediaPlayer; + } + + // get value from application settings + public Boolean getFullscreenStatus() { + return mPreferences.getBoolean("FULLSCREEN", true); + } + + // get value from application settings + public Boolean getMapsStatus() { + return mPreferences.getBoolean("MAPS", true); + } + + // get value from application settings + public String getVehicleStatus() { + return mPreferences.getString("VEHICLES", "Ford"); + } + + // get value from application settings + public Boolean getRateStatus() { + return mPreferences.getBoolean("RATE", true); + } + + // set value to application settings + public Boolean setMapsStatus(boolean value) { + SharedPreferences.Editor editor = mPreferences.edit(); + editor.putBoolean("MAPS", value); + editor.commit(); + return true; + } + + // set value to application settings + public boolean setVehicleStatus(String value) { + SharedPreferences.Editor editor = mPreferences.edit(); + editor.putString("VEHICLES", value); + editor.commit(); + return true; + } + + public double audioGetPosition() { + return mediaGetPosition(); + } + + public String getPathToDownloadedAudioFile(String fileName) { + final File file = new File(getExternalFilesDir(null), fileName + ".mp3"); + return file.getAbsolutePath(); + } + + public Handler getMainHandler() { + return handler; + } + + public int getVideoPausedPosition() { + return mVideoPauseTime; + } + + public double videoGetPosition() { + return mediaGetPosition(); + } + + public boolean videoWasPaused() { + return mVideoWasPaused; + } + + public boolean getVideoPlayed() { + return mVideoPlayed; + } + + public JSONVideoController getVideoController() { + return mVideoController; + } + + public boolean getVideoPrepared() { + return mVideoPrepared; + } + + public JSONBackendController getBEController() { + return mBEController; + } + + // setters + + public void setVideoPlayed(boolean value) { + mVideoPlayed = value; + } + + public void setVideoPrepared(boolean value) { + mVideoPrepared = value; + } + + // ============================================================== + // OTHER METHODS + // ============================================================== + + public void startVideoTimer() { + // start timer to send every N ms current time position of video + Logger.i("Start Timer"); + int N = 500; + + stopVideoTimer(); + + mVideoTimer = new Timer(); + TimerTask timerTask = new TimerTask() { + @Override + public void run() { + // current position in MP never reaches duration value + // check difference on 500 msec + if (mVideoPrepared) { + if ((mMediaPlayer.getDuration() - mMediaPlayer.getCurrentPosition()) < 500) + mVideoController.sendPositionNotification(mMediaPlayer.getDuration()); + else + mVideoController.sendPositionNotification(mMediaPlayer.getCurrentPosition()); + } + } + }; + mVideoTimer.schedule(timerTask, N, N); + } + + public void setProgresbarVisibility(boolean value) { + int v = value ? ProgressBar.VISIBLE : ProgressBar.GONE; + mProgressBar.setVisibility(v); + } + + // ===================================================================== + // private section + // ===================================================================== + + // private Context ctx; + + private MediaPlayer mMediaPlayer; + + private SharedPreferences mPreferences; + private WebView mWebView; + private SurfaceView mPreview; + private SurfaceHolder mHolder; + private ProgressBar mProgressBar; + private RelativeLayout mVideoLayout; + private ImageView mLogo; + + private int mSeekTo; + + private int mVideoWidth; + private int mVideoHeight; + private int mLeftMargin; + private int mTopMargin; + + private String mPath; + + private Animation mAnimationShow; + + // for JSON communication + private JSONServer mServerThread; + private JSONBackendController mBEController; + private JSONVideoController mVideoController; + + // for video time visualization + private Timer mVideoTimer;// timer to send notifications about current video + // time + private boolean mVideoWasPaused = false;// indicate if video was on paused + // before starting activity + private int mVideoPauseTime = 0;// time in msec when video was paused before + // starting activity + private boolean mVideoPlayed = false;// indicate if video played before + // starting activity + // to measure 5 seconds for splash screen; + private long mStartTime; + private boolean mVideoPrepared = false; // indicate that video in MP is + // prepared and timer can be started + + private AppRater mAppRater; + + private ZipResourceFile apkExpansionZipFile = null; + private Context mContext; + + private final Handler handler = new Handler() { + @Override + public void handleMessage(Message msg) { + + super.handleMessage(msg); + + switch (msg.what) { + + // /// VIDEO + case Const.VIDEO_START: + Logger.i("mMediaPlayer.play handler"); + Object[] obj = (Object[]) msg.obj; + String videoFile = (String) obj[0]; + Double scale = (Double) obj[1]; + int x = (Integer) obj[2]; + int y = (Integer) obj[3]; + videoViewResize(scale, y, x); + mPath = videoFile; + initVideoSurface(); + break; + case Const.VIDEO_PAUSE: + Logger.i("mMediaPlayer.pause handler"); + stopVideoTimer(); + if (mMediaPlayer != null) + mMediaPlayer.pause(); + mVideoWasPaused = true; + mVideoPauseTime = mMediaPlayer.getCurrentPosition(); + break; + case Const.VIDEO_SET_POSITION: + Double newPos = (Double) msg.obj * 1000; + newPos = newPos == 0 ? 1 : newPos; // because media player can + // not set zero value + if (mMediaPlayer != null) + mediaSetPosition(newPos); + break; + case Const.VIDEO_SET_POSITION_PAUSED: + newPos = (Double) msg.obj * 1000; + newPos = newPos == 0 ? 1 : newPos; // because media player can + // not set zero value + if (mMediaPlayer != null) + mediaSetPositionPaused(newPos); + break; + case Const.VIDEO_PLAY: + startVideoTimer(); + mVideoWasPaused = false; + Logger.i("mMediaPlayer.start case Const.VIDEO_PLAY"); + if (null != mMediaPlayer) { + mMediaPlayer.start(); + } else { + Logger.i("mMediaPlayer == null"); + } + break; + case Const.VIDEO_STOP: + mVideoLayout.setVisibility(View.INVISIBLE); + stopVideoTimer(); + releaseMediaPlayer(); + mVideoWidth = 0; + mVideoHeight = 0; + mLeftMargin = 0; + mTopMargin = 0; + mPath = null; + mVideoWasPaused = false; + mVideoPlayed = false; + mVideoPauseTime = 0; + break; + case Const.VIDEO_PLAY_AFTER_SCALE: + Logger.i("mMediaPlayer.play after scale handler"); + obj = (Object[]) msg.obj; + scale = (Double) obj[0]; + int left = (Integer) obj[1]; + int top = (Integer) obj[2]; + videoViewResize(scale, top, left); + initVideoSurface(); + break; + + case Const.CONTENT_CHECKER_START: + verifyContent(); + break; + + case Const.WEBVIEW_SHOW: + hideSplashScreen(); + setProgresbarVisibility(false); + mWebView.startAnimation(mAnimationShow); + mWebView.setVisibility(View.VISIBLE); + if (Const.DEBUG) { + long currTime = System.currentTimeMillis(); + String str = "Application loading time = " + String.valueOf(currTime - mStartTime); + Logger.i(str); + SafeToast.showToastAnyThread(str); + } + DialogFragment appSetupDialogFragment = AppSetupDialog.newInstance(R.string.app_setup_dialog_title); + appSetupDialogFragment.show(getFragmentManager(), APP_SETUP_DIALOG_TAG); + appSetupDialogFragment.setCancelable(false); + break; + + default: + break; + } + } + }; + + private void verifyContent() { + + removeOldVideoFiles(); + + // check main expansion file + int mainVersionCode = expFileIsDelivered(true); + + SharedPreferences prefs = getSharedPreferences( + Const.SHPREF_DOWNLOADER_PREFS, 0); + boolean mainMD5IsCalculated = prefs.getBoolean( + Const.SHPREF_MAIN_EXPFILE_VALID, false); + + // check patch expansion file + int patchVersionCode = expFileIsDelivered(false); + + boolean patchMD5IsCalculated = prefs.getBoolean( + Const.SHPREF_PATCH_EXPFILE_VALID, false); + + if (mainVersionCode > 0 && mainMD5IsCalculated + && (patchVersionCode > 0 || Const.PATCH_EXP_FILE_SIZE == 0) + && patchMD5IsCalculated) { + try { + apkExpansionZipFile = APKExpansionSupport + .getAPKExpansionZipFile(this, mainVersionCode, + patchVersionCode); + } catch (IOException e) { + Logger.e(e.getMessage(), e); + } + + } else { + // no expansion file + SharedPreferences.Editor editor = prefs.edit(); + if (editor != null) { + editor.putBoolean(Const.SHPREF_MAIN_EXPFILE_VALID, false); + editor.putBoolean(Const.SHPREF_PATCH_EXPFILE_VALID, false); + } + editor.commit(); + // create downloader client + new DownloaderClient(this, mainVersionCode, mainMD5IsCalculated, + patchVersionCode, patchMD5IsCalculated); + + } + + Utils.sendMessageToHandler(Const.WEBVIEW_SHOW, + MessageConst.NET_DOWNLOAD_FINISHED_SUCC, handler); + } + + /** + * checks if expansion file was downloaded previously + * + * @param isMain - is a main expansion file or a patch + * @return version code if file exists or 0 + */ + + private int expFileIsDelivered(boolean isMain) { + int codeVersion = Utils.getAppVersionCode(getApplicationContext()); + long size = isMain ? Const.MAIN_EXP_FILE_SIZE + : Const.PATCH_EXP_FILE_SIZE; + while (codeVersion > 0) { + XAPKFile xFile = new XAPKFile(isMain, codeVersion, size); + if (ExtStorageUtils.expansionFilesDelivered(mContext, xFile)) { + return codeVersion; + } + codeVersion--; + } + return codeVersion; + } + + public void setExpantionFile(ZipResourceFile file) { + apkExpansionZipFile = file; + } + + /** + * removes video files of MFTG 2, that is apart of expansion file + */ + private boolean removeOldVideoFiles() { + File oldVideoFilesDirectory = getExternalFilesDir(null); + if ((oldVideoFilesDirectory != null) && + oldVideoFilesDirectory.exists()) { + boolean success = true; + final File[] files = oldVideoFilesDirectory.listFiles(); + if (files != null) { + for (File file : files) { + success &= file.delete(); + } + return success; + } + } + Logger.i("Couldn't remove old video files"); + return false; + } + + @Override + protected void onPause() { + super.onPause(); + Logger.i(getClass().getSimpleName() + " onPause, hash:" + hashCode()); + if (!isFirstStart()) { + ActivityUtils.setAppIsForeground(false); + // switch of timer + stopVideoTimer(); + // remember last video position + if (mMediaPlayer != null) + mVideoPauseTime = mMediaPlayer.getCurrentPosition(); + // delete media player + releaseMediaPlayer(); + mVideoLayout.removeAllViews(); + } + } + + protected void onResume() { + super.onResume(); + Logger.i(getClass().getSimpleName() + " onResume, hash:" + hashCode()); + if (!isFirstStart()) { + resumeAvatarActivity(); + } + } + + private void startAvatarActivity() { + mStartTime = System.currentTimeMillis(); + mContext = this; + // Possible work around for market launches. See + // http://code.google.com/p/android/issues/detail?id=2373 + // for more details. Essentially, the market launches the main activity + // on top of other activities. + // we never want this to happen. Instead, we check if we are the root + // and if not, we finish. + if (!isTaskRoot()) { + final Intent intent = getIntent(); + final String intentAction = intent.getAction(); + if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && intentAction != null + && intentAction.equals(Intent.ACTION_MAIN)) { + Logger.w("Main Activity is not the root. Finishing Main Activity instead of launching."); + finish(); + return; + } + } + + mAppRater = new AppRater(this); + startRPCComponents(); + prepareMainView(); + WebViewUtils.initWebView(this); + initVideoSurface(); + } + + private void resumeAvatarActivity() { + ActivityUtils.setAppIsForeground(true); + + if (!fullscreenPreferenceChanged && !vehiclePreferenceChanged) + initVideoSurface(); // to init video after resuming but not + // after FullScreen or Vehicle changing + + if (mPreferences != null) { + if (fullscreenPreferenceChanged) { + fullscreenPreferenceChanged = false; + mBEController.sendFullScreenRequest(getFullscreenStatus()); + } + + if (vehiclePreferenceChanged) { + vehiclePreferenceChanged = false; + mBEController.sendVehicleNotification(getVehicleStatus()); + } + + if (navigationPreferenceChanged) { + navigationPreferenceChanged = false; + mBEController.sendHasMapsNotification(getMapsStatus()); + } + + if (mWebView.getUrl() == null) { + if (!loadContent()) { + SafeToast.showToastAnyThread(getString(R.string.toast_index_not_found)); + } + } + } + } + + @Override + protected void onDestroy() { + Logger.i(getClass().getSimpleName() + " onDestroy, hash:" + hashCode()); + + unbindSDLService(getBaseContext(), mSDLServiceConnectionProxy); + stopService(new Intent(this, SDLService.class)); + + if (!isFirstStart()) { + // switch of timer + stopVideoTimer(); + + releaseMediaPlayer(); + doCleanUp(); + // close JSON server + try { + if (mServerThread != null) + mServerThread.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + super.onDestroy(); + } + + /** + * Checks if the filename exists in the assets. + * + * @param assetFilename Filename without any prefix + * @return true if the file exists + */ + private boolean assetExists(final String assetFilename) { + AssetManager am = getResources().getAssets(); + try { + am.open(assetFilename); + } catch (IOException e) { + return false; + } + return true; + } + + private boolean loadContent() { + Logger.i("loadContent"); + boolean successful = false; + if (assetExists(Const.INDEX_PAGE)) { + mWebView.loadUrl(Const.WEB_MAIN_PAGE_PATH); + successful = true; + } + return successful; + } + + private void startRPCComponents() { + Logger.i(getClass().getSimpleName() + " Start RPC Components"); + + mServerThread = new JSONServer(); + mServerThread.setName("ServerThread"); + mServerThread.start(); + + // wait for a while + while (!mServerThread.isReady()) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + mBEController = new JSONBackendController(this); + mBEController.register(27); + // wait for a while + while (!mBEController.isRegistered()) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + mVideoController = new JSONVideoController(this); + mVideoController.register(28); + // wait for a while + while (!mVideoController.isRegistered()) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + JSONRateController mRateController = new JSONRateController(mAppRater); + mRateController.register(29); + // wait for a while + while (!mRateController.isRegistered()) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + JSONRevSDLController mRevSDLController = new JSONRevSDLController(); + mRevSDLController.register(30); + // wait for a while + while (!mRevSDLController.isRegistered()) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + private void prepareMainView() { + Logger.i("prepareMainView"); + setContentView(R.layout.main); + + mPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + Boolean fullScreen = getFullscreenStatus(); + mLogo = (ImageView) findViewById(R.id.logo); + Logger.i("mFullScreen is " + fullScreen.toString()); + if (fullScreen) { + RelativeLayout.LayoutParams params = new LayoutParams( + LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT); + mLogo.setLayoutParams(params); + // mLogo.setLayoutParams(params); + } else { + + RelativeLayout.LayoutParams params = new LayoutParams(800, 480); + params.addRule(RelativeLayout.CENTER_HORIZONTAL); + params.addRule(RelativeLayout.CENTER_VERTICAL); + mLogo.setLayoutParams(params); + } + mWebView = (WebView) findViewById(R.id.webView1); + mWebView.setWebChromeClient(new WebChromeClient()); + mWebView.getSettings().setRenderPriority(RenderPriority.HIGH); + // mWebView.getSettings().setLoadWithOverviewMode(true); + // mWebView.getSettings().setUseWideViewPort(true); + // mWebView.setInitialScale(10); + + mVideoLayout = (RelativeLayout) findViewById(R.id.videoLayout); + // set progress bar + mProgressBar = (ProgressBar) findViewById(R.id.pbProgress); + LayoutParams progressParams = (LayoutParams) mProgressBar + .getLayoutParams(); + double loaderHeight = Const.WEB_HEIGHT * getScale() * 0.07 * getWindowDensity(); + progressParams.height = (int) loaderHeight; + progressParams.width = progressParams.height; + double loaderVerticalCenter = getWindowHeight() * 0.5; + double loaderVerticalShift = Const.WEB_HEIGHT * getScale() * 0.5 * 0.41 * getWindowDensity(); + double top = (loaderVerticalCenter - 0.5 * loaderHeight) + loaderVerticalShift; + progressParams.topMargin = (int) Math.round(top); + mProgressBar.setLayoutParams(progressParams); + + mAnimationShow = AnimationUtils.loadAnimation(this, R.anim.show); + } + + private double getScale() { + double res = 1; + if (isFullScreen()) { + /** Calculate Scale Point */ + double scalePointW = (double) getWindowWidth() + / (double) Const.WEB_WIDTH / getWindowDensity(); + double scalePointH = (double) getWindowHeight() + / (double) Const.WEB_HEIGHT / getWindowDensity(); + /** Set calculated ScalePoint */ + res = (scalePointW >= scalePointH) ? scalePointH : scalePointW; + } else { + res /= getWindowDensity(); + } + return res; + } + + private boolean isFullScreen() { + SharedPreferences preferences = PreferenceManager + .getDefaultSharedPreferences(this.getApplicationContext()); + return preferences.getBoolean("FULLSCREEN", true); + } + + private Integer getWindowHeight() { + Integer height; + if ((Build.VERSION.SDK_INT > 10)/* && (Build.VERSION.SDK_INT < 14) */) { + // return height without tabs bar + Rect rectgle = new Rect(); + Window window = this.getWindow(); + window.getDecorView().getWindowVisibleDisplayFrame(rectgle); + height = rectgle.bottom; // height = - panel height + } else { + DisplayMetrics dm = new DisplayMetrics(); + this.getWindowManager().getDefaultDisplay().getMetrics(dm); + if (dm.heightPixels > dm.widthPixels) { + height = dm.widthPixels; + } else { + height = dm.heightPixels; + } + } + return height; + } + + private Integer getWindowWidth() { + Integer width; + DisplayMetrics dm = new DisplayMetrics(); + this.getWindowManager().getDefaultDisplay().getMetrics(dm); + if (dm.heightPixels > dm.widthPixels) { + width = dm.heightPixels; + } else { + width = dm.widthPixels; + } + return width; + } + + private void initVideoSurface() { + Logger.i("init surface"); + + mVideoLayout.setVisibility(View.INVISIBLE); + mVideoLayout.removeAllViews(); + + LayoutParams params = (LayoutParams) mVideoLayout.getLayoutParams(); + + params.height = mVideoHeight; + params.width = mVideoWidth; + params.leftMargin = mLeftMargin; + params.topMargin = mTopMargin; + + mVideoLayout.setLayoutParams(params); + mPreview = new SurfaceView(this); + + mVideoLayout.addView(mPreview); + mHolder = mPreview.getHolder(); + mHolder.addCallback(this); + mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); + mVideoLayout.forceLayout(); + mVideoLayout.setVisibility(View.VISIBLE); + + } + + private void hideSplashScreen() { + Logger.i("hide screen "); + mVideoLayout.setVisibility(View.VISIBLE); + mLogo.setVisibility(View.INVISIBLE); + } + + private double mediaGetPosition() { + // setIsGetPosition(true); + Logger.i("mediaGetPosition"); + // isDoubleSeek = true; + if (mMediaPlayer == null) { + return -1; + } + try { + return Utils + .getShortDouble(mMediaPlayer.getCurrentPosition() / 1000.0); + } catch (IllegalStateException e) { + Logger.e(e.getMessage(), e); + return -1; + } + } + + private void mediaSetPosition(double position) { + /* convert to milliseconds */ + // setIsGetPosition(false); + // position *= 1000; + mSeekTo = (int) position; + Logger.i("mediaSetPosition=" + position); + + try { + if (mSeekTo != 0) + mMediaPlayer.seekTo(mSeekTo); + } catch (IllegalStateException e) { + Logger.e(e.getMessage(), e); + } + } + + private void mediaSetPositionPaused(double position) { + /* convert to milliseconds */ + mSeekTo = (int) position; + + Logger.i("mediaSetPositionPaused=" + position); + + AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE); + audioManager.setStreamMute(AudioManager.STREAM_MUSIC, true); + try { + mMediaPlayer.seekTo(mSeekTo); + } catch (IllegalStateException e) { + Logger.e(e.getMessage(), e); + } + } + + private void releaseMediaPlayer() { + if (mMediaPlayer != null) { + mMediaPlayer.reset(); + mMediaPlayer.release(); + mMediaPlayer = null; + } + mVideoPrepared = false; + } + + private void videoViewResize(double scale, int top, int left) { + mVideoWidth = (int) (Const.ORIG_VIDEO_WIDTH * scale * getWindowDensity() - 1); + mVideoHeight = (int) (Const.ORIG_VIDEO_HEIGHT * scale * getWindowDensity() - 1); + mLeftMargin = (int) Math.round(left * getWindowDensity()); + mTopMargin = (int) Math.round(top * getWindowDensity()); + } + + private double getWindowDensity() { + DisplayMetrics dm = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getMetrics(dm); + return dm.density; + } + + private void playVideo(SurfaceHolder holder) { + Logger.i("playVideo"); + if (mPath != null) { + try { + if (mMediaPlayer != null) { + releaseMediaPlayer(); + } + // TODO : optimize MP instantiation + // Create a new media player and set the listeners + mMediaPlayer = new MediaPlayer(); + + initDatasourceWith(mPath); + + Logger.i("video file path : " + mPath); + + mMediaPlayer.setDisplay(holder); + + mMediaPlayer.setOnPreparedListener(new AvatarOnPreparedListener(this)); + mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); + + mMediaPlayer.prepare(); + } catch (Exception e) { + Logger.e("error: " + e.getMessage(), e); + // set duration of video + mVideoController.setVideoDuration(-1); + } + } else { + Logger.i("No video to play"); + } + } + + private void stopVideoTimer() { + if (mVideoTimer != null) { + mVideoTimer.cancel(); + mVideoTimer.purge(); + } + mVideoTimer = null; + } + + private void doCleanUp() { + mVideoWidth = 0; + mVideoHeight = 0; + if (mVideoLayout != null) + mVideoLayout.removeAllViews(); + mHolder = null; + mPreview = null; + mVideoWasPaused = false; + mVideoPauseTime = 0; + mVideoPlayed = false; + } + + private void initDatasourceWith(String fileName) + throws ExtensionFileException, MediaPlayerException { + + AssetFileDescriptor assetFileDescriptor; + // welcome orientation video is in raw resources + if (fileName.toLowerCase().compareTo(Const.WELCOME_VIDEO_FILE_NAME) == 0) { + + // Commit according to REVSDL-116 + //assetFileDescriptor = getResources().openRawResourceFd(R.raw.faq_welcome_orientation); + Logger.w("Welcome Video is disabled in current version"); + return; + + } else { + // get file from expansion archive + if (apkExpansionZipFile == null) { + throw new ExtensionFileException("Expansion zip file variable is not initialized"); + } + assetFileDescriptor = apkExpansionZipFile.getAssetFileDescriptor(fileName); + } + + if (assetFileDescriptor == null) { + throw new ExtensionFileException("Assert file descriptor for file: " + fileName + + " not found"); + } + + try { + mMediaPlayer.setDataSource(assetFileDescriptor.getFileDescriptor(), + assetFileDescriptor.getStartOffset(), + assetFileDescriptor.getLength()); + } catch (IllegalArgumentException e) { + throw new MediaPlayerException(e); + } catch (IllegalStateException e) { + throw new MediaPlayerException(e); + } catch (IOException e) { + throw new MediaPlayerException(e); + } + } + + @Override + public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { + } + + @Override + public void onSDLServiceConnected(SDLServiceBinder service) { + Logger.i("SDLService connected " + service); + + mBoundSDLService = service.getService(); + } + + @Override + public void onSDLServiceDisconnected() { + Logger.i("SDLService disconnected"); + + mBoundSDLService = null; + } +}
\ No newline at end of file diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/views/ConnectionTypeDialog.java b/native/android/avatar/src/main/java/com/ford/avarsdl/views/ConnectionTypeDialog.java new file mode 100644 index 0000000000..0ae6cf2419 --- /dev/null +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/views/ConnectionTypeDialog.java @@ -0,0 +1,17 @@ +package com.ford.avarsdl.views; + +import android.app.Dialog; +import android.content.Context; + +/** + * Created with Android Studio. + * Author: Chernyshov Yuriy - Mobile Development + * Date: 11/28/13 + * Time: 3:08 PM + */ +public class ConnectionTypeDialog extends Dialog { + + public ConnectionTypeDialog(Context context) { + super(context); + } +}
\ No newline at end of file diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/views/EulaActivity.java b/native/android/avatar/src/main/java/com/ford/avarsdl/views/EulaActivity.java new file mode 100644 index 0000000000..b27a41ced1 --- /dev/null +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/views/EulaActivity.java @@ -0,0 +1,32 @@ +package com.ford.avarsdl.views; + +import com.ford.avarsdl.R; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; + +public class EulaActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.eula); + Button btnAgree = (Button) findViewById(R.id.btnAgree); + Bundle extras = getIntent().getExtras(); + if (extras != null && !extras.getBoolean("firstStart")) { + btnAgree.setText("Done"); + } + btnAgree.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = getIntent(); + setResult(Activity.RESULT_OK, intent); + finish(); + } + }); + } +}
\ No newline at end of file diff --git a/native/android/avatar/src/main/java/com/ford/avarsdl/activity/SafeToast.java b/native/android/avatar/src/main/java/com/ford/avarsdl/views/SafeToast.java index a0ad493431..272b29fa06 100644 --- a/native/android/avatar/src/main/java/com/ford/avarsdl/activity/SafeToast.java +++ b/native/android/avatar/src/main/java/com/ford/avarsdl/views/SafeToast.java @@ -1,4 +1,4 @@ -package com.ford.avarsdl.activity; +package com.ford.avarsdl.views; import android.content.Context; import android.widget.Toast; diff --git a/native/android/avatar/src/main/res/layout/sdl_settings.xml b/native/android/avatar/src/main/res/layout/sdl_settings.xml index e4a2e4bd51..d0ad268357 100644 --- a/native/android/avatar/src/main/res/layout/sdl_settings.xml +++ b/native/android/avatar/src/main/res/layout/sdl_settings.xml @@ -1,56 +1,81 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="match_parent" - android:layout_height="match_parent"> + android:orientation="vertical" + android:padding="10dp" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <RadioGroup + android:id="@+id/selectprotocol_radioGroupTransport" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_marginBottom="20dp" + android:orientation="horizontal" > + + <RadioButton + android:id="@+id/selectprotocol_radioWiFi" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginRight="50dp" + android:text="@string/app_setup_protocol_wifi" /> + + <RadioButton + android:id="@+id/selectprotocol_radioBT" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:checked="true" + android:text="@string/app_setup_protocol_bluetooth" /> + </RadioGroup> <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_marginBottom="20dp" + android:layout_width="match_parent" + android:layout_height="wrap_content"> <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="5dp" - android:layout_marginRight="5dp" - android:text="@string/selectprotocol_ipAddress" - android:textAppearance="?android:attr/textAppearanceMedium"/> + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="5dp" + android:layout_marginRight="5dp" + android:text="@string/app_setup_protocol_ip_address" + android:textAppearance="?android:attr/textAppearanceMedium" /> <EditText - android:id="@+id/sdl_ipAddr" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginRight="5dp" - android:layout_weight="1" - android:ems="10" - android:inputType="text" - android:maxLength="15" - android:text="@string/selectprotocol_ipAddressDefault"/> + android:id="@+id/sdl_ipAddr" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginRight="5dp" + android:layout_weight="1" + android:ems="10" + android:inputType="text" + android:maxLength="15" + android:text="@string/app_setup_protocol_ip_address_default" /> </LinearLayout> <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content"> + android:layout_width="match_parent" + android:layout_height="wrap_content"> <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginLeft="5dp" - android:layout_marginRight="5dp" - android:text="@string/selectprotocol_tcpPort" - android:textAppearance="?android:attr/textAppearanceMedium"/> + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="5dp" + android:layout_marginRight="5dp" + android:text="@string/app_setup_protocol_tcp_port" + android:textAppearance="?android:attr/textAppearanceMedium" /> <EditText - android:id="@+id/sdl_tcpPort" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_marginRight="5dp" - android:layout_weight="1" - android:ems="10" - android:inputType="number" - android:maxLength="5" - android:text="@string/selectprotocol_tcpPortDefault"/> + android:id="@+id/sdl_tcpPort" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_marginRight="5dp" + android:layout_weight="1" + android:ems="10" + android:inputType="number" + android:maxLength="5" + android:text="@string/app_setup_protocol_tcp_port_default" /> </LinearLayout> </LinearLayout>
\ No newline at end of file diff --git a/native/android/avatar/src/main/res/raw/faq_welcome_orientation.mp4 b/native/android/avatar/src/main/res/raw/faq_welcome_orientation.mp4 Binary files differdeleted file mode 100644 index 07b2aaf2df..0000000000 --- a/native/android/avatar/src/main/res/raw/faq_welcome_orientation.mp4 +++ /dev/null diff --git a/native/android/avatar/src/main/res/values/strings.xml b/native/android/avatar/src/main/res/values/strings.xml index 712185c86e..0ea9e076f7 100644 --- a/native/android/avatar/src/main/res/values/strings.xml +++ b/native/android/avatar/src/main/res/values/strings.xml @@ -37,9 +37,12 @@ Download Complete.\nVideos are available to view. </string> - <string name="selectprotocol_ipAddress">IP Address:</string> - <string name="selectprotocol_ipAddressDefault">10.10.0.1</string> - <string name="selectprotocol_tcpPort">TCP Port:</string> - <string name="selectprotocol_tcpPortDefault">12345</string> + <string name="app_setup_dialog_title">Please set up application properties</string> + <string name="app_setup_protocol_ip_address">IP Address:</string> + <string name="app_setup_protocol_ip_address_default">10.10.0.1</string> + <string name="app_setup_protocol_tcp_port">TCP Port:</string> + <string name="app_setup_protocol_tcp_port_default">12345</string> + <string name="app_setup_protocol_wifi">WiFi</string> + <string name="app_setup_protocol_bluetooth">Bluetooth</string> </resources>
\ No newline at end of file diff --git a/native/android/avatar_test/src/com/ford/avatar/test/jsoncontroller/JSONAVAControllerTest.java b/native/android/avatar_test/src/com/ford/avatar/test/jsoncontroller/JSONAVAControllerTest.java index b3c17f9d03..b2ad105513 100644 --- a/native/android/avatar_test/src/com/ford/avatar/test/jsoncontroller/JSONAVAControllerTest.java +++ b/native/android/avatar_test/src/com/ford/avatar/test/jsoncontroller/JSONAVAControllerTest.java @@ -56,7 +56,7 @@ public class JSONAVAControllerTest extends TestCase { } /** - * Test method for {@link com.ford.avarsdl.jsoncontroller.JSONAVAController#JSONAVAController(com.ford.avarsdl.activity.AvatarActivity, java.lang.String)}. + * Test method for {@link com.ford.avarsdl.jsoncontroller.JSONAVAController#JSONAVAController(com.ford.avarsdl.views.AvatarActivity, java.lang.String)}. */ public final void testJSONAVAController() { JSONAVAController controller = new JSONAVAController(RPCConst.CN_AVATAR, mTcpStub); diff --git a/openxc_backend/README b/openxc_backend/README new file mode 100644 index 0000000000..51353d22a1 --- /dev/null +++ b/openxc_backend/README @@ -0,0 +1,20 @@ +Dependency libraries (need to install first and check their successfull installation): +- python 2.7 +- pip (http://www.pip-installer.org/en/latest/installing.html) +- openxc (http://python.openxcplatform.com/en/latest/installation.html) + +1. It is necessary to have appropriate firmware for the OpenXC (the one Chris creates with the name "vi-firmware-FORDBOARD-radiocontrols-20-11-13.bin") + +2. Once OpenXC connected to the USB need to be sure that all data transferring well (cammand "openxc-dump" http://python.openxcplatform.com/en/latest/tools/dump.html) + Be sure that only one connection with OpenXC via USB exists! (after successfull command line test close all terminals) + +3. Run Server.py with next parameter: + PYTHONUNBUFFERED=1 python ~/<path_to_file>/Server.py + + To be sure that OpenXC server works navigate to "openxc_backend/web_console" and run index.html + You should see "Server status:" panel at the left side and "Dump:" panel at rigth side with a data flow. + If there are no data flow, please be sure that at the terminal window where server was launched there are no errors (is there are errors - restart server) + + When server run with success please press "Stop" and close index.html page (as pointed in N2 it occupies connection) + +4. When HMI simulator run it automatically create connection to the server diff --git a/openxc_backend/installer.sh b/openxc_backend/installer.sh new file mode 100755 index 0000000000..ba758b87c6 --- /dev/null +++ b/openxc_backend/installer.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +echo "Check Python installation ..." +command -v python >/dev/null 2>&1 || { echo >&2 "Python is not installed. Installing Python now ..."; +sudo apt-get install python; } +echo " Python is installed" + +echo "Check Python Pip installation ..." +command -v python-pip >/dev/null 2>&1 || { echo >&2 "Python Pip is not installed. Installing Python Pip now ..."; +sudo apt-get install python-pip; } +echo " Python Pip is installed" + +echo "Check OpenXC installation ..." +command -v openxc-control version >/dev/null 2>&1 || { echo >&2 " OpenXC is not installed. Installing OpenXC now ..."; +sudo pip install -U openxc; } +echo " OpenXC is installed" + +echo "Installing Tornado ..." +sudo pip install tornado --upgrade +echo " Tornado is installed" diff --git a/openxc_backend/server/Server.py b/openxc_backend/server/Server.py index 5c9bc9bb12..02b4bc2cbd 100644 --- a/openxc_backend/server/Server.py +++ b/openxc_backend/server/Server.py @@ -23,6 +23,8 @@ class MainHandler(WebSocketHandler): print "Socket message: " + message openxc_command = "" + if message.startswith("stop_server"): + return if message.startswith("set_preset_"): #print ("Set Preset", message[11:]) openxc_command = 'openxc-control write --name tune --value preset --event ' + message[11:] @@ -59,8 +61,13 @@ class MainHandler(WebSocketHandler): print "Socket close" def line_from_net_tail(self, data): - self.write_message(data) - self.stream.read_until("\n", self.line_from_net_tail) + try: + self.write_message(data) + self.stream.read_until("\n", self.line_from_net_tail) + except Exception: + self.p.terminate() + self.stream.close() + pass def open_dump_stream(self): self.p = subprocess.Popen(["openxc-dump"], stdout=subprocess.PIPE) diff --git a/openxc_backend/web_console/index.html b/openxc_backend/web_console/index.html index caf9eadc8b..467d62f956 100644 --- a/openxc_backend/web_console/index.html +++ b/openxc_backend/web_console/index.html @@ -8,7 +8,15 @@ </head> <body> <div style="width: 100%; height: 100%"> - <div style="width: 38%; height: 400px;float: left; background-color: gainsboro; padding: 10px"> + <div style="width: 10%; height: 400px;float: left; background-color: aliceblue; padding: 10px"> + <label>Server status:</label> + <label id="server_status_label">stopped</label> + <div style="margin-top: 10px"> + <button id="server_start_btn">Start</button> + <button id="server_stop_btn">Stop</button> + </div> + </div> + <div style="width: 28%; height: 400px;float: left; background-color: gainsboro; padding: 10px"> <div> <label>Tuner Band:</label> <select id="tuner_band_select"> diff --git a/openxc_backend/web_console/js/index.js b/openxc_backend/web_console/js/index.js index 1f8c1f9efb..f90d625520 100644 --- a/openxc_backend/web_console/js/index.js +++ b/openxc_backend/web_console/js/index.js @@ -1,3 +1,4 @@ +var socketURL = "localhost:9092"; var socket; var Socket = { webSocket: null, @@ -7,10 +8,12 @@ var Socket = { ws.onopen = function () { console.log('Socket opened at ' + url); + $("#server_status_label").html("running ..."); }; ws.onclose = function () { console.log('Socket close at ' + url); + $("#server_status_label").html("stopped"); }; ws.onmessage = function (e) { @@ -20,7 +23,7 @@ var Socket = { }; this.webSocket = ws; - } + }, }; function parseMessage(message) { @@ -57,11 +60,20 @@ function updateDumpTextArea(message) { function init() { setListeners(); - Socket.init("localhost:9092"); + Socket.init(socketURL); socket = Socket.webSocket; } function setListeners() { + $('#server_start_btn').on('click', function() { + console.info("Start server"); + Socket.init(socketURL); + socket = Socket.webSocket; + }); + $('#server_stop_btn').on('click', function() { + console.info("Stop server"); + sendCommand("stop_server"); + }); $('#station_up_btn_id').on('click', function() { console.info("Station +"); sendCommand("station_up"); @@ -106,6 +118,11 @@ function sendCommand(command) { } } +window.onbeforeunload = function() { + Socket.onclose = function () {}; // disable onclose handler first + Socket.close() +}; + $(document).ready(function() { init(); });
\ No newline at end of file diff --git a/sdl b/sdl -Subproject 7acc9dd11e86c52907fb98ba82b90de30f19507 +Subproject 66256d76b80048b523027dc42d8cc7874c05256 diff --git a/web/src/app/controller/AppController.js b/web/src/app/controller/AppController.js index b6805f913c..828728d010 100644 --- a/web/src/app/controller/AppController.js +++ b/web/src/app/controller/AppController.js @@ -94,7 +94,7 @@ MFT.AppController = Em.Object.create({ * Show popup and close it after closeTime, if it exists * @param {number} closeTime time, after which the popup will close * @param {string} message, displaying message popup - * @param {string} callback function + * @param {function} callback function */ showPopup: function(elementId, closeTime, message, callback){ var self = this; @@ -155,13 +155,19 @@ MFT.AppController = Em.Object.create({ this.showPopup('SDLMessagesPopup', 2000, MFT.locale.label.view_sdl_messages_popup_driverControl); }, - changeAccessStatus: function(data) { + changeAccessStatus: function(method, data) { var self = this; if (data.success) { - this.set('sdlAccessStatus', true); - this.set('sdlControlStatus', 4); - this.showPopup('SDLMessagesPopup', 2000, MFT.locale.label.view_sdl_messages_popup_granted); + if (method == 'grant') { + this.set('sdlAccessStatus', true); + this.set('sdlControlStatus', 4); + this.showPopup('SDLMessagesPopup', 2000, MFT.locale.label.view_sdl_messages_popup_granted); + } else if (method == 'cancel') { + this.set('sdlAccessStatus', false); + this.set('sdlControlStatus', 1); + this.showPopup('SDLMessagesPopup', 2000, MFT.locale.label.view_sdl_messages_popup_driverControl); + } } else if(data.resultCode == 'REJECTED') { this.set('sdlControlStatus', 3); this.showPopup('SDLMessagesPopup', 2000, MFT.locale.label.view_sdl_messages_popup_denied, function () { diff --git a/web/src/app/controller/MediaController.js b/web/src/app/controller/MediaController.js index 61c8fc3e4e..f4f2bbc876 100644 --- a/web/src/app/controller/MediaController.js +++ b/web/src/app/controller/MediaController.js @@ -931,8 +931,7 @@ MFT.MediaController = Em.Object.create({ } MFT.FmModel.fm1.set('items', items); - - FFW.RevSDL.sendGetRadioDetailsRequest(); + FFW.RevSDL.sendShowRequest(); }, /** Player Next track event*/ @@ -1198,6 +1197,14 @@ MFT.MediaController = Em.Object.create({ } }, + tuneUp: function() { + FFW.RevSDL.tuneUp(); + }, + + tuneDown: function() { + FFW.RevSDL.tuneDown(); + }, + turnReplayHelpVideoOn: function(){ if ( MFT.helpMode ) { MFT.VideoPlayerController.start('ent_Replay'); diff --git a/web/src/app/view/media/radio/fmView.js b/web/src/app/view/media/radio/fmView.js index 6e453add96..e7ca251d42 100644 --- a/web/src/app/view/media/radio/fmView.js +++ b/web/src/app/view/media/radio/fmView.js @@ -192,7 +192,8 @@ MFT.FMView = Em.ContainerView.create(MFT.LoadableView,{ 'scanButton', 'optionsButton', 'directTuneButton', - 'sendRequestButton' + 'sendRequestButton', + 'tuneButtons' ], hdButton: MFT.Button.extend({ @@ -211,13 +212,13 @@ MFT.FMView = Em.ContainerView.create(MFT.LoadableView,{ onDown: false, icon: 'images/media/passiv_horiz_led.png', // Change Icon for HD State - onIconChange: function(){ - if(MFT.MediaController.get('isHDActive') && MFT.SettingsModel.isEnglish){ - this.set('icon', 'images/media/active_horiz_led.png'); - }else{ - this.set('icon', 'images/media/passiv_horiz_led.png'); - } - }.observes('MFT.MediaController.isHDActive'), +// onIconChange: function(){ +// if(MFT.MediaController.get('isHDActive') && MFT.SettingsModel.isEnglish){ +// this.set('icon', 'images/media/active_horiz_led.png'); +// }else{ +// this.set('icon', 'images/media/passiv_horiz_led.png'); +// } +// }.observes('MFT.MediaController.isHDActive'), disabledBinding: 'MFT.MediaController.isHDButtonActive' @@ -295,6 +296,33 @@ MFT.FMView = Em.ContainerView.create(MFT.LoadableView,{ disabled: function() { return (MFT.AppController.sdlControlStatus == 2); }.property('MFT.AppController.sdlControlStatus') + }), + + tuneButtons: Em.ContainerView.extend({ + elementId: 'media_fm_tuneButtons', + + childViews: [ + 'tuneDown', + 'tuneUp' + ], + + tuneUp: MFT.Button.extend({ + elementId: 'media_fm_tuneUpButton', + target: 'MFT.MediaController', + action: 'tuneUp', + onDown: false, + templateName: 'text', + text: '>>' + }), + + tuneDown: MFT.Button.extend({ + elementId: 'media_fm_tuneDownButton', + target: 'MFT.MediaController', + action: 'tuneDown', + onDown: false, + templateName: 'text', + text: '<<' + }) }) }) diff --git a/web/src/css/media.css b/web/src/css/media.css index b3b5199244..c8b62785e4 100644 --- a/web/src/css/media.css +++ b/web/src/css/media.css @@ -18,7 +18,7 @@ } #media_directTune { - z-index: 503; + z-index: 5; position: absolute; top: 290px; left: 165px; @@ -2199,4 +2199,22 @@ /* cancel scrollbar animation */ .cancelBarAnimation { -webkit-transition: none !important; +} + +#media_fm_tuneButtons { + margin: 4px 5px 0 5px; +} + +#media_fm_tuneButtons .ffw-button { + width: 60px; + height: 40px; + font-size: 22px; + text-align: center; + line-height: 40px; + display: inline-block; + vertical-align: top; + border: 1px solid #333; + border-radius: 3px; + position: relative; + margin: 0 4px; }
\ No newline at end of file diff --git a/web/src/ffw/RevSDLRPC.js b/web/src/ffw/RevSDLRPC.js index b4c7ff1ba7..9502301fb9 100644 --- a/web/src/ffw/RevSDLRPC.js +++ b/web/src/ffw/RevSDLRPC.js @@ -90,17 +90,34 @@ FFW.RevSDL = FFW.RPCObserver.create({ switch (response.id) { case this.GrantAccessRequestId: - MFT.AppController.changeAccessStatus(response.result); + MFT.AppController.changeAccessStatus('grant', response.result); break; -// case this.StartScanRequestId: -// MFT.MediaController.set('isFrequencyScan', response.result.success); -// break; -// case this.StopScanRequestId: -// MFT.MediaController.set('isFrequencyScan', !response.result.success); -// break; - case this.GetRadioDetailsRequestId: - MFT.MediaController.setSDLDirectTuneStation(response.result); - this.sendShowRequest(); + case this.CancelAccessRequestId: + MFT.AppController.changeAccessStatus('cancel', response.result); + break; + case this.StartScanRequestId: + if (!response.result.success) { + Em.Logger.error("Error StartScan request:" + response.result.resultCode); + } else { + MFT.MediaController.set('isFrequencyScan', response.result.success); + } + break; + case this.StopScanRequestId: + if (!response.result.success) { + Em.Logger.error("Error StopScan request:" + response.result.resultCode); + } else { + MFT.MediaController.set('isFrequencyScan', !response.result.success); + } + break; + case this.TuneUpRequestId: + if (!response.result.success) { + Em.Logger.error("Error TuneUp request:" + response.result.resultCode); + } + break; + case this.TuneDownRequestId: + if (!response.result.success) { + Em.Logger.error("Error TuneDown request:" + response.result.resultCode); + } break; } }, @@ -147,6 +164,8 @@ FFW.RevSDL = FFW.RPCObserver.create({ StartScanRequestId: -1, StopScanRequestId: -1, GetRadioDetailsRequestId: -1, + TuneUpRequestId: -1, + TuneDownRequestId: -1, /** * Sends a request for access to the management of HMI, through SDL interface @@ -227,13 +246,27 @@ FFW.RevSDL = FFW.RPCObserver.create({ /** * Stop frequency scan on head unit, through SDL interface **/ - sendGetRadioDetailsRequest: function(){ - this.GetRadioDetailsRequestId = this.client.generateId(); + tuneUp: function(){ + this.TuneUpRequestId = this.client.generateId(); + + var JSONMessage = { + "jsonrpc": "2.0", + "id": this.TuneUpRequestId, + "method": "RevSDL.TuneUp" + }; + this.client.send(JSONMessage); + }, + + /** + * Stop frequency scan on head unit, through SDL interface + **/ + tuneDown: function(){ + this.TuneDownRequestId = this.client.generateId(); var JSONMessage = { "jsonrpc": "2.0", - "id": this.GetRadioDetailsRequestId, - "method": "RevSDL.GetRadioDetails" + "id": this.TuneDownRequestId, + "method": "RevSDL.TuneDown" }; this.client.send(JSONMessage); }, diff --git a/web/src/images/common/car.png b/web/src/images/common/car.png Binary files differnew file mode 100644 index 0000000000..141c4f3c14 --- /dev/null +++ b/web/src/images/common/car.png diff --git a/web/src/images/common/car_red.png b/web/src/images/common/car_red.png Binary files differnew file mode 100644 index 0000000000..ee2b88ac27 --- /dev/null +++ b/web/src/images/common/car_red.png diff --git a/web/src/images/common/car_yellow.png b/web/src/images/common/car_yellow.png Binary files differnew file mode 100644 index 0000000000..b5f8fccc60 --- /dev/null +++ b/web/src/images/common/car_yellow.png diff --git a/web/src/images/common/header_bg_old.png b/web/src/images/common/header_bg_old.png Binary files differnew file mode 100644 index 0000000000..f2752149f0 --- /dev/null +++ b/web/src/images/common/header_bg_old.png diff --git a/web/src/images/common/phone.png b/web/src/images/common/phone.png Binary files differnew file mode 100644 index 0000000000..30590dba1d --- /dev/null +++ b/web/src/images/common/phone.png diff --git a/web/src/locale/eng.js b/web/src/locale/eng.js index 48e91bf9da..e6f4435c7f 100644 --- a/web/src/locale/eng.js +++ b/web/src/locale/eng.js @@ -382,7 +382,7 @@ MFT.eng = { view_media_presets: 'Presets', view_media_directTune: 'Direct Tune', view_media_browse: 'Browse', - view_media_grantAccess: 'Grant access', + view_media_grantAccess: 'Request access', view_media_cancelAccess: 'Cancel access', view_media_moreInfo_title: 'Song Information', |