package com.asha.md360player4android; import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.support.v4.util.SimpleArrayMap; import android.util.SparseArray; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.TextView; import android.widget.Toast; import com.asha.vrlib.MDDirectorCamUpdate; import com.asha.vrlib.MDVRLibrary; import com.asha.vrlib.model.MDHotspotBuilder; import com.asha.vrlib.model.MDPosition; import com.asha.vrlib.model.MDRay; import com.asha.vrlib.model.MDViewBuilder; import com.asha.vrlib.model.position.MDMutablePosition; import com.asha.vrlib.plugins.MDAbsPlugin; import com.asha.vrlib.plugins.MDWidgetPlugin; import com.asha.vrlib.plugins.hotspot.IMDHotspot; import com.asha.vrlib.plugins.hotspot.MDAbsHotspot; import com.asha.vrlib.plugins.hotspot.MDAbsView; import com.asha.vrlib.plugins.hotspot.MDSimpleHotspot; import com.asha.vrlib.plugins.hotspot.MDView; import com.asha.vrlib.texture.MD360BitmapTexture; import com.squareup.picasso.Picasso; import com.squareup.picasso.Target; import java.io.FileNotFoundException; import java.util.LinkedList; import java.util.List; import java.util.Locale; import static android.animation.PropertyValuesHolder.ofFloat; import static com.squareup.picasso.MemoryPolicy.NO_CACHE; import static com.squareup.picasso.MemoryPolicy.NO_STORE; /** * using MD360Renderer * * Created by hzqiujiadi on 16/1/22. * hzqiujiadi ashqalcn@gmail.com */ public abstract class MD360PlayerActivity extends Activity { private static final String TAG = "MD360PlayerActivity"; private static final SparseArray<String> sDisplayMode = new SparseArray<>(); private static final SparseArray<String> sInteractiveMode = new SparseArray<>(); private static final SparseArray<String> sProjectionMode = new SparseArray<>(); private static final SparseArray<String> sAntiDistortion = new SparseArray<>(); private static final SparseArray<String> sPitchFilter = new SparseArray<>(); static { sDisplayMode.put(MDVRLibrary.DISPLAY_MODE_NORMAL,"NORMAL"); sDisplayMode.put(MDVRLibrary.DISPLAY_MODE_GLASS,"GLASS"); sInteractiveMode.put(MDVRLibrary.INTERACTIVE_MODE_MOTION,"MOTION"); sInteractiveMode.put(MDVRLibrary.INTERACTIVE_MODE_TOUCH,"TOUCH"); sInteractiveMode.put(MDVRLibrary.INTERACTIVE_MODE_MOTION_WITH_TOUCH,"M & T"); sInteractiveMode.put(MDVRLibrary.INTERACTIVE_MODE_CARDBORAD_MOTION,"CARDBOARD M"); sInteractiveMode.put(MDVRLibrary.INTERACTIVE_MODE_CARDBORAD_MOTION_WITH_TOUCH,"CARDBOARD M&T"); sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_SPHERE,"SPHERE"); sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_DOME180,"DOME 180"); sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_DOME230,"DOME 230"); sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_DOME180_UPPER,"DOME 180 UPPER"); sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_DOME230_UPPER,"DOME 230 UPPER"); sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_STEREO_SPHERE_HORIZONTAL,"STEREO H SPHERE"); sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_STEREO_SPHERE_VERTICAL,"STEREO V SPHERE"); sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_PLANE_FIT,"PLANE FIT"); sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_PLANE_CROP,"PLANE CROP"); sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_PLANE_FULL,"PLANE FULL"); sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_MULTI_FISH_EYE_HORIZONTAL,"MULTI FISH EYE HORIZONTAL"); sProjectionMode.put(MDVRLibrary.PROJECTION_MODE_MULTI_FISH_EYE_VERTICAL,"MULTI FISH EYE VERTICAL"); sProjectionMode.put(CustomProjectionFactory.CUSTOM_PROJECTION_FISH_EYE_RADIUS_VERTICAL,"CUSTOM MULTI FISH EYE"); sAntiDistortion.put(1,"ANTI-ENABLE"); sAntiDistortion.put(0,"ANTI-DISABLE"); sPitchFilter.put(1,"FILTER PITCH"); sPitchFilter.put(0,"FILTER NOP"); } public static void startVideo(Context context, Uri uri){ start(context, uri, VideoPlayerActivity.class); } public static void startBitmap(Context context, Uri uri){ start(context, uri, BitmapPlayerActivity.class); } private static void start(Context context, Uri uri, Class<? extends Activity> clz){ Intent i = new Intent(context,clz); i.setData(uri); context.startActivity(i); } private MDVRLibrary mVRLibrary; // load resource from android drawable and remote url. private MDVRLibrary.IImageLoadProvider mImageLoadProvider = new ImageLoadProvider(); // load resource from android drawable only. private MDVRLibrary.IImageLoadProvider mAndroidProvider = new AndroidProvider(this); private List<MDAbsPlugin> plugins = new LinkedList<>(); private MDPosition logoPosition = MDMutablePosition.newInstance().setY(-8.0f).setYaw(-90.0f); private MDPosition[] positions = new MDPosition[]{ MDPosition.newInstance().setZ(-8.0f).setYaw(-45.0f), MDPosition.newInstance().setZ(-18.0f).setYaw(15.0f).setAngleX(15), MDPosition.newInstance().setZ(-10.0f).setYaw(-10.0f).setAngleX(-15), MDPosition.newInstance().setZ(-10.0f).setYaw(30.0f).setAngleX(30), MDPosition.newInstance().setZ(-10.0f).setYaw(-30.0f).setAngleX(-30), MDPosition.newInstance().setZ(-5.0f).setYaw(30.0f).setAngleX(60), MDPosition.newInstance().setZ(-3.0f).setYaw(15.0f).setAngleX(-45), MDPosition.newInstance().setZ(-3.0f).setYaw(15.0f).setAngleX(-45).setAngleY(45), MDPosition.newInstance().setZ(-3.0f).setYaw(0.0f).setAngleX(90), }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // no title requestWindowFeature(Window.FEATURE_NO_TITLE); // full screen getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); // set content view setContentView(R.layout.activity_md_using_surface_view); // init VR Library mVRLibrary = createVRLibrary(); final Activity activity = this; final List<View> hotspotPoints = new LinkedList<>(); hotspotPoints.add(findViewById(R.id.hotspot_point1)); hotspotPoints.add(findViewById(R.id.hotspot_point2)); SpinnerHelper.with(this) .setData(sDisplayMode) .setDefault(mVRLibrary.getDisplayMode()) .setClickHandler(new SpinnerHelper.ClickHandler() { @Override public void onSpinnerClicked(int index, int key, String value) { mVRLibrary.switchDisplayMode(MD360PlayerActivity.this, key); int i = 0; int size = key == MDVRLibrary.DISPLAY_MODE_GLASS ? 2 : 1; for (View point : hotspotPoints){ point.setVisibility(i < size ? View.VISIBLE : View.GONE); i++; } } }) .init(R.id.spinner_display); SpinnerHelper.with(this) .setData(sInteractiveMode) .setDefault(mVRLibrary.getInteractiveMode()) .setClickHandler(new SpinnerHelper.ClickHandler() { @Override public void onSpinnerClicked(int index, int key, String value) { mVRLibrary.switchInteractiveMode(MD360PlayerActivity.this, key); } }) .init(R.id.spinner_interactive); SpinnerHelper.with(this) .setData(sProjectionMode) .setDefault(mVRLibrary.getProjectionMode()) .setClickHandler(new SpinnerHelper.ClickHandler() { @Override public void onSpinnerClicked(int index, int key, String value) { mVRLibrary.switchProjectionMode(MD360PlayerActivity.this, key); } }) .init(R.id.spinner_projection); SpinnerHelper.with(this) .setData(sAntiDistortion) .setDefault(mVRLibrary.isAntiDistortionEnabled() ? 1 : 0) .setClickHandler(new SpinnerHelper.ClickHandler() { @Override public void onSpinnerClicked(int index, int key, String value) { mVRLibrary.setAntiDistortionEnabled(key != 0); } }) .init(R.id.spinner_distortion); findViewById(R.id.button_add_plugin).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { final int index = (int) (Math.random() * 100) % positions.length; MDPosition position = positions[index]; MDHotspotBuilder builder = MDHotspotBuilder.create(mImageLoadProvider) .size(4f,4f) .provider(0, activity, android.R.drawable.star_off) .provider(1, activity, android.R.drawable.star_on) .provider(10, activity, android.R.drawable.checkbox_off_background) .provider(11, activity, android.R.drawable.checkbox_on_background) .listenClick(new MDVRLibrary.ITouchPickListener() { @Override public void onHotspotHit(IMDHotspot hitHotspot, MDRay ray) { if (hitHotspot instanceof MDWidgetPlugin){ MDWidgetPlugin widgetPlugin = (MDWidgetPlugin) hitHotspot; widgetPlugin.setChecked(!widgetPlugin.getChecked()); } } }) .title("star" + index) .position(position) .status(0,1) .checkedStatus(10,11); MDWidgetPlugin plugin = new MDWidgetPlugin(builder); plugins.add(plugin); getVRLibrary().addPlugin(plugin); Toast.makeText(MD360PlayerActivity.this, "add plugin position:" + position, Toast.LENGTH_SHORT).show(); } }); findViewById(R.id.button_add_plugin_logo).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MDHotspotBuilder builder = MDHotspotBuilder.create(mImageLoadProvider) .size(4f,4f) .provider(activity, R.drawable.moredoo_logo) .title("logo") .position(logoPosition) .listenClick(new MDVRLibrary.ITouchPickListener() { @Override public void onHotspotHit(IMDHotspot hitHotspot, MDRay ray) { Toast.makeText(MD360PlayerActivity.this, "click logo", Toast.LENGTH_SHORT).show(); } }); MDAbsHotspot hotspot = new MDSimpleHotspot(builder); plugins.add(hotspot); getVRLibrary().addPlugin(hotspot); Toast.makeText(MD360PlayerActivity.this, "add plugin logo" , Toast.LENGTH_SHORT).show(); } }); findViewById(R.id.button_remove_plugin).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (plugins.size() > 0){ MDAbsPlugin plugin = plugins.remove(plugins.size() - 1); getVRLibrary().removePlugin(plugin); } } }); findViewById(R.id.button_remove_plugins).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { plugins.clear(); getVRLibrary().removePlugins(); } }); findViewById(R.id.button_add_hotspot_front).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MDHotspotBuilder builder = MDHotspotBuilder.create(mImageLoadProvider) .size(4f,4f) .provider(activity, R.drawable.moredoo_logo) .title("front logo") .tag("tag-front") .position(MDPosition.newInstance().setZ(-12.0f).setY(-1.0f)); MDAbsHotspot hotspot = new MDSimpleHotspot(builder); hotspot.rotateToCamera(); plugins.add(hotspot); getVRLibrary().addPlugin(hotspot); } }); findViewById(R.id.button_rotate_to_camera_plugin).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { IMDHotspot hotspot = getVRLibrary().findHotspotByTag("tag-front"); if (hotspot != null){ hotspot.rotateToCamera(); } } }); findViewById(R.id.button_add_md_view).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { TextView textView = new TextView(activity); textView.setBackgroundColor(0x55FFCC11); textView.setText("Hello world."); MDViewBuilder builder = MDViewBuilder.create() .provider(textView, 400/*view width*/, 100/*view height*/) .size(4, 1) .position(MDPosition.newInstance().setZ(-12.0f)) .title("md view") .tag("tag-md-text-view") ; MDAbsView mdView = new MDView(builder); plugins.add(mdView); getVRLibrary().addPlugin(mdView); } }); findViewById(R.id.button_update_md_view).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MDAbsView mdView = getVRLibrary().findViewByTag("tag-md-text-view"); if (mdView != null){ TextView textView = mdView.castAttachedView(TextView.class); textView.setText("Cheer up!"); textView.setBackgroundColor(0x8800FF00); mdView.invalidate(); } } }); findViewById(R.id.button_md_view_hover).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { View view = new HoverView(activity); view.setBackgroundColor(0x55FFCC11); MDViewBuilder builder = MDViewBuilder.create() .provider(view, 300/*view width*/, 200/*view height*/) .size(3, 2) .position(MDPosition.newInstance().setZ(-8.0f)) .title("md view") .tag("tag-md-text-view") ; MDAbsView mdView = new MDView(builder); mdView.rotateToCamera(); plugins.add(mdView); getVRLibrary().addPlugin(mdView); } }); final TextView hotspotText = (TextView) findViewById(R.id.hotspot_text); final TextView directorBriefText = (TextView) findViewById(R.id.director_brief_text); getVRLibrary().setEyePickChangedListener(new MDVRLibrary.IEyePickListener() { @Override public void onHotspotHit(IMDHotspot hotspot, long hitTimestamp) { String text = hotspot == null ? "nop" : String.format(Locale.CHINESE, "%s %fs", hotspot.getTitle(), (System.currentTimeMillis() - hitTimestamp) / 1000.0f ); hotspotText.setText(text); String brief = getVRLibrary().getDirectorBrief().toString(); directorBriefText.setText(brief); if (System.currentTimeMillis() - hitTimestamp > 5000){ getVRLibrary().resetEyePick(); } } }); findViewById(R.id.button_camera_little_planet).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MDDirectorCamUpdate cameraUpdate = getVRLibrary().updateCamera(); PropertyValuesHolder near = ofFloat("near", cameraUpdate.getNearScale(), -0.5f); PropertyValuesHolder eyeZ = PropertyValuesHolder.ofFloat("eyeZ", cameraUpdate.getEyeZ(), 18f); PropertyValuesHolder pitch = PropertyValuesHolder.ofFloat("pitch", cameraUpdate.getPitch(), 90f); PropertyValuesHolder yaw = PropertyValuesHolder.ofFloat("yaw", cameraUpdate.getYaw(), 90f); PropertyValuesHolder roll = PropertyValuesHolder.ofFloat("roll", cameraUpdate.getRoll(), 0f); startCameraAnimation(cameraUpdate, near, eyeZ, pitch, yaw, roll); } }); findViewById(R.id.button_camera_to_normal).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MDDirectorCamUpdate cameraUpdate = getVRLibrary().updateCamera(); PropertyValuesHolder near = ofFloat("near", cameraUpdate.getNearScale(), 0f); PropertyValuesHolder eyeZ = PropertyValuesHolder.ofFloat("eyeZ", cameraUpdate.getEyeZ(), 0f); PropertyValuesHolder pitch = PropertyValuesHolder.ofFloat("pitch", cameraUpdate.getPitch(), 0f); PropertyValuesHolder yaw = PropertyValuesHolder.ofFloat("yaw", cameraUpdate.getYaw(), 0f); PropertyValuesHolder roll = PropertyValuesHolder.ofFloat("roll", cameraUpdate.getRoll(), 0f); startCameraAnimation(cameraUpdate, near, eyeZ, pitch, yaw, roll); } }); SpinnerHelper.with(this) .setData(sPitchFilter) .setDefault(0) .setClickHandler(new SpinnerHelper.ClickHandler() { @Override public void onSpinnerClicked(int index, int key, String value) { MDVRLibrary.IDirectorFilter filter = key == 0 ? null : new MDVRLibrary.DirectorFilterAdatper() { @Override public float onFilterPitch(float input) { if (input > 70){ return 70; } if (input < -70){ return -70; } return input; } }; getVRLibrary().setDirectorFilter(filter); } }) .init(R.id.spinner_pitch_filter); } private ValueAnimator animator; private void startCameraAnimation(final MDDirectorCamUpdate cameraUpdate, PropertyValuesHolder... values){ if (animator != null){ animator.cancel(); } animator = ValueAnimator.ofPropertyValuesHolder(values).setDuration(2000); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float near = (float) animation.getAnimatedValue("near"); float eyeZ = (float) animation.getAnimatedValue("eyeZ"); float pitch = (float) animation.getAnimatedValue("pitch"); float yaw = (float) animation.getAnimatedValue("yaw"); float roll = (float) animation.getAnimatedValue("roll"); cameraUpdate.setEyeZ(eyeZ).setNearScale(near).setPitch(pitch).setYaw(yaw).setRoll(roll); } }); animator.start(); } abstract protected MDVRLibrary createVRLibrary(); public MDVRLibrary getVRLibrary() { return mVRLibrary; } @Override protected void onResume() { super.onResume(); mVRLibrary.onResume(this); } @Override protected void onPause() { super.onPause(); mVRLibrary.onPause(this); } @Override protected void onDestroy() { super.onDestroy(); mVRLibrary.onDestroy(); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mVRLibrary.onOrientationChanged(this); } protected Uri getUri() { Intent i = getIntent(); if (i == null || i.getData() == null){ return null; } return i.getData(); } public void cancelBusy(){ findViewById(R.id.progress).setVisibility(View.GONE); } public void busy(){ findViewById(R.id.progress).setVisibility(View.VISIBLE); } // android impl private class AndroidProvider implements MDVRLibrary.IImageLoadProvider { Activity activity; public AndroidProvider(Activity activity) { this.activity = activity; } @Override public void onProvideBitmap(Uri uri, MD360BitmapTexture.Callback callback) { try { Bitmap bitmap = BitmapFactory.decodeStream(activity.getContentResolver().openInputStream(uri)); callback.texture(bitmap); } catch (FileNotFoundException e) { e.printStackTrace(); } } } // picasso impl private class ImageLoadProvider implements MDVRLibrary.IImageLoadProvider{ private SimpleArrayMap<Uri,Target> targetMap = new SimpleArrayMap<>(); @Override public void onProvideBitmap(final Uri uri, final MD360BitmapTexture.Callback callback) { final Target target = new Target() { @Override public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { // texture callback.texture(bitmap); targetMap.remove(uri); } @Override public void onBitmapFailed(Drawable errorDrawable) { targetMap.remove(uri); } @Override public void onPrepareLoad(Drawable placeHolderDrawable) { } }; targetMap.put(uri, target); Picasso.with(getApplicationContext()).load(uri).resize(callback.getMaxTextureSize(),callback.getMaxTextureSize()).onlyScaleDown().centerInside().memoryPolicy(NO_CACHE, NO_STORE).into(target); } } }