Skip to content

gdgfresno/androidify-yourself

 
 

Repository files navigation

Androidify Yourself app for GDG event

screenshot

Click here for this particular app's companion conference website to see your submitted avatar

Slides

https://speakerdeck.com/larchaon/androidify-yourself

GDG Riga event link

G+ event link

Basic Functionality

  • Download and start sample application from "empty" git branch
  • Change Application name to "Androidify Yourself!"
  • Rename helloworld.xml layout to main.xml
  • Split screen into parts
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:weightSum="130">

<TextView
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="20"
    android:text="Create your Android" />

    ....

</LinearLayout>
  • Add Layout with Android parts selectors
<LinearLayout
    android:layout_weight="90"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:padding="1dp"
    android:orientation="vertical"
    android:background="@drawable/border">

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPagerHead"
        android:layout_weight="30"
        android:layout_width="match_parent"
        android:layout_height="0dp" />

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPagerBody"
        android:layout_weight="30"
        android:layout_width="match_parent"
        android:layout_height="0dp" />

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPagerLegs"
        android:layout_weight="30"
        android:layout_width="match_parent"
        android:layout_height="0dp" />
</LinearLayout>
  • Bind Views in MainActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.helloworld);

    ViewPager headViewPager = (ViewPager) findViewById(R.id.viewPagerHead);
    ViewPager bodyViewPager = (ViewPager) findViewById(R.id.viewPagerBody);
    ViewPager legsViewPager = (ViewPager) findViewById(R.id.viewPagerLegs);
    ....
}
  • Create AndroidifyViewPagerAdapter
public class AndroidifyViewPagerAdapter extends FragmentPagerAdapter {

    private List<Integer> imgIds;

    public AndroidifyViewPagerAdapter(FragmentManager fm, List<Integer> imgIds) {
        super(fm);
        this.imgIds = imgIds;
    }

    @Override
    public Fragment getItem(int position) {
        ...
    }

    @Override
    public int getCount() {
        return imgIds.size();
    }
}
  • Create AndroidifyViewPagerItemFragment
public class AndroidifyViewPagerItemFragment extends Fragment {

    private int imgId;

    public AndroidifyViewPagerItemFragment(int imgId) {
        this.imgId = imgId;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        ....
    }
}
  • Create androidify_part.xml layout
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent">

     <ImageView
         android:id="@+id/android_part"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
 </LinearLayout>
  • Add View inflating in AndroidifyViewPagerItemFragment onCreateView()
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.androidify_part, container, false);
    ImageView imageView = (ImageView) rootView.findViewById(R.id.android_part);
    imageView.setImageResource(imgId);
    return rootView;
}
  • Add Fragment creating in AndroidifyViewPagerAdapter getItem(int position)
@Override
public Fragment getItem(int position) {
    return new AndroidifyViewPagerItemFragment(imgIds.get(position));
}
  • Extend MainActivity from android.support.v4.app.FragmentActivity
  • Set Adapter to ViewPagers in MainActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.helloworld);

    ViewPager headViewPager = (ViewPager) findViewById(R.id.viewPagerHead);
    ViewPager bodyViewPager = (ViewPager) findViewById(R.id.viewPagerBody);
    ViewPager legsViewPager = (ViewPager) findViewById(R.id.viewPagerLegs);

    FragmentManager fm = getSupportFragmentManager();
    headViewPager.setAdapter(new AndroidifyViewPagerAdapter(fm, AndroidDrawables.getHeads()));
    bodyViewPager.setAdapter(new AndroidifyViewPagerAdapter(fm, AndroidDrawables.getBodies()));
    legsViewPager.setAdapter(new AndroidifyViewPagerAdapter(fm, AndroidDrawables.getLegs()));
}
  • Create and register all Drawables
public class AndroidDrawables {

    private static final List<Integer> bodies = new ArrayList<Integer>(Arrays.asList(
        R.drawable.body1,
        R.drawable.body2,
        R.drawable.body3,
        R.drawable.body4,
        R.drawable.body5,
        R.drawable.body6,
        R.drawable.body7,
        R.drawable.body8,
        R.drawable.body9,
        R.drawable.body10,
        R.drawable.body11,
        R.drawable.body12,
        R.drawable.body13,
        R.drawable.body14,
        R.drawable.body15,
        R.drawable.body16,
        R.drawable.body17,
        R.drawable.body18,
        R.drawable.body19
    ));

    private static final List<Integer> heads = new ArrayList<Integer>(Arrays.asList(
        R.drawable.head1,
        R.drawable.head2,
        R.drawable.head3,
        R.drawable.head4,
        R.drawable.head5,
        R.drawable.head6,
        R.drawable.head7,
        R.drawable.head8,
        R.drawable.head9,
        R.drawable.head10,
        R.drawable.head11,
        R.drawable.head12,
        R.drawable.head13,
        R.drawable.head14,
        R.drawable.head15,
        R.drawable.head16,
        R.drawable.head17,
        R.drawable.head18,
        R.drawable.head19
    ));

    private static final List<Integer> legs = new ArrayList<Integer>(Arrays.asList(
        R.drawable.legs1,
        R.drawable.legs2,
        R.drawable.legs3,
        R.drawable.legs4,
        R.drawable.legs5,
        R.drawable.legs6,
        R.drawable.legs7,
        R.drawable.legs8,
        R.drawable.legs10,
        R.drawable.legs11,
        R.drawable.legs12,
        R.drawable.legs13,
        R.drawable.legs14,
        R.drawable.legs15,
        R.drawable.legs16,
        R.drawable.legs17,
        R.drawable.legs18,
        R.drawable.legs19
    ));

    public static List<Integer> getBodies() {
        return bodies;
    }

    public static List<Integer> getHeads() {
        return heads;
    }

    public static List<Integer> getLegs() {
        return legs;
    }
}

Bug fixes

  • Try to flip your device ;) Lets try to fix AndroidifyViewPagerItemFragment:
public class AndroidifyViewPagerItemFragment extends Fragment {

    public static final String IMG_ID = "IMG_ID";

    private int imgId;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if (savedInstanceState != null) {
            imgId = savedInstanceState.getInt(IMG_ID);
        }

        View rootView = inflater.inflate(R.layout.androidify_part, container, false);
        ImageView imageView = (ImageView) rootView.findViewById(R.id.android_part);
        imageView.setImageResource(imgId);
        return rootView;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        outState.putInt(IMG_ID, imgId);
    }

    public void setImgId(int imgId) {
        this.imgId = imgId;
    }
}
  • And fix getItem() in AndroidifyViewPagerAdapter
@Override
public Fragment getItem(int position) {
    AndroidifyViewPagerItemFragment fragment = new AndroidifyViewPagerItemFragment();
    fragment.setImgId(imgIds.get(position));
    return fragment;
}

Extended Functionality

  • Lets add a control panel in main.xml layout
<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:weightSum="3"
        android:layout_weight="20">

    <LinearLayout
            android:layout_width="0dp"
            android:layout_weight="1"
            android:gravity="center"
            android:layout_height="wrap_content">

        <ImageButton
                android:id="@+id/button_share"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:src="@drawable/android_icon"
                android:background="@null"
                android:adjustViewBounds="true"
                android:scaleType="centerInside" />
    </LinearLayout>

    <LinearLayout
            android:layout_width="0dp"
            android:layout_weight="1"
            android:gravity="center"
            android:layout_height="wrap_content">

        <ImageButton
                android:id="@+id/button_record_sound"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:src="@drawable/record_off"
                android:background="@null"
                android:adjustViewBounds="true"
                android:scaleType="centerInside" />
    </LinearLayout>

    <LinearLayout
            android:layout_width="0dp"
            android:layout_weight="1"
            android:gravity="center"
            android:layout_height="wrap_content">

        <ImageButton
                android:id="@+id/button_play_sound"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:src="@drawable/play"
                android:background="@null"
                android:adjustViewBounds="true"
                android:scaleType="centerInside" />
    </LinearLayout>
</LinearLayout>
  • Lets implement Androidify Share intent in MainActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    initShareButton(headViewPager, bodyViewPager, legsViewPager);
}

private void initShareButton(final ViewPager viewPagerHead, final ViewPager viewPagerBody, final ViewPager viewPagerLegs) {
    View shareButton = findViewById(R.id.button_share);
    shareButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            ...
        }
    });
}
  • Create BitmapUtils for creating an image Bitmap
public class BitmapUtils {

    public static Bitmap getBitmap(Resources resources, int drawableResourceId) {
        return BitmapFactory.decodeResource(resources,
                drawableResourceId);
    }

    public static Bitmap combineDrawables(Resources resources, int head, int body, int legs) {
        Bitmap headBitmap = getBitmap(resources, head);
        Bitmap bodyBitmap = getBitmap(resources, body);
        Bitmap legsBitmap = getBitmap(resources, legs);

        int height = headBitmap.getHeight() + bodyBitmap.getHeight() + legsBitmap.getHeight();
        int width = Math.max(headBitmap.getWidth(), Math.max(bodyBitmap.getWidth(), legsBitmap.getWidth()));

        Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas comboImage = new Canvas(result);
        comboImage.drawBitmap(headBitmap, 0f, 0f, null);
        comboImage.drawBitmap(bodyBitmap, 0f, headBitmap.getHeight(), null);
        comboImage.drawBitmap(legsBitmap, 0f, headBitmap.getHeight() + bodyBitmap.getHeight(), null);

        return result;
    }
}
  • Add share intent invocation onClick
private void initShareButton(final ViewPager viewPagerHead, final ViewPager viewPagerBody, final ViewPager viewPagerLegs) {
    View shareButton = findViewById(R.id.button_share);
    shareButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Integer head = AndroidDrawables.getHeads().get(viewPagerHead.getCurrentItem());
            Integer body = AndroidDrawables.getBodies().get(viewPagerBody.getCurrentItem());
            Integer legs = AndroidDrawables.getLegs().get(viewPagerLegs.getCurrentItem());

            Bitmap bitmap = BitmapUtils.combineDrawables(getResources(), head, body, legs);

            String imagePath = MediaStore.Images.Media.insertImage(getContentResolver(), bitmap, "Android Avatar", null);
            Uri imageURI = Uri.parse(imagePath);
            startShareActivity(imageURI);
        }
    });
}

private void startShareActivity(Uri imageURI) {
    Intent shareIntent = new Intent(Intent.ACTION_SEND);

    shareIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    shareIntent.putExtra(Intent.EXTRA_STREAM, imageURI);
    shareIntent.setType("image/png");

    startActivity(shareIntent);
}
  • Oops we have an exception. Lets fix it
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  • Next stop - sound recording. Create AndroidSoundRecorder
public class AndroidSoundRecorder {

    private MediaRecorder mediaRecorder;
    private String mFileName;

    public AndroidSoundRecorder(String mFileName) {
        this.mFileName = Environment.getExternalStorageDirectory().
                getAbsolutePath() + "/" + mFileName;
    }

    public void startRecording() {
        if (mediaRecorder != null) stopRecording();

        mediaRecorder = new MediaRecorder();
        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mediaRecorder.setOutputFile(mFileName);
        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
        mediaRecorder.setAudioSamplingRate(44100);
        mediaRecorder.setAudioEncodingBitRate(16);

        try {
            mediaRecorder.prepare();
        } catch (IOException e) {
            Log.e(AndroidSoundRecorder.class.getSimpleName(), "prepare() failed");
        }

        mediaRecorder.start();

    }

    public void stopRecording() {
        if (mediaRecorder == null) return;

        mediaRecorder.stop();
        mediaRecorder.release();
        mediaRecorder = null;
    }

    public boolean isRecording() {
        return mediaRecorder != null;
    }

}
  • Initiate RecordButton in MainActivity
...
private final String mySound = "my_recorded_sound";
private AndroidSoundRecorder soundRecorder;
...

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    initRecordButton();
}

private void initRecordButton() {
    soundRecorder = new AndroidSoundRecorder(mySound);

    View recordButton = findViewById(R.id.button_record_sound);
    recordButton.setOnTouchListener(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            ImageButton recordButton = (ImageButton) view;

            if (MotionEvent.ACTION_UP == motionEvent.getAction()) {
                if (soundRecorder.isRecording()) {
                    soundRecorder.stopRecording();
                    recordButton.setImageDrawable(getResources().getDrawable(R.drawable.record_off));
                } else {
                    soundRecorder.startRecording();
                    recordButton.setImageDrawable(getResources().getDrawable(R.drawable.record_on));
                }
            }

            return false;
        }
    });
}
  • Create AndroidSoundPlayer
public class AndroidSoundPlayer {

    private final String fileName;
    private MediaPlayer mediaPlayer;

    public AndroidSoundPlayer(String fileName) {
        this.fileName = Environment.getExternalStorageDirectory().
                getAbsolutePath() + "/" + fileName;
    }

    public void startPlaying() {
        if (mediaPlayer != null) stopPlaying();

        mediaPlayer = new MediaPlayer();
        try {
            mediaPlayer.setDataSource(fileName);
            mediaPlayer.prepare();
            mediaPlayer.start();
        } catch (IOException e) {
            Log.e("SoundPlayer", "prepare() failed");
        }
    }

    public void stopPlaying() {
        if (mediaPlayer == null) return;
        mediaPlayer.release();
        mediaPlayer = null;
    }

    public boolean isPlaying() {
        return mediaPlayer != null && mediaPlayer.isPlaying();
    }
}
  • Initiate PlayButton in MainActivity
private AndroidSoundPlayer soundPlayer;
...

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    initPlayButton();
}

private void initPlayButton() {
    soundPlayer = new AndroidSoundPlayer(mySound);

    View playButton = findViewById(R.id.button_play_sound);
    playButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (soundPlayer.isPlaying()) {
                soundPlayer.stopPlaying();
            } else {
                soundPlayer.startPlaying();
            }
        }
    });
}
  • Add permission to AndroidManifest.xml
<uses-permission android:name="android.permission.RECORD_AUDIO"/>

About

Androidify Yourself app for 2017 Valley DevFest, based on the GDG Riga event app

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Java 100.0%