├── ic_launcher-web.png
├── Art
├── recorder_screen.png
└── recording_play.png
├── res
├── drawable-hdpi
│ ├── delete.png
│ ├── ico_mic.png
│ ├── share.png
│ ├── sort_list.png
│ ├── ic_launcher.png
│ ├── ic_action_next.png
│ ├── ic_action_play.png
│ ├── ic_action_stop.png
│ ├── ic_action_pause.png
│ ├── ic_action_previous.png
│ └── bg_gradient.xml
├── drawable-mdpi
│ ├── ico_mic.png
│ └── ic_launcher.png
├── drawable-xxhdpi
│ ├── ico_mic.png
│ └── ic_launcher.png
├── drawable-xhdpi
│ └── ic_launcher.png
├── values
│ ├── dimens.xml
│ ├── color.xml
│ ├── styles.xml
│ ├── attrs.xml
│ └── strings.xml
├── values-v11
│ └── styles.xml
├── values-w820dp
│ └── dimens.xml
├── values-v14
│ └── styles.xml
├── menu
│ └── main.xml
└── layout
│ ├── activity_main.xml
│ ├── swipe_layout_recording_list_item.xml
│ ├── record_audio_fragment.xml
│ └── recording_list_fragment.xml
├── .gitattributes
├── .classpath
├── .settings
└── org.eclipse.jdt.core.prefs
├── project.properties
├── proguard-project.txt
├── .project
├── src
└── com
│ └── serveroverload
│ └── recorder
│ ├── customview
│ ├── SimpleSwipeListener.java
│ ├── PlayerVisualizerView.java
│ ├── RecorderVisualizerView.java
│ └── SwipeLayout.java
│ ├── util
│ ├── Helper.java
│ ├── RecordingsLoaderTask.java
│ └── RecordingsListArrayAdapter.java
│ └── ui
│ ├── HomeActivity.java
│ ├── RecordingListFragment.java
│ └── RecordAudioFragment.java
├── .gitignore
├── README.md
└── AndroidManifest.xml
/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshsahu/Android-Audio-Recorder-Visualization-Master/HEAD/ic_launcher-web.png
--------------------------------------------------------------------------------
/Art/recorder_screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshsahu/Android-Audio-Recorder-Visualization-Master/HEAD/Art/recorder_screen.png
--------------------------------------------------------------------------------
/Art/recording_play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshsahu/Android-Audio-Recorder-Visualization-Master/HEAD/Art/recording_play.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshsahu/Android-Audio-Recorder-Visualization-Master/HEAD/res/drawable-hdpi/delete.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ico_mic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshsahu/Android-Audio-Recorder-Visualization-Master/HEAD/res/drawable-hdpi/ico_mic.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/share.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshsahu/Android-Audio-Recorder-Visualization-Master/HEAD/res/drawable-hdpi/share.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ico_mic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshsahu/Android-Audio-Recorder-Visualization-Master/HEAD/res/drawable-mdpi/ico_mic.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/sort_list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshsahu/Android-Audio-Recorder-Visualization-Master/HEAD/res/drawable-hdpi/sort_list.png
--------------------------------------------------------------------------------
/res/drawable-xxhdpi/ico_mic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshsahu/Android-Audio-Recorder-Visualization-Master/HEAD/res/drawable-xxhdpi/ico_mic.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshsahu/Android-Audio-Recorder-Visualization-Master/HEAD/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshsahu/Android-Audio-Recorder-Visualization-Master/HEAD/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshsahu/Android-Audio-Recorder-Visualization-Master/HEAD/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_action_next.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshsahu/Android-Audio-Recorder-Visualization-Master/HEAD/res/drawable-hdpi/ic_action_next.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_action_play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshsahu/Android-Audio-Recorder-Visualization-Master/HEAD/res/drawable-hdpi/ic_action_play.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_action_stop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshsahu/Android-Audio-Recorder-Visualization-Master/HEAD/res/drawable-hdpi/ic_action_stop.png
--------------------------------------------------------------------------------
/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshsahu/Android-Audio-Recorder-Visualization-Master/HEAD/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_action_pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshsahu/Android-Audio-Recorder-Visualization-Master/HEAD/res/drawable-hdpi/ic_action_pause.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_action_previous.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hiteshsahu/Android-Audio-Recorder-Visualization-Master/HEAD/res/drawable-hdpi/ic_action_previous.png
--------------------------------------------------------------------------------
/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
addSimpleSwipeListener method. When
10 | * the simpleSwipe event occurs, that object's appropriate
11 | * method is invoked.
12 | *
13 | * @see SimpleSwipeEvent
14 | */
15 | public class SimpleSwipeListener implements SwipeLayout.SwipeListener {
16 |
17 | @Override
18 | public void onStartOpen(SwipeLayout layout) {
19 | }
20 |
21 | @Override
22 | public void onOpen(SwipeLayout layout) {
23 | }
24 |
25 | @Override
26 | public void onStartClose(SwipeLayout layout) {
27 | }
28 |
29 | @Override
30 | public void onClose(SwipeLayout layout) {
31 | }
32 |
33 | @Override
34 | public void onUpdate(SwipeLayout layout, int leftOffset, int topOffset) {
35 | }
36 |
37 | @Override
38 | public void onHandRelease(SwipeLayout layout, float xvel, float yvel) {
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Audio Recorder Pro
5 | Hello world!
6 | Settings
7 | Exit
8 | Tap on mic icon to start recording, taping on stop icon will save file on SD card.
9 | \nIf recording was not good you can delete it by pressing delete icon and try again or you can delete and compare with other saved file by tapping on list icon.
10 | \nIf you think recording is up to your expectations you can share it with your friends from browsing list
11 | Audio Recorder
12 | Recording Started
13 | Recording Failed
14 | Failed to create recordings folder
15 | Recording Saved at
16 | Deleted recording
17 | Failed to delete recording
18 | ca-app-pub-9404626930613325/4259844699
19 | ca-app-pub-9404626930613325/5736577892
20 |
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 |
15 | # Gradle files
16 | .gradle/
17 | build/
18 | */build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # =========================
36 | # Operating System Files
37 | # =========================
38 |
39 | # OSX
40 | # =========================
41 |
42 | .DS_Store
43 | .AppleDouble
44 | .LSOverride
45 |
46 | # Thumbnails
47 | ._*
48 |
49 | # Files that might appear in the root of a volume
50 | .DocumentRevisions-V100
51 | .fseventsd
52 | .Spotlight-V100
53 | .TemporaryItems
54 | .Trashes
55 | .VolumeIcon.icns
56 |
57 | # Directories potentially created on remote AFP share
58 | .AppleDB
59 | .AppleDesktop
60 | Network Trash Folder
61 | Temporary Items
62 | .apdisk
63 |
64 | # Windows
65 | # =========================
66 |
67 | # Windows image file caches
68 | Thumbs.db
69 | ehthumbs.db
70 |
71 | # Folder config file
72 | Desktop.ini
73 |
74 | # Recycle Bin used on file shares
75 | $RECYCLE.BIN/
76 |
77 | # Windows Installer files
78 | *.cab
79 | *.msi
80 | *.msm
81 | *.msp
82 |
83 | # Windows shortcuts
84 | *.lnk
85 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Android-Audio-Recorder-Visualization-Master
2 | Audio recorder with visualization for audio recorder & player.
3 |
4 | This project display visualizer for audio recording as well as on recording playback screen.
5 |
6 | There is a option to share or delete recordings with the help of swipe layout.
7 |
8 | 
9 | 
10 |
11 | Feel free to play with controls on app or download it from playstore.
12 |
13 | This project's main purpose was to demonstarte use of :-
14 |
15 | 1) Audio recorder & Media player ApI of Android.
16 |
17 | 2) Display Visalizer for both recording and playback screens.
18 |
19 | 3) Create simplay music player to support play,pause,next previous and play on tap.
20 |
21 | 4) Use adMob SDK to show ad banners.
22 |
23 |
24 | Dependency:- Appcomat v7 and Google plays libraries
25 |
26 | Copyright 2015 Hitesh Kumar Sahu
27 |
28 | Licensed under the Apache License, Version 2.0 (the "License");
29 | you may not use this file except in compliance with the License.
30 | You may obtain a copy of the License at
31 |
32 | http://www.apache.org/licenses/LICENSE-2.0
33 |
34 | Unless required by applicable law or agreed to in writing, software
35 | distributed under the License is distributed on an "AS IS" BASIS,
36 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
37 | See the License for the specific language governing permissions and
38 | limitations under the License.
39 |
--------------------------------------------------------------------------------
/src/com/serveroverload/recorder/util/Helper.java:
--------------------------------------------------------------------------------
1 | package com.serveroverload.recorder.util;
2 |
3 | import java.io.File;
4 | import java.util.ArrayList;
5 |
6 | import android.content.Context;
7 | import android.os.Environment;
8 | import android.os.Vibrator;
9 |
10 | public class Helper {
11 |
12 | private static Helper helperInstance;
13 |
14 | private Helper() {
15 |
16 | }
17 |
18 | public static Helper getHelperInstance() {
19 |
20 | if (null == helperInstance) {
21 | helperInstance = new Helper();
22 | }
23 | return helperInstance;
24 |
25 | }
26 |
27 | public static final String RECORDING_PATH = Environment
28 | .getExternalStorageDirectory() + "/Recordings";
29 | public static final String LOAD_RECORDINGS = "Load Records";
30 |
31 | public void makeHepticFeedback(Context context) {
32 |
33 | ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE))
34 | .vibrate(100);
35 | }
36 |
37 | public ArrayList getAllFileInDirectory(File directory) {
38 |
39 | final File[] files = directory.listFiles();
40 | ArrayList listOfRecordings = new ArrayList();
41 |
42 | if (files != null) {
43 | for (File file : files) {
44 | if (file != null) {
45 | if (file.isDirectory()) { // it is a folder...
46 | getAllFileInDirectory(file);
47 | } else { // it is a file...
48 |
49 | listOfRecordings.add(file.getAbsolutePath());
50 | }
51 | }
52 | }
53 | }
54 | return listOfRecordings;
55 | }
56 |
57 | public ArrayList getAllRecordings() {
58 | return getAllFileInDirectory(new File(RECORDING_PATH));
59 |
60 | }
61 |
62 | public boolean createRecordingFolder() {
63 |
64 | if (!new File(RECORDING_PATH).exists()) {
65 |
66 | return new File(RECORDING_PATH).mkdir();
67 | } else {
68 | return true;
69 | }
70 |
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/src/com/serveroverload/recorder/ui/HomeActivity.java:
--------------------------------------------------------------------------------
1 | package com.serveroverload.recorder.ui;
2 |
3 | import java.util.ArrayList;
4 |
5 | import android.media.MediaPlayer;
6 | import android.os.Bundle;
7 | import android.support.v4.app.FragmentActivity;
8 | import android.support.v4.app.FragmentManager;
9 | import android.support.v4.app.FragmentTransaction;
10 |
11 | import com.google.android.gms.ads.AdRequest;
12 | import com.google.android.gms.ads.AdView;
13 | import com.serveroverload.recorder.R;
14 |
15 | public class HomeActivity extends FragmentActivity {
16 |
17 | MediaPlayer mMediaPlayer;
18 |
19 | private ArrayList recordings = new ArrayList();
20 |
21 | public int RecordingNumber;
22 |
23 | /**
24 | * @return the mMediaPlayer
25 | */
26 | public MediaPlayer getmMediaPlayer() {
27 | return mMediaPlayer;
28 | }
29 |
30 | @Override
31 | protected void onCreate(Bundle savedInstanceState) {
32 | super.onCreate(savedInstanceState);
33 |
34 | setContentView(R.layout.activity_main);
35 |
36 | mMediaPlayer = new MediaPlayer();
37 |
38 | FragmentManager fragmentManager = getSupportFragmentManager();
39 | FragmentTransaction fragmentTransaction = fragmentManager
40 | .beginTransaction();
41 | fragmentTransaction.replace(R.id.container, new RecordAudioFragment());
42 | fragmentTransaction.addToBackStack("RecordAudioFragment");
43 | fragmentTransaction.commit();
44 |
45 | AdView mAdView = (AdView) findViewById(R.id.adView);
46 | AdRequest adRequest = new AdRequest.Builder().build();
47 | mAdView.loadAd(adRequest);
48 |
49 | }
50 |
51 | @Override
52 | protected void onDestroy() {
53 | // TODO Auto-generated method stub
54 | super.onDestroy();
55 |
56 | if (mMediaPlayer != null) {
57 | mMediaPlayer.stop();
58 | mMediaPlayer = null;
59 | }
60 |
61 | }
62 |
63 | public ArrayList getRecordings() {
64 | return recordings;
65 | }
66 |
67 | public void setRecordings(ArrayList recordings) {
68 | this.recordings = recordings;
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/src/com/serveroverload/recorder/customview/PlayerVisualizerView.java:
--------------------------------------------------------------------------------
1 | package com.serveroverload.recorder.customview;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.graphics.Rect;
8 | import android.media.audiofx.Visualizer.OnDataCaptureListener;
9 | import android.view.View;
10 |
11 | /**
12 | * code taken from official sample app see
13 | * ApiDemos>src>com>example>android>apis>media>AudioFxDemo.java A simple class
14 | * that draws waveform data received from a
15 | * {@link OnDataCaptureListener#onWaveFormDataCapture }
16 | */
17 | public class PlayerVisualizerView extends View {
18 | private byte[] mBytes;
19 | private float[] mPoints;
20 | private Rect mRect = new Rect();
21 |
22 | private Paint mForePaint = new Paint();
23 |
24 | public PlayerVisualizerView(Context context) {
25 | super(context);
26 | init();
27 | }
28 |
29 | private void init() {
30 | mBytes = null;
31 |
32 | mForePaint.setStrokeWidth(1f);
33 | mForePaint.setAntiAlias(true);
34 | mForePaint.setColor(Color.GREEN);
35 | }
36 |
37 | public void updateVisualizer(byte[] bytes) {
38 | mBytes = bytes;
39 | invalidate();
40 | }
41 |
42 | @Override
43 | protected void onDraw(Canvas canvas) {
44 | super.onDraw(canvas);
45 |
46 | if (mBytes == null) {
47 | return;
48 | }
49 |
50 | if (mPoints == null || mPoints.length < mBytes.length * 4) {
51 | mPoints = new float[mBytes.length * 4];
52 | }
53 |
54 | mRect.set(0, 0, getWidth(), getHeight());
55 |
56 | for (int i = 0; i < mBytes.length - 1; i++) {
57 | mPoints[i * 4] = mRect.width() * i / (mBytes.length - 1);
58 | mPoints[i * 4 + 1] = mRect.height() / 2
59 | + ((byte) (mBytes[i] + 128)) * (mRect.height() / 2) / 128;
60 | mPoints[i * 4 + 2] = mRect.width() * (i + 1) / (mBytes.length - 1);
61 | mPoints[i * 4 + 3] = mRect.height() / 2
62 | + ((byte) (mBytes[i + 1] + 128)) * (mRect.height() / 2)
63 | / 128;
64 | }
65 |
66 | canvas.drawLines(mPoints, mForePaint);
67 | }
68 | }
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
24 |
25 |
26 |
29 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/com/serveroverload/recorder/util/RecordingsLoaderTask.java:
--------------------------------------------------------------------------------
1 | package com.serveroverload.recorder.util;
2 |
3 | import java.util.ArrayList;
4 |
5 | import com.serveroverload.recorder.R;
6 | import com.serveroverload.recorder.R.layout;
7 | import com.serveroverload.recorder.ui.HomeActivity;
8 |
9 | import android.content.Context;
10 | import android.os.AsyncTask;
11 | import android.support.v4.widget.SwipeRefreshLayout;
12 | import android.widget.ListView;
13 |
14 | /**
15 | * The Class ImageLoaderTask.
16 | */
17 | public class RecordingsLoaderTask extends
18 | AsyncTask> {
19 |
20 | private Context context;
21 | private SwipeRefreshLayout swipeLayout;
22 | ListView recordingsListView;
23 |
24 | /**
25 | * Instantiates a new image loader task.
26 | *
27 | * @param contacts
28 | * the contacts
29 | * @param position
30 | * the position
31 | */
32 | public RecordingsLoaderTask(SwipeRefreshLayout swipeLayout,
33 | ListView listView, Context context) {
34 |
35 | this.swipeLayout = swipeLayout;
36 | this.recordingsListView = listView;
37 | this.context = context;
38 | }
39 |
40 | /*
41 | * (non-Javadoc)
42 | *
43 | * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
44 | */
45 | @Override
46 | protected void onPostExecute(final ArrayList listOfRecordings) {
47 |
48 | if (null != recordingsListView) {
49 |
50 | RecordingsListArrayAdapter arrayAdapter2 = new RecordingsListArrayAdapter(
51 | context, R.layout.swipe_layout_recording_list_item,
52 | ((HomeActivity) context).getRecordings());
53 |
54 | recordingsListView.setAdapter(arrayAdapter2);
55 |
56 | recordingsListView.setFastScrollEnabled(true);
57 |
58 | }
59 |
60 | if (null != swipeLayout) {
61 | swipeLayout.setRefreshing(false);
62 | }
63 |
64 | super.onPostExecute(listOfRecordings);
65 | }
66 |
67 | @Override
68 | protected ArrayList doInBackground(String... loadTask) {
69 |
70 | ((HomeActivity) context).setRecordings(Helper.getHelperInstance()
71 | .getAllRecordings());
72 |
73 | return ((HomeActivity) context).getRecordings();
74 | }
75 | }
--------------------------------------------------------------------------------
/src/com/serveroverload/recorder/customview/RecorderVisualizerView.java:
--------------------------------------------------------------------------------
1 | package com.serveroverload.recorder.customview;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import android.content.Context;
7 | import android.graphics.Canvas;
8 | import android.graphics.Color;
9 | import android.graphics.Paint;
10 | import android.util.AttributeSet;
11 | import android.view.View;
12 |
13 | public class RecorderVisualizerView extends View {
14 | private static final int LINE_WIDTH = 2; // width of visualizer lines
15 | private static final int LINE_SCALE = 100; // scales visualizer lines
16 | private List amplitudes; // amplitudes for line lengths
17 | private int width; // width of this View
18 | private int height; // height of this View
19 | private Paint linePaint; // specifies line drawing characteristics
20 |
21 | // constructor
22 | public RecorderVisualizerView(Context context, AttributeSet attrs) {
23 | super(context, attrs); // call superclass constructor
24 | linePaint = new Paint(); // create Paint for lines
25 | linePaint.setColor(Color.GREEN); // set color to green
26 | linePaint.setStrokeWidth(LINE_WIDTH); // set stroke width
27 | }
28 |
29 | // called when the dimensions of the View change
30 | @Override
31 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
32 | width = w; // new width of this View
33 | height = h; // new height of this View
34 | amplitudes = new ArrayList(width / LINE_WIDTH);
35 | }
36 |
37 | // clear all amplitudes to prepare for a new visualization
38 | public void clear() {
39 | amplitudes.clear();
40 | }
41 |
42 | // add the given amplitude to the amplitudes ArrayList
43 | public void addAmplitude(float amplitude) {
44 | amplitudes.add(amplitude); // add newest to the amplitudes ArrayList
45 |
46 | // if the power lines completely fill the VisualizerView
47 | if (amplitudes.size() * LINE_WIDTH >= width) {
48 | amplitudes.remove(0); // remove oldest power value
49 | }
50 | }
51 |
52 | // draw the visualizer with scaled lines representing the amplitudes
53 | @Override
54 | public void onDraw(Canvas canvas) {
55 | int middle = height / 2; // get the middle of the View
56 | float curX = 0; // start curX at zero
57 |
58 | // for each item in the amplitudes ArrayList
59 | for (float power : amplitudes) {
60 | float scaledHeight = power / LINE_SCALE; // scale the power
61 | curX += LINE_WIDTH; // increase X by LINE_WIDTH
62 |
63 | // draw a line representing this item in the amplitudes ArrayList
64 | canvas.drawLine(curX, middle + scaledHeight / 2, curX, middle
65 | - scaledHeight / 2, linePaint);
66 | }
67 | }
68 |
69 | }
--------------------------------------------------------------------------------
/res/layout/swipe_layout_recording_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
19 |
20 |
25 |
26 |
31 |
32 |
42 |
43 |
44 |
48 |
49 |
54 |
55 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
82 |
83 |
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/src/com/serveroverload/recorder/util/RecordingsListArrayAdapter.java:
--------------------------------------------------------------------------------
1 | package com.serveroverload.recorder.util;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.util.List;
6 |
7 | import com.serveroverload.recorder.R;
8 | import com.serveroverload.recorder.R.id;
9 | import com.serveroverload.recorder.R.layout;
10 | import com.serveroverload.recorder.customview.SwipeLayout;
11 | import com.serveroverload.recorder.ui.HomeActivity;
12 |
13 | import android.content.Context;
14 | import android.content.Intent;
15 | import android.media.MediaPlayer;
16 | import android.net.Uri;
17 | import android.view.LayoutInflater;
18 | import android.view.View;
19 | import android.view.View.OnClickListener;
20 | import android.view.ViewGroup;
21 | import android.widget.ArrayAdapter;
22 | import android.widget.TextView;
23 | import android.widget.Toast;
24 |
25 | public class RecordingsListArrayAdapter extends ArrayAdapter
26 |
27 | {
28 | public RecordingsListArrayAdapter(Context context, int resource,
29 | List listOfRecordings) {
30 | super(context, resource, listOfRecordings);
31 |
32 | this.context = context;
33 | this.listOfRecordings = listOfRecordings;
34 | }
35 |
36 | private final Context context;
37 | private final List listOfRecordings;
38 | private ViewHolder holder;
39 |
40 | private class ViewHolder {
41 | TextView recordingName;
42 | SwipeLayout currentSwipeLayout;
43 | }
44 |
45 | @Override
46 | public View getView(final int position, View convertView, ViewGroup parent) {
47 |
48 | if (convertView == null) {
49 |
50 | LayoutInflater inflater = (LayoutInflater) context
51 | .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
52 |
53 | convertView = inflater.inflate(
54 | R.layout.swipe_layout_recording_list_item, parent, false);
55 |
56 | holder = new ViewHolder();
57 |
58 | holder.recordingName = (TextView) convertView
59 | .findViewById(R.id.textViewRecordingName);
60 |
61 | holder.recordingName.setSelected(true);
62 |
63 | holder.currentSwipeLayout = (SwipeLayout) convertView
64 | .findViewById(R.id.swipe_layout_1);
65 |
66 | holder.currentSwipeLayout.setShowMode(SwipeLayout.ShowMode.PullOut);
67 |
68 | holder.currentSwipeLayout.setDragEdge(SwipeLayout.DragEdge.Left);
69 |
70 | convertView.setTag(holder);
71 | } else {
72 | holder = (ViewHolder) convertView.getTag();
73 | }
74 |
75 | holder.recordingName.setText(((HomeActivity) context).getRecordings().get(position));
76 |
77 | // Tapped in hidden menu
78 | holder.currentSwipeLayout.findViewById(R.id.share).setOnClickListener(
79 | new OnClickListener() {
80 |
81 | @Override
82 | public void onClick(View arg0) {
83 | Intent sharingIntent = new Intent(
84 | android.content.Intent.ACTION_SEND);
85 | sharingIntent.setType("text/plain");
86 | File archivo = new File(((HomeActivity) context).getRecordings().get(position));
87 | sharingIntent.putExtra(Intent.EXTRA_STREAM,
88 | Uri.fromFile(archivo));
89 | context.startActivity(Intent.createChooser(
90 | sharingIntent, "Share via"));
91 |
92 | }
93 | });
94 |
95 | holder.currentSwipeLayout.findViewById(R.id.delete_song)
96 | .setOnClickListener(new OnClickListener() {
97 |
98 | @Override
99 | public void onClick(View v) {
100 |
101 | Helper.getHelperInstance().makeHepticFeedback(context);
102 |
103 | if (new File(((HomeActivity) context).getRecordings().get(position)).delete()) {
104 | Toast.makeText(getContext(), "Deleted", 500).show();
105 |
106 | ((HomeActivity) context).getRecordings().remove(position);
107 |
108 | notifyDataSetChanged();
109 |
110 | ((HomeActivity) context).getmMediaPlayer().reset();
111 | }
112 |
113 | }
114 |
115 | });
116 |
117 | // convertView.setOnClickListener(new OnClickListener() {
118 | //
119 | // @Override
120 | // public void onClick(View v) {
121 | // MediaPlayer mMediaPlayer = ((HomeActivity) context)
122 | // .getmMediaPlayer();
123 | //
124 | // try {
125 | //
126 | // mMediaPlayer.reset();
127 | // mMediaPlayer.setDataSource(((HomeActivity) context).getRecordings().get(position));
128 | // mMediaPlayer.prepare();
129 | // mMediaPlayer.start();
130 | //
131 | // } catch (IllegalArgumentException | SecurityException
132 | // | IllegalStateException | IOException e) {
133 | // // TODO Auto-generated catch block
134 | // e.printStackTrace();
135 | // }
136 | //
137 | // }
138 | // });
139 |
140 | return convertView;
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/res/layout/record_audio_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
24 |
25 |
36 |
37 |
43 |
44 |
50 |
51 |
57 |
58 |
64 |
65 |
71 |
72 |
78 |
79 |
85 |
86 |
92 |
93 |
94 |
107 |
108 |
114 |
115 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/res/layout/recording_list_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
22 |
23 |
32 |
33 |
40 |
41 |
42 |
51 |
52 |
57 |
58 |
66 |
67 |
71 |
72 |
81 |
82 |
90 |
91 |
95 |
96 |
103 |
104 |
108 |
109 |
110 |
117 |
118 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/src/com/serveroverload/recorder/ui/RecordingListFragment.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | */
4 | package com.serveroverload.recorder.ui;
5 |
6 | import java.io.IOException;
7 |
8 | import android.app.Activity;
9 | import android.media.MediaPlayer;
10 | import android.media.audiofx.Visualizer;
11 | import android.os.Bundle;
12 | import android.support.v4.app.Fragment;
13 | import android.support.v4.widget.SwipeRefreshLayout;
14 | import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener;
15 | import android.view.LayoutInflater;
16 | import android.view.View;
17 | import android.view.View.OnClickListener;
18 | import android.view.ViewGroup;
19 | import android.widget.AdapterView;
20 | import android.widget.AdapterView.OnItemClickListener;
21 | import android.widget.LinearLayout;
22 | import android.widget.ListView;
23 |
24 | import com.serveroverload.recorder.R;
25 | import com.serveroverload.recorder.customview.PlayerVisualizerView;
26 | import com.serveroverload.recorder.util.Helper;
27 | import com.serveroverload.recorder.util.RecordingsLoaderTask;
28 |
29 | /**
30 | * @author Hitesh
31 | *
32 | */
33 | public class RecordingListFragment extends Fragment implements
34 | OnRefreshListener {
35 |
36 | private static final float VISUALIZER_HEIGHT_DIP = 100f;
37 | private SwipeRefreshLayout swipeLayout;
38 | private ListView recordingsListView;
39 | private LinearLayout mLinearLayout;
40 | private com.serveroverload.recorder.customview.PlayerVisualizerView mVisualizerView;
41 | private Visualizer mVisualizer;
42 | private View rootView;
43 | private boolean SONGPAUSED;
44 |
45 | @Override
46 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
47 | Bundle savedInstanceState) {
48 | rootView = inflater.inflate(R.layout.recording_list_fragment,
49 | container, false);
50 |
51 | ((HomeActivity) getActivity()).RecordingNumber = 0;
52 | //
53 | // ((HomeActivity) getActivity()).getmActionBarTitle().setText(
54 | // getResources().getString(R.string.title_album));
55 |
56 | recordingsListView = (ListView) rootView
57 | .findViewById(R.id.listView_Recording);
58 |
59 | new RecordingsLoaderTask(swipeLayout, recordingsListView, getActivity())
60 | .execute(Helper.LOAD_RECORDINGS);
61 |
62 | recordingsListView.setFastScrollEnabled(true);
63 |
64 | // }
65 |
66 | swipeLayout = (SwipeRefreshLayout) rootView
67 | .findViewById(R.id.swipe_container);
68 | swipeLayout.setOnRefreshListener(RecordingListFragment.this);
69 | swipeLayout.setColorScheme(android.R.color.holo_blue_bright,
70 | android.R.color.holo_green_light,
71 | android.R.color.holo_orange_light,
72 | android.R.color.holo_red_light);
73 |
74 | // listen for when the music stream ends playing
75 | ((HomeActivity) getActivity()).getmMediaPlayer()
76 | .setOnCompletionListener(
77 | new MediaPlayer.OnCompletionListener() {
78 | public void onCompletion(MediaPlayer mediaPlayer) {
79 | // disable the visualizer as it's no longer
80 | // needed
81 |
82 | if (null != mVisualizer)
83 | mVisualizer.setEnabled(false);
84 |
85 | rootView.findViewById(R.id.btnPauseSlider)
86 | .setVisibility(View.GONE);
87 |
88 | rootView.findViewById(R.id.btnPlaySlider)
89 | .setVisibility(View.VISIBLE);
90 |
91 | }
92 | });
93 |
94 | mLinearLayout = (LinearLayout) rootView
95 | .findViewById(R.id.linearLayoutVisual);
96 | // Create a VisualizerView to display the audio waveform for the current
97 | // settings
98 | mVisualizerView = new PlayerVisualizerView(getActivity());
99 | mVisualizerView.setLayoutParams(new ViewGroup.LayoutParams(
100 | ViewGroup.LayoutParams.MATCH_PARENT,
101 | (int) (VISUALIZER_HEIGHT_DIP * getResources()
102 | .getDisplayMetrics().density)));
103 | mLinearLayout.addView(mVisualizerView);
104 |
105 | // Create the Visualizer object and attach it to our media player.
106 | mVisualizer = new Visualizer(((HomeActivity) getActivity())
107 | .getmMediaPlayer().getAudioSessionId());
108 |
109 | mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);
110 |
111 | mVisualizer.setDataCaptureListener(
112 | new Visualizer.OnDataCaptureListener() {
113 | public void onWaveFormDataCapture(Visualizer visualizer,
114 | byte[] bytes, int samplingRate) {
115 | mVisualizerView.updateVisualizer(bytes);
116 | }
117 |
118 | public void onFftDataCapture(Visualizer visualizer,
119 | byte[] bytes, int samplingRate) {
120 | }
121 | }, Visualizer.getMaxCaptureRate() / 2, true, false);
122 |
123 | mVisualizer.setEnabled(true);
124 |
125 | rootView.findViewById(R.id.btnPauseSlider).setOnClickListener(
126 | new OnClickListener() {
127 |
128 | @Override
129 | public void onClick(View v) {
130 |
131 | Helper.getHelperInstance().makeHepticFeedback(
132 | getActivity());
133 |
134 | if (null != mVisualizer)
135 | mVisualizer.setEnabled(false);
136 |
137 | ((HomeActivity) getActivity()).getmMediaPlayer()
138 | .pause();
139 |
140 | SONGPAUSED = true;
141 |
142 | rootView.findViewById(R.id.btnPauseSlider)
143 | .setVisibility(View.GONE);
144 |
145 | rootView.findViewById(R.id.btnPlaySlider)
146 | .setVisibility(View.VISIBLE);
147 |
148 | }
149 | });
150 |
151 | rootView.findViewById(R.id.btnPlaySlider).setOnClickListener(
152 | new OnClickListener() {
153 |
154 | @Override
155 | public void onClick(View v) {
156 |
157 | Helper.getHelperInstance().makeHepticFeedback(
158 | getActivity());
159 |
160 | if (SONGPAUSED) {
161 |
162 | resumeSong();
163 |
164 | } else {
165 |
166 | playSong(((HomeActivity) getActivity()).RecordingNumber);
167 |
168 | }
169 | }
170 | });
171 |
172 | rootView.findViewById(R.id.btnNextSlider).setOnClickListener(
173 | new OnClickListener() {
174 |
175 | @Override
176 | public void onClick(View v) {
177 |
178 | Helper.getHelperInstance().makeHepticFeedback(
179 | getActivity());
180 |
181 | if (((HomeActivity) getActivity()).getRecordings()
182 | .size() > 0) {
183 | if (((HomeActivity) getActivity()).RecordingNumber < (((HomeActivity) getActivity())
184 | .getRecordings().size() - 1)) {
185 | ((HomeActivity) getActivity()).RecordingNumber++;
186 | } else {
187 | ((HomeActivity) getActivity()).RecordingNumber = 0;
188 | }
189 |
190 | playSong(((HomeActivity) getActivity()).RecordingNumber);
191 | }
192 |
193 | }
194 | });
195 |
196 | rootView.findViewById(R.id.btnBackSlider).setOnClickListener(
197 | new OnClickListener() {
198 |
199 | @Override
200 | public void onClick(View v) {
201 |
202 | Helper.getHelperInstance().makeHepticFeedback(
203 | getActivity());
204 |
205 | if (((HomeActivity) getActivity()).getRecordings()
206 | .size() > 0) {
207 | if (((HomeActivity) getActivity()).RecordingNumber > 0) {
208 | ((HomeActivity) getActivity()).RecordingNumber--;
209 | } else {
210 | ((HomeActivity) getActivity()).RecordingNumber = ((HomeActivity) getActivity())
211 | .getRecordings().size() - 1;
212 | }
213 |
214 | playSong(((HomeActivity) getActivity()).RecordingNumber);
215 | }
216 |
217 | }
218 | });
219 |
220 | rootView.findViewById(R.id.btnNextSlider).setOnClickListener(
221 | new OnClickListener() {
222 |
223 | @Override
224 | public void onClick(View v) {
225 |
226 | if (((HomeActivity) getActivity()).getRecordings()
227 | .size() > 0) {
228 | if (((HomeActivity) getActivity()).RecordingNumber < (((HomeActivity) getActivity())
229 | .getRecordings().size() - 1)) {
230 | ((HomeActivity) getActivity()).RecordingNumber++;
231 | } else {
232 | ((HomeActivity) getActivity()).RecordingNumber = 0;
233 | }
234 | }
235 | playSong(((HomeActivity) getActivity()).RecordingNumber);
236 |
237 | }
238 | });
239 |
240 | recordingsListView.setOnItemClickListener(new OnItemClickListener() {
241 |
242 | @Override
243 | public void onItemClick(AdapterView> parent, View view,
244 | int position, long id) {
245 |
246 | ((HomeActivity) getActivity()).RecordingNumber = position;
247 |
248 | playSong(position);
249 |
250 | }
251 | });
252 |
253 | return rootView;
254 | }
255 |
256 | @Override
257 | public void onRefresh() {
258 |
259 | new RecordingsLoaderTask(swipeLayout, recordingsListView, getActivity())
260 | .execute(Helper.LOAD_RECORDINGS);
261 |
262 | }
263 |
264 | @Override
265 | public void onDestroy() {
266 | // TODO Auto-generated method stub
267 | super.onDestroy();
268 |
269 | if (null != mVisualizer)
270 | mVisualizer.release();
271 | mVisualizer = null;
272 | }
273 |
274 | @Override
275 | public void onPause() {
276 | // TODO Auto-generated method stub
277 | super.onPause();
278 |
279 | if (null != mVisualizer)
280 | mVisualizer.release();
281 | mVisualizer = null;
282 |
283 | ((HomeActivity) getActivity()).getmMediaPlayer().reset();
284 | }
285 |
286 | @Override
287 | public void onAttach(Activity activity) {
288 | // TODO Auto-generated method stub
289 | super.onAttach(activity);
290 |
291 | // activityReference = activity;
292 | }
293 |
294 | private void playSong(int RecordingNumber) {
295 | MediaPlayer mMediaPlayer = ((HomeActivity) getActivity())
296 | .getmMediaPlayer();
297 |
298 | if (null != mVisualizer)
299 | mVisualizer.setEnabled(true);
300 |
301 | if (null != mMediaPlayer
302 | && !((HomeActivity) getActivity()).getRecordings().isEmpty()) {
303 | mMediaPlayer.reset();
304 | try {
305 | mMediaPlayer.setDataSource(((HomeActivity) getActivity())
306 | .getRecordings().get(RecordingNumber).toString());
307 |
308 | mMediaPlayer.prepare();
309 | mMediaPlayer.start();
310 |
311 | rootView.findViewById(R.id.btnPauseSlider).setVisibility(
312 | View.VISIBLE);
313 |
314 | rootView.findViewById(R.id.btnPlaySlider).setVisibility(
315 | View.GONE);
316 | } catch (IllegalArgumentException e) {
317 | // TODO Auto-generated catch block
318 | e.printStackTrace();
319 | } catch (SecurityException e) {
320 | // TODO Auto-generated catch block
321 | e.printStackTrace();
322 | } catch (IllegalStateException e) {
323 | // TODO Auto-generated catch block
324 | e.printStackTrace();
325 | } catch (IOException e) {
326 | // TODO Auto-generated catch block
327 | e.printStackTrace();
328 | }
329 |
330 | }
331 | }
332 |
333 | private void resumeSong() {
334 |
335 | if (null != mVisualizer)
336 | mVisualizer.setEnabled(true);
337 |
338 | ((HomeActivity) getActivity()).getmMediaPlayer().start();
339 |
340 | rootView.findViewById(R.id.btnPauseSlider).setVisibility(View.VISIBLE);
341 |
342 | rootView.findViewById(R.id.btnPlaySlider).setVisibility(View.GONE);
343 |
344 | SONGPAUSED = false;
345 | }
346 |
347 | // private Activity activityReference;
348 |
349 | }
350 |
--------------------------------------------------------------------------------
/src/com/serveroverload/recorder/ui/RecordAudioFragment.java:
--------------------------------------------------------------------------------
1 | package com.serveroverload.recorder.ui;
2 |
3 | import java.io.File;
4 | import java.io.IOException;
5 | import java.text.SimpleDateFormat;
6 | import java.util.Date;
7 |
8 | import android.media.MediaRecorder;
9 | import android.os.Bundle;
10 | import android.os.Handler;
11 | import android.support.v4.app.Fragment;
12 | import android.support.v4.app.FragmentManager;
13 | import android.support.v4.app.FragmentTransaction;
14 | import android.view.KeyEvent;
15 | import android.view.LayoutInflater;
16 | import android.view.MotionEvent;
17 | import android.view.View;
18 | import android.view.View.OnTouchListener;
19 | import android.view.ViewGroup;
20 | import android.widget.Toast;
21 |
22 | import com.serveroverload.recorder.R;
23 | import com.serveroverload.recorder.customview.RecorderVisualizerView;
24 | import com.serveroverload.recorder.util.Helper;
25 |
26 | public class RecordAudioFragment extends Fragment {
27 |
28 | private String currentOutFile;
29 | private MediaRecorder myAudioRecorder;
30 |
31 | private boolean isRecording;
32 | private RecorderVisualizerView visualizerView;
33 | private View rootView;
34 |
35 | private boolean doubleBackToExitPressedOnce;
36 | private Handler mHandler = new Handler();
37 |
38 | private final Runnable mRunnable = new Runnable() {
39 | @Override
40 | public void run() {
41 | doubleBackToExitPressedOnce = false;
42 | }
43 | };
44 |
45 | public static final int REPEAT_INTERVAL = 40;
46 |
47 | private Handler handler = new Handler(); // Handler for updating the
48 | // visualizer
49 |
50 | @Override
51 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
52 | Bundle savedInstanceState) {
53 |
54 | rootView = inflater.inflate(R.layout.record_audio_fragment, container,
55 | false);
56 |
57 | rootView.findViewById(R.id.stop_recording).setEnabled(false);
58 | rootView.findViewById(R.id.delete_recording).setEnabled(false);
59 |
60 | visualizerView = (RecorderVisualizerView) rootView
61 | .findViewById(R.id.visualizer);
62 |
63 | rootView.findViewById(R.id.start_recording).setOnTouchListener(
64 | new OnTouchListener() {
65 |
66 | @Override
67 | public boolean onTouch(View v, MotionEvent event) {
68 |
69 | Helper.getHelperInstance().makeHepticFeedback(
70 | getActivity());
71 |
72 | if (Helper.getHelperInstance().createRecordingFolder()) {
73 |
74 | SimpleDateFormat dateFormat = new SimpleDateFormat(
75 | "yyyyMMdd_HH_mm_ss");
76 | String currentTimeStamp = dateFormat
77 | .format(new Date());
78 |
79 | currentOutFile = Helper.RECORDING_PATH
80 | + "/recording_" + currentTimeStamp + ".3gp";
81 |
82 | myAudioRecorder = new MediaRecorder();
83 | myAudioRecorder
84 | .setAudioSource(MediaRecorder.AudioSource.MIC);
85 | myAudioRecorder
86 | .setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
87 | myAudioRecorder
88 | .setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
89 | myAudioRecorder.setOutputFile(currentOutFile);
90 |
91 | try {
92 |
93 | myAudioRecorder.prepare();
94 | myAudioRecorder.start();
95 |
96 | Toast.makeText(
97 | getActivity(),
98 | getActivity().getResources().getString(
99 | R.string.rec_start),
100 | Toast.LENGTH_LONG).show();
101 |
102 | rootView.findViewById(R.id.start_recording)
103 | .setEnabled(false);
104 | rootView.findViewById(R.id.stop_recording)
105 | .setEnabled(true);
106 | rootView.findViewById(R.id.delete_recording)
107 | .setEnabled(false);
108 |
109 | isRecording = true;
110 |
111 | handler.post(updateVisualizer);
112 | }
113 |
114 | catch (IllegalStateException e) {
115 | Toast.makeText(
116 | getActivity(),
117 | getActivity().getResources().getString(
118 | R.string.rec_fail),
119 | Toast.LENGTH_LONG).show();
120 | e.printStackTrace();
121 |
122 | rootView.findViewById(R.id.start_recording)
123 | .setEnabled(true);
124 | rootView.findViewById(R.id.stop_recording)
125 | .setEnabled(false);
126 | rootView.findViewById(R.id.delete_recording)
127 | .setEnabled(true);
128 |
129 | isRecording = false;
130 | }
131 |
132 | catch (IOException e) {
133 | Toast.makeText(
134 | getActivity(),
135 | getActivity().getResources().getString(
136 | R.string.rec_fail),
137 | Toast.LENGTH_LONG).show();
138 | e.printStackTrace();
139 |
140 | rootView.findViewById(R.id.start_recording)
141 | .setEnabled(true);
142 | rootView.findViewById(R.id.stop_recording)
143 | .setEnabled(false);
144 | rootView.findViewById(R.id.delete_recording)
145 | .setEnabled(true);
146 |
147 | isRecording = false;
148 | }
149 | } else {
150 |
151 | Toast.makeText(
152 | getActivity(),
153 | getActivity().getResources().getString(
154 | R.string.rec_fail_mkdir),
155 | Toast.LENGTH_LONG).show();
156 |
157 | isRecording = false;
158 | }
159 |
160 | return false;
161 | }
162 | });
163 |
164 | rootView.findViewById(R.id.stop_recording).setOnTouchListener(
165 | new OnTouchListener() {
166 |
167 | @Override
168 | public boolean onTouch(View v, MotionEvent event) {
169 |
170 | Helper.getHelperInstance().makeHepticFeedback(
171 | getActivity());
172 | try {
173 |
174 | if (null != myAudioRecorder) {
175 | myAudioRecorder.stop();
176 | myAudioRecorder.release();
177 | myAudioRecorder = null;
178 |
179 | Toast.makeText(
180 | getActivity(),
181 | getActivity().getResources().getString(
182 | R.string.rec_saved)
183 | + currentOutFile,
184 | Toast.LENGTH_SHORT).show();
185 | }
186 |
187 | } catch (Exception e) {
188 | e.printStackTrace();
189 | Toast.makeText(
190 | getActivity(),
191 | getActivity().getResources().getString(
192 | R.string.rec_fail),
193 | Toast.LENGTH_LONG).show();
194 | }
195 |
196 | rootView.findViewById(R.id.start_recording).setEnabled(
197 | true);
198 | rootView.findViewById(R.id.stop_recording).setEnabled(
199 | false);
200 | rootView.findViewById(R.id.delete_recording)
201 | .setEnabled(true);
202 |
203 | isRecording = false;
204 |
205 | handler.removeCallbacks(updateVisualizer);
206 |
207 | return false;
208 | }
209 | });
210 |
211 | rootView.findViewById(R.id.delete_recording).setOnTouchListener(
212 | new OnTouchListener() {
213 |
214 | @Override
215 | public boolean onTouch(View v, MotionEvent event) {
216 |
217 | File recording = new File(currentOutFile);
218 |
219 | if (recording.exists() && recording.delete()) {
220 | Toast.makeText(
221 | getActivity(),
222 | getResources().getString(
223 | R.string.rec_deleted)
224 | + currentOutFile,
225 | Toast.LENGTH_SHORT).show();
226 | } else {
227 | Toast.makeText(
228 | getActivity(),
229 | getActivity().getResources().getString(
230 | R.string.rec_delete_fail)
231 | + currentOutFile,
232 | Toast.LENGTH_SHORT).show();
233 | }
234 |
235 | rootView.findViewById(R.id.stop_recording).setEnabled(
236 | false);
237 | rootView.findViewById(R.id.delete_recording)
238 | .setEnabled(false);
239 | return false;
240 | }
241 | });
242 |
243 | rootView.findViewById(R.id.txt_cancel).setOnTouchListener(
244 | new OnTouchListener() {
245 |
246 | @Override
247 | public boolean onTouch(View v, MotionEvent event) {
248 |
249 | Helper.getHelperInstance().makeHepticFeedback(
250 | getActivity());
251 |
252 | try {
253 |
254 | if (null != myAudioRecorder) {
255 | myAudioRecorder.stop();
256 | myAudioRecorder.release();
257 | myAudioRecorder = null;
258 |
259 | Toast.makeText(
260 | getActivity(),
261 | getActivity().getResources().getString(
262 | R.string.rec_saved)
263 | + currentOutFile,
264 | Toast.LENGTH_SHORT).show();
265 | }
266 |
267 | } catch (Exception e) {
268 | e.printStackTrace();
269 | Toast.makeText(
270 | getActivity(),
271 | getActivity().getResources().getString(
272 | R.string.rec_fail),
273 | Toast.LENGTH_LONG).show();
274 | }
275 |
276 | isRecording = false;
277 |
278 | handler.removeCallbacks(updateVisualizer);
279 |
280 | System.exit(0);
281 |
282 | return false;
283 | }
284 | });
285 |
286 | rootView.findViewById(R.id.browse_recording).setOnTouchListener(
287 | new OnTouchListener() {
288 |
289 | @Override
290 | public boolean onTouch(View v, MotionEvent event) {
291 |
292 | FragmentManager fragmentManager = getActivity()
293 | .getSupportFragmentManager();
294 | FragmentTransaction fragmentTransaction = fragmentManager
295 | .beginTransaction();
296 | fragmentTransaction.replace(R.id.container,
297 | new RecordingListFragment());
298 | fragmentTransaction
299 | .addToBackStack("RecordingListFragment");
300 | fragmentTransaction.commit();
301 |
302 | return false;
303 | }
304 | });
305 |
306 | rootView.setFocusableInTouchMode(true);
307 | rootView.requestFocus();
308 | rootView.setOnKeyListener(new View.OnKeyListener() {
309 |
310 | @Override
311 | public boolean onKey(View v, int keyCode, KeyEvent event) {
312 |
313 | if (event.getAction() == KeyEvent.ACTION_UP
314 | && keyCode == KeyEvent.KEYCODE_BACK) {
315 |
316 | if (doubleBackToExitPressedOnce) {
317 | // super.onBackPressed();
318 |
319 | if (mHandler != null) {
320 | mHandler.removeCallbacks(mRunnable);
321 | }
322 |
323 | getActivity().finish();
324 |
325 | return true;
326 | }
327 |
328 | doubleBackToExitPressedOnce = true;
329 | Toast.makeText(getActivity(),
330 | "Please click BACK again to exit",
331 | Toast.LENGTH_SHORT).show();
332 |
333 | mHandler.postDelayed(mRunnable, 2000);
334 |
335 | }
336 | return true;
337 | }
338 | });
339 |
340 | return rootView;
341 |
342 | }
343 |
344 | @Override
345 | public void onPause() {
346 | // TODO Auto-generated method stub
347 | super.onPause();
348 |
349 | if (isRecording) {
350 |
351 | try {
352 |
353 | if (null != myAudioRecorder) {
354 |
355 | myAudioRecorder.stop();
356 | myAudioRecorder.release();
357 | myAudioRecorder = null;
358 |
359 | Toast.makeText(
360 | getActivity(),
361 | getActivity().getResources().getString(
362 | R.string.rec_saved)
363 | + currentOutFile, Toast.LENGTH_SHORT)
364 | .show();
365 |
366 | rootView.findViewById(R.id.start_recording)
367 | .setEnabled(true);
368 | rootView.findViewById(R.id.stop_recording)
369 | .setEnabled(false);
370 | rootView.findViewById(R.id.delete_recording).setEnabled(
371 | true);
372 |
373 | handler.removeCallbacks(updateVisualizer);
374 | }
375 |
376 | } catch (Exception e) {
377 | e.printStackTrace();
378 | Toast.makeText(
379 | getActivity(),
380 | getActivity().getResources().getString(
381 | R.string.rec_fail), Toast.LENGTH_LONG).show();
382 |
383 | rootView.findViewById(R.id.start_recording).setEnabled(true);
384 | rootView.findViewById(R.id.stop_recording).setEnabled(false);
385 | rootView.findViewById(R.id.delete_recording).setEnabled(true);
386 |
387 | handler.removeCallbacks(updateVisualizer);
388 |
389 | }
390 | }
391 | }
392 |
393 | // updates the visualizer every 50 milliseconds
394 | Runnable updateVisualizer = new Runnable() {
395 | @Override
396 | public void run() {
397 | if (isRecording) // if we are already recording
398 | {
399 | // get the current amplitude
400 | int x = myAudioRecorder.getMaxAmplitude();
401 | visualizerView.addAmplitude(x); // update the VisualizeView
402 | visualizerView.invalidate(); // refresh the VisualizerView
403 |
404 | // update in 40 milliseconds
405 | handler.postDelayed(this, REPEAT_INTERVAL);
406 | }
407 | }
408 | };
409 |
410 | }
411 |
--------------------------------------------------------------------------------
/src/com/serveroverload/recorder/customview/SwipeLayout.java:
--------------------------------------------------------------------------------
1 | package com.serveroverload.recorder.customview;
2 |
3 | import java.util.ArrayList;
4 | import java.util.HashMap;
5 | import java.util.List;
6 | import java.util.Map;
7 |
8 | import com.serveroverload.recorder.R;
9 | import com.serveroverload.recorder.R.styleable;
10 |
11 | import android.content.Context;
12 | import android.content.res.TypedArray;
13 | import android.graphics.Rect;
14 | import android.support.v4.view.ViewCompat;
15 | import android.support.v4.widget.ViewDragHelper;
16 | import android.util.AttributeSet;
17 | import android.view.GestureDetector;
18 | import android.view.MotionEvent;
19 | import android.view.View;
20 | import android.view.ViewConfiguration;
21 | import android.view.ViewGroup;
22 | import android.view.ViewParent;
23 | import android.widget.Adapter;
24 | import android.widget.AdapterView;
25 | import android.widget.BaseAdapter;
26 | import android.widget.FrameLayout;
27 | import android.widget.ListAdapter;
28 |
29 | /**
30 | * The Class SwipeLayout.
31 | */
32 | public class SwipeLayout extends FrameLayout {
33 |
34 | /** The Constant EMPTY_LAYOUT. */
35 | public static final int EMPTY_LAYOUT = -1;
36 |
37 | /** The Constant DRAG_LEFT. */
38 | private static final int DRAG_LEFT = 1;
39 |
40 | /** The Constant DRAG_RIGHT. */
41 | private static final int DRAG_RIGHT = 2;
42 |
43 | /** The Constant DRAG_TOP. */
44 | private static final int DRAG_TOP = 4;
45 |
46 | /** The Constant DRAG_BOTTOM. */
47 | private static final int DRAG_BOTTOM = 8;
48 |
49 | /** The m touch slop. */
50 | private int mTouchSlop;
51 |
52 | /** The m left index. */
53 | private int mLeftIndex;
54 |
55 | /** The m right index. */
56 | private int mRightIndex;
57 |
58 | /** The m top index. */
59 | private int mTopIndex;
60 |
61 | /** The m bottom index. */
62 | private int mBottomIndex;
63 |
64 | /** The m current direction index. */
65 | private int mCurrentDirectionIndex = 0;
66 |
67 | /** The m drag helper. */
68 | private ViewDragHelper mDragHelper;
69 |
70 | /** The m drag distance. */
71 | private int mDragDistance = 0;
72 |
73 | /** The m drag edges. */
74 | private List mDragEdges;
75 |
76 | /** The m show mode. */
77 | private ShowMode mShowMode;
78 |
79 | /** The m left edge swipe offset. */
80 | private float mLeftEdgeSwipeOffset;
81 |
82 | /** The m right edge swipe offset. */
83 | private float mRightEdgeSwipeOffset;
84 |
85 | /** The m top edge swipe offset. */
86 | private float mTopEdgeSwipeOffset;
87 |
88 | /** The m bottom edge swipe offset. */
89 | private float mBottomEdgeSwipeOffset;
90 |
91 | /** The m bottom view id map. */
92 | private Map mBottomViewIdMap = new HashMap();
93 |
94 | /** The m bottom view ids set. */
95 | private boolean mBottomViewIdsSet = false;
96 |
97 | /** The m swipe listeners. */
98 | private List mSwipeListeners = new ArrayList();
99 |
100 | /** The m swipe deniers. */
101 | private List mSwipeDeniers = new ArrayList();
102 |
103 | /** The m reveal listeners. */
104 | private Map> mRevealListeners = new HashMap>();
105 |
106 | /** The m show entirely. */
107 | private Map mShowEntirely = new HashMap();
108 |
109 | /** The m double click listener. */
110 | private DoubleClickListener mDoubleClickListener;
111 |
112 | /** The m swipe enabled. */
113 | private boolean mSwipeEnabled = true;
114 |
115 | /** The m left swipe enabled. */
116 | private boolean mLeftSwipeEnabled = true;
117 |
118 | /** The m right swipe enabled. */
119 | private boolean mRightSwipeEnabled = true;
120 |
121 | /** The m top swipe enabled. */
122 | private boolean mTopSwipeEnabled = true;
123 |
124 | /** The m bottom swipe enabled. */
125 | private boolean mBottomSwipeEnabled = true;
126 |
127 | /**
128 | * The Enum DragEdge.
129 | */
130 | public static enum DragEdge {
131 |
132 | /** The Left. */
133 | Left,
134 |
135 | /** The Right. */
136 | Right,
137 |
138 | /** The Top. */
139 | Top,
140 |
141 | /** The Bottom. */
142 | Bottom;
143 | }
144 |
145 | ;
146 |
147 | /**
148 | * The Enum ShowMode.
149 | */
150 | public static enum ShowMode {
151 |
152 | /** The Lay down. */
153 | LayDown,
154 |
155 | /** The Pull out. */
156 | PullOut
157 | }
158 |
159 | /**
160 | * Instantiates a new swipe layout.
161 | *
162 | * @param context the context
163 | */
164 | public SwipeLayout(Context context) {
165 | this(context, null);
166 | }
167 |
168 | /**
169 | * Instantiates a new swipe layout.
170 | *
171 | * @param context the context
172 | * @param attrs the attrs
173 | */
174 | public SwipeLayout(Context context, AttributeSet attrs) {
175 | this(context, attrs, 0);
176 | }
177 |
178 | /**
179 | * Instantiates a new swipe layout.
180 | *
181 | * @param context the context
182 | * @param attrs the attrs
183 | * @param defStyle the def style
184 | */
185 | public SwipeLayout(Context context, AttributeSet attrs, int defStyle) {
186 | super(context, attrs, defStyle);
187 | mDragHelper = ViewDragHelper.create(this, mDragHelperCallback);
188 | mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
189 |
190 | TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SwipeLayout);
191 | int dragEdgeChoices = a.getInt(R.styleable.SwipeLayout_drag_edge, DRAG_RIGHT);
192 | mLeftEdgeSwipeOffset = a.getDimension(R.styleable.SwipeLayout_leftEdgeSwipeOffset, 0);
193 | mRightEdgeSwipeOffset = a.getDimension(R.styleable.SwipeLayout_rightEdgeSwipeOffset, 0);
194 | mTopEdgeSwipeOffset = a.getDimension(R.styleable.SwipeLayout_topEdgeSwipeOffset, 0);
195 | mBottomEdgeSwipeOffset = a.getDimension(R.styleable.SwipeLayout_bottomEdgeSwipeOffset, 0);
196 |
197 | mDragEdges = new ArrayList();
198 | if ((dragEdgeChoices & DRAG_LEFT) == DRAG_LEFT) {
199 | mDragEdges.add(DragEdge.Left);
200 | }
201 | if ((dragEdgeChoices & DRAG_RIGHT) == DRAG_RIGHT) {
202 | mDragEdges.add(DragEdge.Right);
203 | }
204 | if ((dragEdgeChoices & DRAG_TOP) == DRAG_TOP) {
205 | mDragEdges.add(DragEdge.Top);
206 | }
207 | if ((dragEdgeChoices & DRAG_BOTTOM) == DRAG_BOTTOM) {
208 | mDragEdges.add(DragEdge.Bottom);
209 | }
210 | populateIndexes();
211 | int ordinal = a.getInt(R.styleable.SwipeLayout_show_mode, ShowMode.PullOut.ordinal());
212 | mShowMode = ShowMode.values()[ordinal];
213 | a.recycle();
214 | }
215 |
216 | /**
217 | * The listener interface for receiving swipe events.
218 | * The class that is interested in processing a swipe
219 | * event implements this interface, and the object created
220 | * with that class is registered with a component using the
221 | * component's addSwipeListener method. When
222 | * the swipe event occurs, that object's appropriate
223 | * method is invoked.
224 | *
225 | * @see SwipeEvent
226 | */
227 | public interface SwipeListener {
228 |
229 | /**
230 | * On start open.
231 | *
232 | * @param layout the layout
233 | */
234 | public void onStartOpen(SwipeLayout layout);
235 |
236 | /**
237 | * On open.
238 | *
239 | * @param layout the layout
240 | */
241 | public void onOpen(SwipeLayout layout);
242 |
243 | /**
244 | * On start close.
245 | *
246 | * @param layout the layout
247 | */
248 | public void onStartClose(SwipeLayout layout);
249 |
250 | /**
251 | * On close.
252 | *
253 | * @param layout the layout
254 | */
255 | public void onClose(SwipeLayout layout);
256 |
257 | /**
258 | * On update.
259 | *
260 | * @param layout the layout
261 | * @param leftOffset the left offset
262 | * @param topOffset the top offset
263 | */
264 | public void onUpdate(SwipeLayout layout, int leftOffset, int topOffset);
265 |
266 | /**
267 | * On hand release.
268 | *
269 | * @param layout the layout
270 | * @param xvel the xvel
271 | * @param yvel the yvel
272 | */
273 | public void onHandRelease(SwipeLayout layout, float xvel, float yvel);
274 | }
275 |
276 | /**
277 | * Adds the swipe listener.
278 | *
279 | * @param l the l
280 | */
281 | public void addSwipeListener(SwipeListener l) {
282 | mSwipeListeners.add(l);
283 | }
284 |
285 | /**
286 | * Removes the swipe listener.
287 | *
288 | * @param l the l
289 | */
290 | public void removeSwipeListener(SwipeListener l) {
291 | mSwipeListeners.remove(l);
292 | }
293 |
294 | /**
295 | * The Interface SwipeDenier.
296 | */
297 | public static interface SwipeDenier {
298 | /*
299 | * Called in onInterceptTouchEvent Determines if this swipe event should
300 | * be denied Implement this interface if you are using views with swipe
301 | * gestures As a child of SwipeLayout
302 | *
303 | * @return true deny false allow
304 | */
305 | /**
306 | * Should deny swipe.
307 | *
308 | * @param ev the ev
309 | * @return true, if successful
310 | */
311 | public boolean shouldDenySwipe(MotionEvent ev);
312 | }
313 |
314 | /**
315 | * Adds the swipe denier.
316 | *
317 | * @param denier the denier
318 | */
319 | public void addSwipeDenier(SwipeDenier denier) {
320 | mSwipeDeniers.add(denier);
321 | }
322 |
323 | /**
324 | * Removes the swipe denier.
325 | *
326 | * @param denier the denier
327 | */
328 | public void removeSwipeDenier(SwipeDenier denier) {
329 | mSwipeDeniers.remove(denier);
330 | }
331 |
332 | /**
333 | * Removes the all swipe deniers.
334 | */
335 | public void removeAllSwipeDeniers() {
336 | mSwipeDeniers.clear();
337 | }
338 |
339 | /**
340 | * The listener interface for receiving onReveal events.
341 | * The class that is interested in processing a onReveal
342 | * event implements this interface, and the object created
343 | * with that class is registered with a component using the
344 | * component's addOnRevealListener method. When
345 | * the onReveal event occurs, that object's appropriate
346 | * method is invoked.
347 | *
348 | * @see OnRevealEvent
349 | */
350 | public interface OnRevealListener {
351 |
352 | /**
353 | * On reveal.
354 | *
355 | * @param child the child
356 | * @param edge the edge
357 | * @param fraction the fraction
358 | * @param distance the distance
359 | */
360 | public void onReveal(View child, DragEdge edge, float fraction, int distance);
361 | }
362 |
363 | /**
364 | * bind a view with a specific
365 | *
366 | * @param childId the view id.
367 | * @param l the target
368 | */
369 | public void addRevealListener(int childId, OnRevealListener l) {
370 | View child = findViewById(childId);
371 | if (child == null) {
372 | throw new IllegalArgumentException("Child does not belong to SwipeListener.");
373 | }
374 |
375 | if (!mShowEntirely.containsKey(child)) {
376 | mShowEntirely.put(child, false);
377 | }
378 | if (mRevealListeners.get(child) == null)
379 | mRevealListeners.put(child, new ArrayList());
380 |
381 | mRevealListeners.get(child).add(l);
382 | }
383 |
384 | /**
385 | * bind multiple views with an
386 | *
387 | * @param childIds the view id.
388 | */
389 | public void addRevealListener(int[] childIds, OnRevealListener l) {
390 | for (int i : childIds)
391 | addRevealListener(i, l);
392 | }
393 |
394 | /**
395 | * Removes the reveal listener.
396 | *
397 | * @param childId the child id
398 | * @param l the l
399 | */
400 | public void removeRevealListener(int childId, OnRevealListener l) {
401 | View child = findViewById(childId);
402 |
403 | if (child == null) return;
404 |
405 | mShowEntirely.remove(child);
406 | if (mRevealListeners.containsKey(child)) mRevealListeners.get(child).remove(l);
407 | }
408 |
409 | /**
410 | * Removes the all reveal listeners.
411 | *
412 | * @param childId the child id
413 | */
414 | public void removeAllRevealListeners(int childId) {
415 | View child = findViewById(childId);
416 | if (child != null) {
417 | mRevealListeners.remove(child);
418 | mShowEntirely.remove(child);
419 | }
420 | }
421 |
422 | /** The m drag helper callback. */
423 | private ViewDragHelper.Callback mDragHelperCallback = new ViewDragHelper.Callback() {
424 |
425 | @Override
426 | public int clampViewPositionHorizontal(View child, int left, int dx) {
427 | if (child == getSurfaceView()) {
428 | switch (mDragEdges.get(mCurrentDirectionIndex)) {
429 | case Top:
430 | case Bottom:
431 | return getPaddingLeft();
432 | case Left:
433 | if (left < getPaddingLeft()) return getPaddingLeft();
434 | if (left > getPaddingLeft() + mDragDistance)
435 | return getPaddingLeft() + mDragDistance;
436 | break;
437 | case Right:
438 | if (left > getPaddingLeft()) return getPaddingLeft();
439 | if (left < getPaddingLeft() - mDragDistance)
440 | return getPaddingLeft() - mDragDistance;
441 | break;
442 | }
443 | } else if (getBottomViews().get(mCurrentDirectionIndex) == child) {
444 |
445 | switch (mDragEdges.get(mCurrentDirectionIndex)) {
446 | case Top:
447 | case Bottom:
448 | return getPaddingLeft();
449 | case Left:
450 | if (mShowMode == ShowMode.PullOut) {
451 | if (left > getPaddingLeft()) return getPaddingLeft();
452 | }
453 | break;
454 | case Right:
455 | if (mShowMode == ShowMode.PullOut) {
456 | if (left < getMeasuredWidth() - mDragDistance) {
457 | return getMeasuredWidth() - mDragDistance;
458 | }
459 | }
460 | break;
461 | }
462 | }
463 | return left;
464 | }
465 |
466 | @Override
467 | public int clampViewPositionVertical(View child, int top, int dy) {
468 | if (child == getSurfaceView()) {
469 | switch (mDragEdges.get(mCurrentDirectionIndex)) {
470 | case Left:
471 | case Right:
472 | return getPaddingTop();
473 | case Top:
474 | if (top < getPaddingTop()) return getPaddingTop();
475 | if (top > getPaddingTop() + mDragDistance)
476 | return getPaddingTop() + mDragDistance;
477 | break;
478 | case Bottom:
479 | if (top < getPaddingTop() - mDragDistance) {
480 | return getPaddingTop() - mDragDistance;
481 | }
482 | if (top > getPaddingTop()) {
483 | return getPaddingTop();
484 | }
485 | }
486 | } else {
487 | switch (mDragEdges.get(mCurrentDirectionIndex)) {
488 | case Left:
489 | case Right:
490 | return getPaddingTop();
491 | case Top:
492 | if (mShowMode == ShowMode.PullOut) {
493 | if (top > getPaddingTop()) return getPaddingTop();
494 | } else {
495 | if (getSurfaceView().getTop() + dy < getPaddingTop())
496 | return getPaddingTop();
497 | if (getSurfaceView().getTop() + dy > getPaddingTop() + mDragDistance)
498 | return getPaddingTop() + mDragDistance;
499 | }
500 | break;
501 | case Bottom:
502 | if (mShowMode == ShowMode.PullOut) {
503 | if (top < getMeasuredHeight() - mDragDistance)
504 | return getMeasuredHeight() - mDragDistance;
505 | } else {
506 | if (getSurfaceView().getTop() + dy >= getPaddingTop())
507 | return getPaddingTop();
508 | if (getSurfaceView().getTop() + dy <= getPaddingTop() - mDragDistance)
509 | return getPaddingTop() - mDragDistance;
510 | }
511 | }
512 | }
513 | return top;
514 | }
515 |
516 | @Override
517 | public boolean tryCaptureView(View child, int pointerId) {
518 | return child == getSurfaceView() || getBottomViews().contains(child);
519 | }
520 |
521 | @Override
522 | public int getViewHorizontalDragRange(View child) {
523 | return mDragDistance;
524 | }
525 |
526 | @Override
527 | public int getViewVerticalDragRange(View child) {
528 | return mDragDistance;
529 | }
530 |
531 | @Override
532 | public void onViewReleased(View releasedChild, float xvel, float yvel) {
533 | super.onViewReleased(releasedChild, xvel, yvel);
534 | for (SwipeListener l : mSwipeListeners)
535 | l.onHandRelease(SwipeLayout.this, xvel, yvel);
536 | if (releasedChild == getSurfaceView()) {
537 | processSurfaceRelease(xvel, yvel);
538 | } else if (getBottomViews().contains(releasedChild)) {
539 | if (getShowMode() == ShowMode.PullOut) {
540 | processBottomPullOutRelease(xvel, yvel);
541 | } else if (getShowMode() == ShowMode.LayDown) {
542 | processBottomLayDownMode(xvel, yvel);
543 | }
544 | }
545 |
546 | invalidate();
547 | }
548 |
549 | @Override
550 | public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
551 | int evLeft = getSurfaceView().getLeft(), evRight = getSurfaceView().getRight(), evTop = getSurfaceView()
552 | .getTop(), evBottom = getSurfaceView().getBottom();
553 | if (changedView == getSurfaceView()) {
554 |
555 | if (mShowMode == ShowMode.PullOut) {
556 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left
557 | || mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right)
558 | getBottomViews().get(mCurrentDirectionIndex).offsetLeftAndRight(dx);
559 | else getBottomViews().get(mCurrentDirectionIndex).offsetTopAndBottom(dy);
560 | }
561 |
562 | } else if (getBottomViews().contains(changedView)) {
563 |
564 | if (mShowMode == ShowMode.PullOut) {
565 | getSurfaceView().offsetLeftAndRight(dx);
566 | getSurfaceView().offsetTopAndBottom(dy);
567 | } else {
568 | Rect rect = computeBottomLayDown(mDragEdges.get(mCurrentDirectionIndex));
569 | getBottomViews().get(mCurrentDirectionIndex).layout(rect.left, rect.top, rect.right, rect.bottom);
570 |
571 | int newLeft = getSurfaceView().getLeft() + dx, newTop = getSurfaceView().getTop() + dy;
572 |
573 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left && newLeft < getPaddingLeft())
574 | newLeft = getPaddingLeft();
575 | else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right && newLeft > getPaddingLeft())
576 | newLeft = getPaddingLeft();
577 | else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top && newTop < getPaddingTop())
578 | newTop = getPaddingTop();
579 | else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Bottom && newTop > getPaddingTop())
580 | newTop = getPaddingTop();
581 |
582 | getSurfaceView()
583 | .layout(newLeft, newTop, newLeft + getMeasuredWidth(), newTop + getMeasuredHeight());
584 | }
585 | }
586 |
587 | dispatchRevealEvent(evLeft, evTop, evRight, evBottom);
588 |
589 | dispatchSwipeEvent(evLeft, evTop, dx, dy);
590 |
591 | invalidate();
592 | }
593 | };
594 |
595 | /**
596 | * the dispatchRevealEvent method may not always get accurate position, it
597 | * makes the view may not always get the event when the view is totally
598 | * show( fraction = 1), so , we need to calculate every time.
599 | *
600 | * @param child the child
601 | * @param relativePosition the relative position
602 | * @param edge the edge
603 | * @param surfaceLeft the surface left
604 | * @param surfaceTop the surface top
605 | * @param surfaceRight the surface right
606 | * @param surfaceBottom the surface bottom
607 | * @return true, if is view totally first showed
608 | */
609 | protected boolean isViewTotallyFirstShowed(View child, Rect relativePosition, DragEdge edge, int surfaceLeft,
610 | int surfaceTop, int surfaceRight, int surfaceBottom) {
611 | if (mShowEntirely.get(child)) return false;
612 | int childLeft = relativePosition.left;
613 | int childRight = relativePosition.right;
614 | int childTop = relativePosition.top;
615 | int childBottom = relativePosition.bottom;
616 | boolean r = false;
617 | if (getShowMode() == ShowMode.LayDown) {
618 | if ((edge == DragEdge.Right && surfaceRight <= childLeft)
619 | || (edge == DragEdge.Left && surfaceLeft >= childRight)
620 | || (edge == DragEdge.Top && surfaceTop >= childBottom)
621 | || (edge == DragEdge.Bottom && surfaceBottom <= childTop)) r = true;
622 | } else if (getShowMode() == ShowMode.PullOut) {
623 | if ((edge == DragEdge.Right && childRight <= getWidth())
624 | || (edge == DragEdge.Left && childLeft >= getPaddingLeft())
625 | || (edge == DragEdge.Top && childTop >= getPaddingTop())
626 | || (edge == DragEdge.Bottom && childBottom <= getHeight())) r = true;
627 | }
628 | return r;
629 | }
630 |
631 | /**
632 | * Checks if is view showing.
633 | *
634 | * @param child the child
635 | * @param relativePosition the relative position
636 | * @param availableEdge the available edge
637 | * @param surfaceLeft the surface left
638 | * @param surfaceTop the surface top
639 | * @param surfaceRight the surface right
640 | * @param surfaceBottom the surface bottom
641 | * @return true, if is view showing
642 | */
643 | protected boolean isViewShowing(View child, Rect relativePosition, DragEdge availableEdge, int surfaceLeft,
644 | int surfaceTop, int surfaceRight, int surfaceBottom) {
645 | int childLeft = relativePosition.left;
646 | int childRight = relativePosition.right;
647 | int childTop = relativePosition.top;
648 | int childBottom = relativePosition.bottom;
649 | if (getShowMode() == ShowMode.LayDown) {
650 | switch (availableEdge) {
651 | case Right:
652 | if (surfaceRight > childLeft && surfaceRight <= childRight) {
653 | return true;
654 | }
655 | break;
656 | case Left:
657 | if (surfaceLeft < childRight && surfaceLeft >= childLeft) {
658 | return true;
659 | }
660 | break;
661 | case Top:
662 | if (surfaceTop >= childTop && surfaceTop < childBottom) {
663 | return true;
664 | }
665 | break;
666 | case Bottom:
667 | if (surfaceBottom > childTop && surfaceBottom <= childBottom) {
668 | return true;
669 | }
670 | break;
671 | }
672 | } else if (getShowMode() == ShowMode.PullOut) {
673 | switch (availableEdge) {
674 | case Right:
675 | if (childLeft <= getWidth() && childRight > getWidth()) return true;
676 | break;
677 | case Left:
678 | if (childRight >= getPaddingLeft() && childLeft < getPaddingLeft()) return true;
679 | break;
680 | case Top:
681 | if (childTop < getPaddingTop() && childBottom >= getPaddingTop()) return true;
682 | break;
683 | case Bottom:
684 | if (childTop < getHeight() && childTop >= getPaddingTop()) return true;
685 | break;
686 | }
687 | }
688 | return false;
689 | }
690 |
691 | /**
692 | * Gets the relative position.
693 | *
694 | * @param child the child
695 | * @return the relative position
696 | */
697 | protected Rect getRelativePosition(View child) {
698 | View t = child;
699 | Rect r = new Rect(t.getLeft(), t.getTop(), 0, 0);
700 | while (t.getParent() != null && t != getRootView()) {
701 | t = (View) t.getParent();
702 | if (t == this) break;
703 | r.left += t.getLeft();
704 | r.top += t.getTop();
705 | }
706 | r.right = r.left + child.getMeasuredWidth();
707 | r.bottom = r.top + child.getMeasuredHeight();
708 | return r;
709 | }
710 |
711 | /** The m event counter. */
712 | private int mEventCounter = 0;
713 |
714 | /**
715 | * Dispatch swipe event.
716 | *
717 | * @param surfaceLeft the surface left
718 | * @param surfaceTop the surface top
719 | * @param dx the dx
720 | * @param dy the dy
721 | */
722 | protected void dispatchSwipeEvent(int surfaceLeft, int surfaceTop, int dx, int dy) {
723 | DragEdge edge = getDragEdge();
724 | boolean open = true;
725 | if (edge == DragEdge.Left) {
726 | if (dx < 0) open = false;
727 | } else if (edge == DragEdge.Right) {
728 | if (dx > 0) open = false;
729 | } else if (edge == DragEdge.Top) {
730 | if (dy < 0) open = false;
731 | } else if (edge == DragEdge.Bottom) {
732 | if (dy > 0) open = false;
733 | }
734 |
735 | dispatchSwipeEvent(surfaceLeft, surfaceTop, open);
736 | }
737 |
738 | /**
739 | * Dispatch swipe event.
740 | *
741 | * @param surfaceLeft the surface left
742 | * @param surfaceTop the surface top
743 | * @param open the open
744 | */
745 | protected void dispatchSwipeEvent(int surfaceLeft, int surfaceTop, boolean open) {
746 | safeBottomView();
747 | Status status = getOpenStatus();
748 |
749 | if (!mSwipeListeners.isEmpty()) {
750 | mEventCounter++;
751 | for (SwipeListener l : mSwipeListeners) {
752 | if (mEventCounter == 1) {
753 | if (open) {
754 | l.onStartOpen(this);
755 | } else {
756 | l.onStartClose(this);
757 | }
758 | }
759 | l.onUpdate(SwipeLayout.this, surfaceLeft - getPaddingLeft(), surfaceTop - getPaddingTop());
760 | }
761 |
762 | if (status == Status.Close) {
763 | for (SwipeListener l : mSwipeListeners) {
764 | l.onClose(SwipeLayout.this);
765 | }
766 | mEventCounter = 0;
767 | }
768 |
769 | if (status == Status.Open) {
770 | getBottomViews().get(mCurrentDirectionIndex).setEnabled(true);
771 | for (SwipeListener l : mSwipeListeners) {
772 | l.onOpen(SwipeLayout.this);
773 | }
774 | mEventCounter = 0;
775 | }
776 | }
777 | }
778 |
779 | /**
780 | * prevent bottom view get any touch event. Especially in LayDown mode.
781 | */
782 | private void safeBottomView() {
783 | Status status = getOpenStatus();
784 | List bottoms = getBottomViews();
785 |
786 | if (status == Status.Close) {
787 | for (ViewGroup bottom : bottoms) {
788 | if (bottom.getVisibility() != INVISIBLE) bottom.setVisibility(INVISIBLE);
789 | }
790 | } else {
791 | if (bottoms.get(mCurrentDirectionIndex).getVisibility() != VISIBLE)
792 | bottoms.get(mCurrentDirectionIndex).setVisibility(VISIBLE);
793 | }
794 | }
795 |
796 | /**
797 | * Dispatch reveal event.
798 | *
799 | * @param surfaceLeft the surface left
800 | * @param surfaceTop the surface top
801 | * @param surfaceRight the surface right
802 | * @param surfaceBottom the surface bottom
803 | */
804 | protected void dispatchRevealEvent(final int surfaceLeft, final int surfaceTop, final int surfaceRight,
805 | final int surfaceBottom) {
806 | if (mRevealListeners.isEmpty()) return;
807 | for (Map.Entry> entry : mRevealListeners.entrySet()) {
808 | View child = entry.getKey();
809 | Rect rect = getRelativePosition(child);
810 | if (isViewShowing(child, rect, mDragEdges.get(mCurrentDirectionIndex), surfaceLeft, surfaceTop,
811 | surfaceRight, surfaceBottom)) {
812 | mShowEntirely.put(child, false);
813 | int distance = 0;
814 | float fraction = 0f;
815 | if (getShowMode() == ShowMode.LayDown) {
816 | switch (mDragEdges.get(mCurrentDirectionIndex)) {
817 | case Left:
818 | distance = rect.left - surfaceLeft;
819 | fraction = distance / (float) child.getWidth();
820 | break;
821 | case Right:
822 | distance = rect.right - surfaceRight;
823 | fraction = distance / (float) child.getWidth();
824 | break;
825 | case Top:
826 | distance = rect.top - surfaceTop;
827 | fraction = distance / (float) child.getHeight();
828 | break;
829 | case Bottom:
830 | distance = rect.bottom - surfaceBottom;
831 | fraction = distance / (float) child.getHeight();
832 | break;
833 | }
834 | } else if (getShowMode() == ShowMode.PullOut) {
835 | switch (mDragEdges.get(mCurrentDirectionIndex)) {
836 | case Left:
837 | distance = rect.right - getPaddingLeft();
838 | fraction = distance / (float) child.getWidth();
839 | break;
840 | case Right:
841 | distance = rect.left - getWidth();
842 | fraction = distance / (float) child.getWidth();
843 | break;
844 | case Top:
845 | distance = rect.bottom - getPaddingTop();
846 | fraction = distance / (float) child.getHeight();
847 | break;
848 | case Bottom:
849 | distance = rect.top - getHeight();
850 | fraction = distance / (float) child.getHeight();
851 | break;
852 | }
853 | }
854 |
855 | for (OnRevealListener l : entry.getValue()) {
856 | l.onReveal(child, mDragEdges.get(mCurrentDirectionIndex), Math.abs(fraction), distance);
857 | if (Math.abs(fraction) == 1) {
858 | mShowEntirely.put(child, true);
859 | }
860 | }
861 | }
862 |
863 | if (isViewTotallyFirstShowed(child, rect, mDragEdges.get(mCurrentDirectionIndex), surfaceLeft, surfaceTop,
864 | surfaceRight, surfaceBottom)) {
865 | mShowEntirely.put(child, true);
866 | for (OnRevealListener l : entry.getValue()) {
867 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left
868 | || mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right)
869 | l.onReveal(child, mDragEdges.get(mCurrentDirectionIndex), 1, child.getWidth());
870 | else
871 | l.onReveal(child, mDragEdges.get(mCurrentDirectionIndex), 1, child.getHeight());
872 | }
873 | }
874 |
875 | }
876 | }
877 |
878 | /* (non-Javadoc)
879 | * @see android.view.View#computeScroll()
880 | */
881 | @Override
882 | public void computeScroll() {
883 | super.computeScroll();
884 | if (mDragHelper.continueSettling(true)) {
885 | ViewCompat.postInvalidateOnAnimation(this);
886 | }
887 | }
888 |
889 | /**
890 | * {@link android.view.View.OnLayoutChangeListener} added in API 11. I need
891 | * to support it from API 8.
892 | */
893 | public interface OnLayout {
894 |
895 | /**
896 | * On layout.
897 | *
898 | * @param v the v
899 | */
900 | public void onLayout(SwipeLayout v);
901 | }
902 |
903 | /** The m on layout listeners. */
904 | private List mOnLayoutListeners;
905 |
906 | /**
907 | * Adds the on layout listener.
908 | *
909 | * @param l the l
910 | */
911 | public void addOnLayoutListener(OnLayout l) {
912 | if (mOnLayoutListeners == null) mOnLayoutListeners = new ArrayList();
913 | mOnLayoutListeners.add(l);
914 | }
915 |
916 | /**
917 | * Removes the on layout listener.
918 | *
919 | * @param l the l
920 | */
921 | public void removeOnLayoutListener(OnLayout l) {
922 | if (mOnLayoutListeners != null) mOnLayoutListeners.remove(l);
923 | }
924 |
925 | /* (non-Javadoc)
926 | * @see android.widget.FrameLayout#onLayout(boolean, int, int, int, int)
927 | */
928 | @Override
929 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
930 | int childCount = getChildCount();
931 | if (childCount != 1 + mDragEdges.size()) {
932 | throw new IllegalStateException("You need to have one surface view plus one view for each of your drag edges");
933 | }
934 | for (int i = 0; i < childCount; i++) {
935 | if (!(getChildAt(i) instanceof ViewGroup)) {
936 | throw new IllegalArgumentException("All the children in SwipeLayout must be an instance of ViewGroup");
937 | }
938 | }
939 |
940 | if (mShowMode == ShowMode.PullOut)
941 | layoutPullOut();
942 | else if (mShowMode == ShowMode.LayDown) layoutLayDown();
943 |
944 | safeBottomView();
945 |
946 | if (mOnLayoutListeners != null) for (int i = 0; i < mOnLayoutListeners.size(); i++) {
947 | mOnLayoutListeners.get(i).onLayout(this);
948 | }
949 |
950 | }
951 |
952 | /**
953 | * Layout pull out.
954 | */
955 | void layoutPullOut() {
956 | Rect rect = computeSurfaceLayoutArea(false);
957 | getSurfaceView().layout(rect.left, rect.top, rect.right, rect.bottom);
958 | rect = computeBottomLayoutAreaViaSurface(ShowMode.PullOut, rect);
959 | getBottomViews().get(mCurrentDirectionIndex).layout(rect.left, rect.top, rect.right, rect.bottom);
960 | bringChildToFront(getSurfaceView());
961 | }
962 |
963 | /**
964 | * Layout lay down.
965 | */
966 | void layoutLayDown() {
967 | Rect rect = computeSurfaceLayoutArea(false);
968 | getSurfaceView().layout(rect.left, rect.top, rect.right, rect.bottom);
969 | rect = computeBottomLayoutAreaViaSurface(ShowMode.LayDown, rect);
970 | getBottomViews().get(mCurrentDirectionIndex).layout(rect.left, rect.top, rect.right, rect.bottom);
971 | bringChildToFront(getSurfaceView());
972 | }
973 |
974 | /* (non-Javadoc)
975 | * @see android.widget.FrameLayout#onMeasure(int, int)
976 | */
977 | @Override
978 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
979 | super.onMeasure(widthMeasureSpec, heightMeasureSpec);
980 |
981 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left
982 | || mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right)
983 | mDragDistance = getBottomViews().get(mCurrentDirectionIndex).getMeasuredWidth()
984 | - dp2px(getCurrentOffset());
985 | else mDragDistance = getBottomViews().get(mCurrentDirectionIndex).getMeasuredHeight()
986 | - dp2px(getCurrentOffset());
987 | }
988 |
989 | /** The m touch consumed by child. */
990 | private boolean mTouchConsumedByChild = false;
991 |
992 | /* (non-Javadoc)
993 | * @see android.view.ViewGroup#onInterceptTouchEvent(android.view.MotionEvent)
994 | */
995 | @Override
996 | public boolean onInterceptTouchEvent(MotionEvent ev) {
997 |
998 | if (!isEnabled() || !isEnabledInAdapterView()) {
999 | return true;
1000 | }
1001 |
1002 | if (!isSwipeEnabled()) {
1003 | return false;
1004 | }
1005 |
1006 | for (SwipeDenier denier : mSwipeDeniers) {
1007 | if (denier != null && denier.shouldDenySwipe(ev)) {
1008 | return false;
1009 | }
1010 | }
1011 | //
1012 | // if a child wants to handle the touch event,
1013 | // then let it do it.
1014 | //
1015 | int action = ev.getActionMasked();
1016 | switch (action) {
1017 | case MotionEvent.ACTION_DOWN:
1018 | Status status = getOpenStatus();
1019 | if (status == Status.Close) {
1020 | mTouchConsumedByChild = childNeedHandleTouchEvent(getSurfaceView(), ev) != null;
1021 | } else if (status == Status.Open) {
1022 | mTouchConsumedByChild = childNeedHandleTouchEvent(getBottomViews().get(mCurrentDirectionIndex), ev) != null;
1023 | }
1024 | break;
1025 | case MotionEvent.ACTION_UP:
1026 | case MotionEvent.ACTION_CANCEL:
1027 | mTouchConsumedByChild = false;
1028 | }
1029 |
1030 | if (mTouchConsumedByChild) return false;
1031 | return mDragHelper.shouldInterceptTouchEvent(ev);
1032 | }
1033 |
1034 | /**
1035 | * if the ViewGroup children want to handle this event.
1036 | *
1037 | * @param v the v
1038 | * @param event the event
1039 | * @return the view
1040 | */
1041 | private View childNeedHandleTouchEvent(ViewGroup v, MotionEvent event) {
1042 | if (v == null) return null;
1043 | if (v.onTouchEvent(event)) return v;
1044 |
1045 | int childCount = v.getChildCount();
1046 | for (int i = childCount - 1; i >= 0; i--) {
1047 | View child = v.getChildAt(i);
1048 | if (child instanceof ViewGroup) {
1049 | View grandChild = childNeedHandleTouchEvent((ViewGroup) child, event);
1050 | if (grandChild != null) return grandChild;
1051 | } else {
1052 | if (childNeedHandleTouchEvent(v.getChildAt(i), event)) return v.getChildAt(i);
1053 | }
1054 | }
1055 | return null;
1056 | }
1057 |
1058 | /**
1059 | * if the view (v) wants to handle this event.
1060 | *
1061 | * @param v the v
1062 | * @param event the event
1063 | * @return true, if successful
1064 | */
1065 | private boolean childNeedHandleTouchEvent(View v, MotionEvent event) {
1066 | if (v == null) return false;
1067 |
1068 | int[] loc = new int[2];
1069 | v.getLocationOnScreen(loc);
1070 | int left = loc[0], top = loc[1];
1071 |
1072 | if (event.getRawX() > left && event.getRawX() < left + v.getWidth() && event.getRawY() > top
1073 | && event.getRawY() < top + v.getHeight()) {
1074 | return v.onTouchEvent(event);
1075 | }
1076 |
1077 | return false;
1078 | }
1079 |
1080 | /** The s y. */
1081 | private float sX = -1, sY = -1;
1082 |
1083 | /**
1084 | * Should allow swipe.
1085 | *
1086 | * @return true, if successful
1087 | */
1088 | private boolean shouldAllowSwipe() {
1089 | if (mCurrentDirectionIndex == mLeftIndex && !mLeftSwipeEnabled) return false;
1090 | if (mCurrentDirectionIndex == mRightIndex && !mRightSwipeEnabled) return false;
1091 | if (mCurrentDirectionIndex == mTopIndex && !mTopSwipeEnabled) return false;
1092 | if (mCurrentDirectionIndex == mBottomIndex && !mBottomSwipeEnabled) return false;
1093 | return true;
1094 | }
1095 |
1096 | /* (non-Javadoc)
1097 | * @see android.view.View#onTouchEvent(android.view.MotionEvent)
1098 | */
1099 | @Override
1100 | public boolean onTouchEvent(MotionEvent event) {
1101 | if (!isEnabledInAdapterView() || !isEnabled()) return true;
1102 |
1103 | if (!isSwipeEnabled()) return super.onTouchEvent(event);
1104 |
1105 | int action = event.getActionMasked();
1106 | ViewParent parent = getParent();
1107 |
1108 | gestureDetector.onTouchEvent(event);
1109 | Status status = getOpenStatus();
1110 | ViewGroup touching = null;
1111 | if (status == Status.Close) {
1112 | touching = getSurfaceView();
1113 | } else if (status == Status.Open) {
1114 | touching = getBottomViews().get(mCurrentDirectionIndex);
1115 | }
1116 |
1117 | switch (action) {
1118 | case MotionEvent.ACTION_DOWN:
1119 | mDragHelper.processTouchEvent(event);
1120 | parent.requestDisallowInterceptTouchEvent(true);
1121 |
1122 | sX = event.getRawX();
1123 | sY = event.getRawY();
1124 |
1125 | if (touching != null) touching.setPressed(true);
1126 | return true;
1127 | case MotionEvent.ACTION_MOVE: {
1128 | float distanceX = event.getRawX() - sX;
1129 | float distanceY = event.getRawY() - sY;
1130 | float angle = Math.abs(distanceY / distanceX);
1131 | angle = (float) Math.toDegrees(Math.atan(angle));
1132 | if (getOpenStatus() == Status.Close) {
1133 | int lastCurrentDirectionIndex = mCurrentDirectionIndex;
1134 | if (angle < 45) {
1135 | if (mLeftIndex != -1 && distanceX > 0 && isLeftSwipeEnabled()) {
1136 | mCurrentDirectionIndex = mLeftIndex;
1137 | } else if (mRightIndex != -1 && distanceX < 0 && isRightSwipeEnabled()) {
1138 | mCurrentDirectionIndex = mRightIndex;
1139 | }
1140 | } else {
1141 | if (mTopIndex != -1 && distanceY > 0 && isTopSwipeEnabled()) {
1142 | mCurrentDirectionIndex = mTopIndex;
1143 | } else if (mBottomIndex != -1 && distanceY < 0 && isBottomSwipeEnabled()) {
1144 | mCurrentDirectionIndex = mBottomIndex;
1145 | }
1146 | }
1147 | if (lastCurrentDirectionIndex != mCurrentDirectionIndex) {
1148 | updateBottomViews();
1149 | }
1150 | }
1151 | if (!shouldAllowSwipe()) return super.onTouchEvent(event);
1152 |
1153 | boolean doNothing = false;
1154 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) {
1155 | boolean suitable = (status == Status.Open && distanceX > mTouchSlop)
1156 | || (status == Status.Close && distanceX < -mTouchSlop);
1157 | suitable = suitable || (status == Status.Middle);
1158 |
1159 | if (angle > 30 || !suitable) {
1160 | doNothing = true;
1161 | }
1162 | }
1163 |
1164 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) {
1165 | boolean suitable = (status == Status.Open && distanceX < -mTouchSlop)
1166 | || (status == Status.Close && distanceX > mTouchSlop);
1167 | suitable = suitable || status == Status.Middle;
1168 |
1169 | if (angle > 30 || !suitable) {
1170 | doNothing = true;
1171 | }
1172 | }
1173 |
1174 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top) {
1175 | boolean suitable = (status == Status.Open && distanceY < -mTouchSlop)
1176 | || (status == Status.Close && distanceY > mTouchSlop);
1177 | suitable = suitable || status == Status.Middle;
1178 |
1179 | if (angle < 60 || !suitable) {
1180 | doNothing = true;
1181 | }
1182 | }
1183 |
1184 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Bottom) {
1185 | boolean suitable = (status == Status.Open && distanceY > mTouchSlop)
1186 | || (status == Status.Close && distanceY < -mTouchSlop);
1187 | suitable = suitable || status == Status.Middle;
1188 |
1189 | if (angle < 60 || !suitable) {
1190 | doNothing = true;
1191 | }
1192 | }
1193 |
1194 | if (doNothing) {
1195 | parent.requestDisallowInterceptTouchEvent(false);
1196 | return false;
1197 | } else {
1198 | if (touching != null) {
1199 | touching.setPressed(false);
1200 | }
1201 | parent.requestDisallowInterceptTouchEvent(true);
1202 | mDragHelper.processTouchEvent(event);
1203 | }
1204 | break;
1205 | }
1206 | case MotionEvent.ACTION_UP:
1207 | case MotionEvent.ACTION_CANCEL: {
1208 | sX = -1;
1209 | sY = -1;
1210 | if (touching != null) {
1211 | touching.setPressed(false);
1212 | }
1213 | }
1214 | default:
1215 | parent.requestDisallowInterceptTouchEvent(true);
1216 | mDragHelper.processTouchEvent(event);
1217 | }
1218 |
1219 | return true;
1220 | }
1221 |
1222 | /**
1223 | * if working in {@link android.widget.AdapterView}, we should response
1224 | * {@link android.widget.Adapter} isEnable(int position).
1225 | *
1226 | * @return true when item is enabled, else disabled.
1227 | */
1228 | private boolean isEnabledInAdapterView() {
1229 | AdapterView adapterView = getAdapterView();
1230 | boolean enable = true;
1231 | if (adapterView != null) {
1232 | Adapter adapter = adapterView.getAdapter();
1233 | if (adapter != null) {
1234 | int p = adapterView.getPositionForView(SwipeLayout.this);
1235 | if (adapter instanceof BaseAdapter) {
1236 | enable = ((BaseAdapter) adapter).isEnabled(p);
1237 | } else if (adapter instanceof ListAdapter) {
1238 | enable = ((ListAdapter) adapter).isEnabled(p);
1239 | }
1240 | }
1241 | }
1242 | return enable;
1243 | }
1244 |
1245 | /**
1246 | * Sets the swipe enabled.
1247 | *
1248 | * @param enabled the new swipe enabled
1249 | */
1250 | public void setSwipeEnabled(boolean enabled) {
1251 | mSwipeEnabled = enabled;
1252 | }
1253 |
1254 | /**
1255 | * Checks if is swipe enabled.
1256 | *
1257 | * @return true, if is swipe enabled
1258 | */
1259 | public boolean isSwipeEnabled() {
1260 | return mSwipeEnabled;
1261 | }
1262 |
1263 | /**
1264 | * Checks if is left swipe enabled.
1265 | *
1266 | * @return true, if is left swipe enabled
1267 | */
1268 | public boolean isLeftSwipeEnabled() {
1269 | return mLeftSwipeEnabled;
1270 | }
1271 |
1272 | /**
1273 | * Sets the left swipe enabled.
1274 | *
1275 | * @param leftSwipeEnabled the new left swipe enabled
1276 | */
1277 | public void setLeftSwipeEnabled(boolean leftSwipeEnabled) {
1278 | this.mLeftSwipeEnabled = leftSwipeEnabled;
1279 | }
1280 |
1281 | /**
1282 | * Checks if is right swipe enabled.
1283 | *
1284 | * @return true, if is right swipe enabled
1285 | */
1286 | public boolean isRightSwipeEnabled() {
1287 | return mRightSwipeEnabled;
1288 | }
1289 |
1290 | /**
1291 | * Sets the right swipe enabled.
1292 | *
1293 | * @param rightSwipeEnabled the new right swipe enabled
1294 | */
1295 | public void setRightSwipeEnabled(boolean rightSwipeEnabled) {
1296 | this.mRightSwipeEnabled = rightSwipeEnabled;
1297 | }
1298 |
1299 | /**
1300 | * Checks if is top swipe enabled.
1301 | *
1302 | * @return true, if is top swipe enabled
1303 | */
1304 | public boolean isTopSwipeEnabled() {
1305 | return mTopSwipeEnabled;
1306 | }
1307 |
1308 | /**
1309 | * Sets the top swipe enabled.
1310 | *
1311 | * @param topSwipeEnabled the new top swipe enabled
1312 | */
1313 | public void setTopSwipeEnabled(boolean topSwipeEnabled) {
1314 | this.mTopSwipeEnabled = topSwipeEnabled;
1315 | }
1316 |
1317 | /**
1318 | * Checks if is bottom swipe enabled.
1319 | *
1320 | * @return true, if is bottom swipe enabled
1321 | */
1322 | public boolean isBottomSwipeEnabled() {
1323 | return mBottomSwipeEnabled;
1324 | }
1325 |
1326 | /**
1327 | * Sets the bottom swipe enabled.
1328 | *
1329 | * @param bottomSwipeEnabled the new bottom swipe enabled
1330 | */
1331 | public void setBottomSwipeEnabled(boolean bottomSwipeEnabled) {
1332 | this.mBottomSwipeEnabled = bottomSwipeEnabled;
1333 | }
1334 |
1335 | /**
1336 | * Inside adapter view.
1337 | *
1338 | * @return true, if successful
1339 | */
1340 | private boolean insideAdapterView() {
1341 | return getAdapterView() != null;
1342 | }
1343 |
1344 | /**
1345 | * Gets the adapter view.
1346 | *
1347 | * @return the adapter view
1348 | */
1349 | private AdapterView getAdapterView() {
1350 | ViewParent t = getParent();
1351 | while (t != null) {
1352 | if (t instanceof AdapterView) {
1353 | return (AdapterView) t;
1354 | }
1355 | t = t.getParent();
1356 | }
1357 | return null;
1358 | }
1359 |
1360 | /**
1361 | * Perform adapter view item click.
1362 | *
1363 | * @param e the e
1364 | */
1365 | private void performAdapterViewItemClick(MotionEvent e) {
1366 | ViewParent t = getParent();
1367 | while (t != null) {
1368 | if (t instanceof AdapterView) {
1369 | AdapterView view = (AdapterView) t;
1370 | int p = view.getPositionForView(SwipeLayout.this);
1371 | if (p != AdapterView.INVALID_POSITION
1372 | && view.performItemClick(view.getChildAt(p - view.getFirstVisiblePosition()), p, view
1373 | .getAdapter().getItemId(p))) return;
1374 | } else {
1375 | if (t instanceof View && ((View) t).performClick()) return;
1376 | }
1377 | t = t.getParent();
1378 | }
1379 | }
1380 |
1381 | /** The gesture detector. */
1382 | private GestureDetector gestureDetector = new GestureDetector(getContext(), new SwipeDetector());
1383 |
1384 | /**
1385 | * The Class SwipeDetector.
1386 | */
1387 | class SwipeDetector extends GestureDetector.SimpleOnGestureListener {
1388 |
1389 | /* (non-Javadoc)
1390 | * @see android.view.GestureDetector.SimpleOnGestureListener#onDown(android.view.MotionEvent)
1391 | */
1392 | @Override
1393 | public boolean onDown(MotionEvent e) {
1394 | return true;
1395 | }
1396 |
1397 | /**
1398 | * Simulate the touch event lifecycle. If you use SwipeLayout in
1399 | * {@link android.widget.AdapterView} ({@link android.widget.ListView},
1400 | * {@link android.widget.GridView} etc.) It will manually call
1401 | * {@link android.widget.AdapterView}.performItemClick,
1402 | * performItemLongClick.
1403 | *
1404 | * @param e the e
1405 | * @return true, if successful
1406 | */
1407 | @Override
1408 | public boolean onSingleTapUp(MotionEvent e) {
1409 | if (mDoubleClickListener == null) {
1410 | performAdapterViewItemClick(e);
1411 | }
1412 | return true;
1413 | }
1414 |
1415 | /* (non-Javadoc)
1416 | * @see android.view.GestureDetector.SimpleOnGestureListener#onSingleTapConfirmed(android.view.MotionEvent)
1417 | */
1418 | @Override
1419 | public boolean onSingleTapConfirmed(MotionEvent e) {
1420 | if (mDoubleClickListener != null) {
1421 | performAdapterViewItemClick(e);
1422 | }
1423 | return true;
1424 | }
1425 |
1426 | /* (non-Javadoc)
1427 | * @see android.view.GestureDetector.SimpleOnGestureListener#onLongPress(android.view.MotionEvent)
1428 | */
1429 | @Override
1430 | public void onLongPress(MotionEvent e) {
1431 | performLongClick();
1432 | }
1433 |
1434 | /* (non-Javadoc)
1435 | * @see android.view.GestureDetector.SimpleOnGestureListener#onDoubleTap(android.view.MotionEvent)
1436 | */
1437 | @Override
1438 | public boolean onDoubleTap(MotionEvent e) {
1439 | if (mDoubleClickListener != null) {
1440 | View target;
1441 | ViewGroup bottom = getBottomViews().get(mCurrentDirectionIndex);
1442 | ViewGroup surface = getSurfaceView();
1443 | if (e.getX() > bottom.getLeft() && e.getX() < bottom.getRight() && e.getY() > bottom.getTop()
1444 | && e.getY() < bottom.getBottom()) {
1445 | target = bottom;
1446 | } else {
1447 | target = surface;
1448 | }
1449 | mDoubleClickListener.onDoubleClick(SwipeLayout.this, target == surface);
1450 | }
1451 | return true;
1452 | }
1453 | }
1454 |
1455 | /**
1456 | * Sets the drag edge.
1457 | *
1458 | * @param dragEdge the new drag edge
1459 | */
1460 | public void setDragEdge(DragEdge dragEdge) {
1461 | mDragEdges = new ArrayList();
1462 | mDragEdges.add(dragEdge);
1463 | mCurrentDirectionIndex = 0;
1464 | populateIndexes();
1465 | requestLayout();
1466 | updateBottomViews();
1467 | }
1468 |
1469 | /**
1470 | * set the drag distance, it will force set the bottom view's width or
1471 | * height via this value.
1472 | *
1473 | * @param max the new drag distance
1474 | */
1475 | public void setDragDistance(int max) {
1476 | if (max < 0) throw new IllegalArgumentException("Drag distance can not be < 0");
1477 | mDragDistance = dp2px(max);
1478 | requestLayout();
1479 | }
1480 |
1481 | /**
1482 | * There are 2 diffirent show mode.
1483 | *
1484 | * @param mode the new show mode
1485 | */
1486 | public void setShowMode(ShowMode mode) {
1487 | mShowMode = mode;
1488 | requestLayout();
1489 | }
1490 |
1491 | /**
1492 | * Gets the drag edge.
1493 | *
1494 | * @return the drag edge
1495 | */
1496 | public DragEdge getDragEdge() {
1497 | return mDragEdges.get(mCurrentDirectionIndex);
1498 | }
1499 |
1500 | /**
1501 | * Gets the drag distance.
1502 | *
1503 | * @return the drag distance
1504 | */
1505 | public int getDragDistance() {
1506 | return mDragDistance;
1507 | }
1508 |
1509 | /**
1510 | * Gets the show mode.
1511 | *
1512 | * @return the show mode
1513 | */
1514 | public ShowMode getShowMode() {
1515 | return mShowMode;
1516 | }
1517 |
1518 | /**
1519 | * Gets the surface view.
1520 | *
1521 | * @return the surface view
1522 | */
1523 | public ViewGroup getSurfaceView() {
1524 | return (ViewGroup) getChildAt(getChildCount() - 1);
1525 | }
1526 |
1527 | /**
1528 | * Gets the bottom views.
1529 | *
1530 | * @return the bottom views
1531 | */
1532 | public List getBottomViews() {
1533 | List lvg = new ArrayList();
1534 | // If the user has provided a map for views to
1535 | if (mBottomViewIdsSet) {
1536 | if (mDragEdges.contains(DragEdge.Left)) {
1537 | lvg.add(mLeftIndex, ((ViewGroup) findViewById(mBottomViewIdMap.get(DragEdge.Left))));
1538 | }
1539 | if (mDragEdges.contains(DragEdge.Right)) {
1540 | lvg.add(mRightIndex, ((ViewGroup) findViewById(mBottomViewIdMap.get(DragEdge.Right))));
1541 | }
1542 | if (mDragEdges.contains(DragEdge.Top)) {
1543 | lvg.add(mTopIndex, ((ViewGroup) findViewById(mBottomViewIdMap.get(DragEdge.Top))));
1544 | }
1545 | if (mDragEdges.contains(DragEdge.Bottom)) {
1546 | lvg.add(mBottomIndex, ((ViewGroup) findViewById(mBottomViewIdMap.get(DragEdge.Bottom))));
1547 | }
1548 | }
1549 | // Default behaviour is to simply use the first n-1 children in the order they're listed in the layout
1550 | // and return them in
1551 | else {
1552 | for (int i = 0; i < (getChildCount() - 1); i++) {
1553 | lvg.add((ViewGroup) getChildAt(i));
1554 | }
1555 | }
1556 | return lvg;
1557 | }
1558 |
1559 | // Pass the id of the view if set, otherwise pass -1
1560 | /**
1561 | * Sets the bottom view ids.
1562 | *
1563 | * @param left the left
1564 | * @param right the right
1565 | * @param top the top
1566 | * @param bottom the bottom
1567 | */
1568 | public void setBottomViewIds(int left, int right, int top, int bottom) {
1569 | if (mDragEdges.contains(DragEdge.Left)) {
1570 | if (left == EMPTY_LAYOUT) {
1571 | mBottomViewIdsSet = false;
1572 | } else {
1573 | mBottomViewIdMap.put(DragEdge.Left, left);
1574 | mBottomViewIdsSet = true;
1575 | }
1576 | }
1577 | if (mDragEdges.contains(DragEdge.Right)) {
1578 | if (right == EMPTY_LAYOUT) {
1579 | mBottomViewIdsSet = false;
1580 | } else {
1581 | mBottomViewIdMap.put(DragEdge.Right, right);
1582 | mBottomViewIdsSet = true;
1583 | }
1584 | }
1585 | if (mDragEdges.contains(DragEdge.Top)) {
1586 | if (top == EMPTY_LAYOUT) {
1587 | mBottomViewIdsSet = false;
1588 | } else {
1589 | mBottomViewIdMap.put(DragEdge.Top, top);
1590 | mBottomViewIdsSet = true;
1591 | }
1592 | }
1593 | if (mDragEdges.contains(DragEdge.Bottom)) {
1594 | if (bottom == EMPTY_LAYOUT) {
1595 | mBottomViewIdsSet = false;
1596 | } else {
1597 | mBottomViewIdMap.put(DragEdge.Bottom, bottom);
1598 | mBottomViewIdsSet = true;
1599 | }
1600 | }
1601 | }
1602 |
1603 | /**
1604 | * The Enum Status.
1605 | */
1606 | public enum Status {
1607 |
1608 | /** The Middle. */
1609 | Middle,
1610 |
1611 | /** The Open. */
1612 | Open,
1613 |
1614 | /** The Close. */
1615 | Close
1616 | }
1617 |
1618 | /**
1619 | * get the open status.
1620 | *
1621 | * Middle.
1622 | */
1623 | public Status getOpenStatus() {
1624 | int surfaceLeft = getSurfaceView().getLeft();
1625 | int surfaceTop = getSurfaceView().getTop();
1626 | if (surfaceLeft == getPaddingLeft() && surfaceTop == getPaddingTop()) return Status.Close;
1627 |
1628 | if (surfaceLeft == (getPaddingLeft() - mDragDistance) || surfaceLeft == (getPaddingLeft() + mDragDistance)
1629 | || surfaceTop == (getPaddingTop() - mDragDistance) || surfaceTop == (getPaddingTop() + mDragDistance))
1630 | return Status.Open;
1631 |
1632 | return Status.Middle;
1633 | }
1634 |
1635 | /**
1636 | * Process the surface release event.
1637 | *
1638 | * @param xvel the xvel
1639 | * @param yvel the yvel
1640 | */
1641 | private void processSurfaceRelease(float xvel, float yvel) {
1642 | if (xvel == 0 && getOpenStatus() == Status.Middle) close();
1643 |
1644 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left
1645 | || mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) {
1646 | if (xvel > 0) {
1647 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left)
1648 | open();
1649 | else close();
1650 | }
1651 | if (xvel < 0) {
1652 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left)
1653 | close();
1654 | else open();
1655 | }
1656 | } else {
1657 | if (yvel > 0) {
1658 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top)
1659 | open();
1660 | else close();
1661 | }
1662 | if (yvel < 0) {
1663 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top)
1664 | close();
1665 | else open();
1666 | }
1667 | }
1668 | }
1669 |
1670 | /**
1671 | * process bottom (PullOut mode) hand release event.
1672 | *
1673 | * @param xvel the xvel
1674 | * @param yvel the yvel
1675 | */
1676 | private void processBottomPullOutRelease(float xvel, float yvel) {
1677 |
1678 | if (xvel == 0 && getOpenStatus() == Status.Middle) close();
1679 |
1680 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left
1681 | || mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) {
1682 | if (xvel > 0) {
1683 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left)
1684 | open();
1685 | else close();
1686 | }
1687 | if (xvel < 0) {
1688 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left)
1689 | close();
1690 | else open();
1691 | }
1692 | } else {
1693 | if (yvel > 0) {
1694 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top)
1695 | open();
1696 | else close();
1697 | }
1698 |
1699 | if (yvel < 0) {
1700 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top)
1701 | close();
1702 | else open();
1703 | }
1704 | }
1705 | }
1706 |
1707 | /**
1708 | * process bottom (LayDown mode) hand release event.
1709 | *
1710 | * @param xvel the xvel
1711 | * @param yvel the yvel
1712 | */
1713 | private void processBottomLayDownMode(float xvel, float yvel) {
1714 |
1715 | if (xvel == 0 && getOpenStatus() == Status.Middle) close();
1716 |
1717 | int l = getPaddingLeft(), t = getPaddingTop();
1718 |
1719 | if (xvel < 0 && mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right)
1720 | l -= mDragDistance;
1721 | if (xvel > 0 && mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) l += mDragDistance;
1722 |
1723 | if (yvel > 0 && mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top) t += mDragDistance;
1724 | if (yvel < 0 && mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Bottom)
1725 | t -= mDragDistance;
1726 |
1727 | mDragHelper.smoothSlideViewTo(getSurfaceView(), l, t);
1728 | invalidate();
1729 | }
1730 |
1731 | /**
1732 | * smoothly open surface.
1733 | */
1734 | public void open() {
1735 | open(true, true);
1736 | }
1737 |
1738 | /**
1739 | * Open.
1740 | *
1741 | * @param smooth the smooth
1742 | */
1743 | public void open(boolean smooth) {
1744 | open(smooth, true);
1745 | }
1746 |
1747 | /**
1748 | * Open.
1749 | *
1750 | * @param smooth the smooth
1751 | * @param notify the notify
1752 | */
1753 | public void open(boolean smooth, boolean notify) {
1754 | ViewGroup surface = getSurfaceView(), bottom = getBottomViews().get(mCurrentDirectionIndex);
1755 | int dx, dy;
1756 | Rect rect = computeSurfaceLayoutArea(true);
1757 | if (smooth) {
1758 | mDragHelper.smoothSlideViewTo(getSurfaceView(), rect.left, rect.top);
1759 | } else {
1760 | dx = rect.left - surface.getLeft();
1761 | dy = rect.top - surface.getTop();
1762 | surface.layout(rect.left, rect.top, rect.right, rect.bottom);
1763 | if (getShowMode() == ShowMode.PullOut) {
1764 | Rect bRect = computeBottomLayoutAreaViaSurface(ShowMode.PullOut, rect);
1765 | bottom.layout(bRect.left, bRect.top, bRect.right, bRect.bottom);
1766 | }
1767 | if (notify) {
1768 | dispatchRevealEvent(rect.left, rect.top, rect.right, rect.bottom);
1769 | dispatchSwipeEvent(rect.left, rect.top, dx, dy);
1770 | } else {
1771 | safeBottomView();
1772 | }
1773 | }
1774 | invalidate();
1775 | }
1776 |
1777 | /**
1778 | * Open.
1779 | *
1780 | * @param edge the edge
1781 | */
1782 | public void open(DragEdge edge) {
1783 | switch (edge) {
1784 | case Left:
1785 | mCurrentDirectionIndex = mLeftIndex;
1786 | case Right:
1787 | mCurrentDirectionIndex = mRightIndex;
1788 | case Top:
1789 | mCurrentDirectionIndex = mTopIndex;
1790 | case Bottom:
1791 | mCurrentDirectionIndex = mBottomIndex;
1792 | }
1793 | open(true, true);
1794 | }
1795 |
1796 | /**
1797 | * Open.
1798 | *
1799 | * @param smooth the smooth
1800 | * @param edge the edge
1801 | */
1802 | public void open(boolean smooth, DragEdge edge) {
1803 | switch (edge) {
1804 | case Left:
1805 | mCurrentDirectionIndex = mLeftIndex;
1806 | case Right:
1807 | mCurrentDirectionIndex = mRightIndex;
1808 | case Top:
1809 | mCurrentDirectionIndex = mTopIndex;
1810 | case Bottom:
1811 | mCurrentDirectionIndex = mBottomIndex;
1812 | }
1813 | open(smooth, true);
1814 | }
1815 |
1816 | /**
1817 | * Open.
1818 | *
1819 | * @param smooth the smooth
1820 | * @param notify the notify
1821 | * @param edge the edge
1822 | */
1823 | public void open(boolean smooth, boolean notify, DragEdge edge) {
1824 | switch (edge) {
1825 | case Left:
1826 | mCurrentDirectionIndex = mLeftIndex;
1827 | case Right:
1828 | mCurrentDirectionIndex = mRightIndex;
1829 | case Top:
1830 | mCurrentDirectionIndex = mTopIndex;
1831 | case Bottom:
1832 | mCurrentDirectionIndex = mBottomIndex;
1833 | }
1834 | open(smooth, notify);
1835 | }
1836 |
1837 | /**
1838 | * smoothly close surface.
1839 | */
1840 | public void close() {
1841 | close(true, true);
1842 | }
1843 |
1844 | /**
1845 | * Close.
1846 | *
1847 | * @param smooth the smooth
1848 | */
1849 | public void close(boolean smooth) {
1850 | close(smooth, true);
1851 | }
1852 |
1853 | /**
1854 | * close surface.
1855 | *
1856 | * @param smooth smoothly or not.
1857 | * @param notify if notify all the listeners.
1858 | */
1859 | public void close(boolean smooth, boolean notify) {
1860 | ViewGroup surface = getSurfaceView();
1861 | int dx, dy;
1862 | if (smooth)
1863 | mDragHelper.smoothSlideViewTo(getSurfaceView(), getPaddingLeft(), getPaddingTop());
1864 | else {
1865 | Rect rect = computeSurfaceLayoutArea(false);
1866 | dx = rect.left - surface.getLeft();
1867 | dy = rect.top - surface.getTop();
1868 | surface.layout(rect.left, rect.top, rect.right, rect.bottom);
1869 | if (notify) {
1870 | dispatchRevealEvent(rect.left, rect.top, rect.right, rect.bottom);
1871 | dispatchSwipeEvent(rect.left, rect.top, dx, dy);
1872 | } else {
1873 | safeBottomView();
1874 | }
1875 | }
1876 | invalidate();
1877 | }
1878 |
1879 | /**
1880 | * Toggle.
1881 | */
1882 | public void toggle() {
1883 | toggle(true);
1884 | }
1885 |
1886 | /**
1887 | * Toggle.
1888 | *
1889 | * @param smooth the smooth
1890 | */
1891 | public void toggle(boolean smooth) {
1892 | if (getOpenStatus() == Status.Open)
1893 | close(smooth);
1894 | else if (getOpenStatus() == Status.Close) open(smooth);
1895 | }
1896 |
1897 | /**
1898 | * a helper function to compute the Rect area that surface will hold in.
1899 | *
1900 | * @param open open status or close status.
1901 | * @return the rect
1902 | */
1903 | private Rect computeSurfaceLayoutArea(boolean open) {
1904 | int l = getPaddingLeft(), t = getPaddingTop();
1905 | if (open) {
1906 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left)
1907 | l = getPaddingLeft() + mDragDistance;
1908 | else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right)
1909 | l = getPaddingLeft() - mDragDistance;
1910 | else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top)
1911 | t = getPaddingTop() + mDragDistance;
1912 | else t = getPaddingTop() - mDragDistance;
1913 | }
1914 | return new Rect(l, t, l + getMeasuredWidth(), t + getMeasuredHeight());
1915 | }
1916 |
1917 | /**
1918 | * Compute bottom layout area via surface.
1919 | *
1920 | * @param mode the mode
1921 | * @param surfaceArea the surface area
1922 | * @return the rect
1923 | */
1924 | private Rect computeBottomLayoutAreaViaSurface(ShowMode mode, Rect surfaceArea) {
1925 | Rect rect = surfaceArea;
1926 |
1927 | int bl = rect.left, bt = rect.top, br = rect.right, bb = rect.bottom;
1928 | if (mode == ShowMode.PullOut) {
1929 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left)
1930 | bl = rect.left - mDragDistance;
1931 | else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right)
1932 | bl = rect.right;
1933 | else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top)
1934 | bt = rect.top - mDragDistance;
1935 | else bt = rect.bottom;
1936 |
1937 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left || mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right) {
1938 | bb = rect.bottom;
1939 | br = bl + getBottomViews().get(mCurrentDirectionIndex).getMeasuredWidth();
1940 | } else {
1941 | bb = bt + getBottomViews().get(mCurrentDirectionIndex).getMeasuredHeight();
1942 | br = rect.right;
1943 | }
1944 | } else if (mode == ShowMode.LayDown) {
1945 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left)
1946 | br = bl + mDragDistance;
1947 | else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right)
1948 | bl = br - mDragDistance;
1949 | else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top)
1950 | bb = bt + mDragDistance;
1951 | else bt = bb - mDragDistance;
1952 |
1953 | }
1954 | return new Rect(bl, bt, br, bb);
1955 |
1956 | }
1957 |
1958 | /**
1959 | * Compute bottom lay down.
1960 | *
1961 | * @param dragEdge the drag edge
1962 | * @return the rect
1963 | */
1964 | private Rect computeBottomLayDown(DragEdge dragEdge) {
1965 | int bl = getPaddingLeft(), bt = getPaddingTop();
1966 | int br, bb;
1967 | if (dragEdge == DragEdge.Right) {
1968 | bl = getMeasuredWidth() - mDragDistance;
1969 | } else if (dragEdge == DragEdge.Bottom) {
1970 | bt = getMeasuredHeight() - mDragDistance;
1971 | }
1972 | if (dragEdge == DragEdge.Left || dragEdge == DragEdge.Right) {
1973 | br = bl + mDragDistance;
1974 | bb = bt + getMeasuredHeight();
1975 | } else {
1976 | br = bl + getMeasuredWidth();
1977 | bb = bt + mDragDistance;
1978 | }
1979 | return new Rect(bl, bt, br, bb);
1980 | }
1981 |
1982 | /**
1983 | * Sets the on double click listener.
1984 | *
1985 | * @param doubleClickListener the new on double click listener
1986 | */
1987 | public void setOnDoubleClickListener(DoubleClickListener doubleClickListener) {
1988 | mDoubleClickListener = doubleClickListener;
1989 | }
1990 |
1991 | /**
1992 | * The listener interface for receiving doubleClick events.
1993 | * The class that is interested in processing a doubleClick
1994 | * event implements this interface, and the object created
1995 | * with that class is registered with a component using the
1996 | * component's addDoubleClickListener method. When
1997 | * the doubleClick event occurs, that object's appropriate
1998 | * method is invoked.
1999 | *
2000 | * @see DoubleClickEvent
2001 | */
2002 | public interface DoubleClickListener {
2003 |
2004 | /**
2005 | * On double click.
2006 | *
2007 | * @param layout the layout
2008 | * @param surface the surface
2009 | */
2010 | public void onDoubleClick(SwipeLayout layout, boolean surface);
2011 | }
2012 |
2013 | /**
2014 | * Dp2px.
2015 | *
2016 | * @param dp the dp
2017 | * @return the int
2018 | */
2019 | private int dp2px(float dp) {
2020 | return (int) (dp * getContext().getResources().getDisplayMetrics().density + 0.5f);
2021 | }
2022 |
2023 | /**
2024 | * Gets the drag edges.
2025 | *
2026 | * @return the drag edges
2027 | */
2028 | public List getDragEdges() {
2029 | return mDragEdges;
2030 | }
2031 |
2032 | /**
2033 | * Sets the drag edges.
2034 | *
2035 | * @param mDragEdges the new drag edges
2036 | */
2037 | public void setDragEdges(List mDragEdges) {
2038 | this.mDragEdges = mDragEdges;
2039 | mCurrentDirectionIndex = 0;
2040 | populateIndexes();
2041 | updateBottomViews();
2042 | }
2043 |
2044 | /**
2045 | * Sets the drag edges.
2046 | *
2047 | * @param mDragEdges the new drag edges
2048 | */
2049 | public void setDragEdges(DragEdge... mDragEdges) {
2050 | this.mDragEdges = new ArrayList();
2051 | for (DragEdge e : mDragEdges) {
2052 | this.mDragEdges.add(e);
2053 | }
2054 | mCurrentDirectionIndex = 0;
2055 | populateIndexes();
2056 | updateBottomViews();
2057 | }
2058 |
2059 | /**
2060 | * Populate indexes.
2061 | */
2062 | private void populateIndexes() {
2063 | mLeftIndex = this.mDragEdges.indexOf(DragEdge.Left);
2064 | mRightIndex = this.mDragEdges.indexOf(DragEdge.Right);
2065 | mTopIndex = this.mDragEdges.indexOf(DragEdge.Top);
2066 | mBottomIndex = this.mDragEdges.indexOf(DragEdge.Bottom);
2067 | }
2068 |
2069 | /**
2070 | * Gets the current offset.
2071 | *
2072 | * @return the current offset
2073 | */
2074 | private float getCurrentOffset() {
2075 | if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Left) return mLeftEdgeSwipeOffset;
2076 | else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Right)
2077 | return mRightEdgeSwipeOffset;
2078 | else if (mDragEdges.get(mCurrentDirectionIndex) == DragEdge.Top) return mTopEdgeSwipeOffset;
2079 | else return mBottomEdgeSwipeOffset;
2080 | }
2081 |
2082 | /**
2083 | * Update bottom views.
2084 | */
2085 | private void updateBottomViews() {
2086 | // removeAllViews();
2087 | // addView(getBottomViews().get(mCurrentDirectionIndex));
2088 | // addView(getSurfaceView());
2089 | // getBottomViews().get(mCurrentDirectionIndex).bringToFront();
2090 | // getSurfaceView().bringToFront();
2091 | if (mShowMode == ShowMode.PullOut)
2092 | layoutPullOut();
2093 | else if (mShowMode == ShowMode.LayDown) layoutLayDown();
2094 |
2095 | safeBottomView();
2096 |
2097 | if (mOnLayoutListeners != null) for (int i = 0; i < mOnLayoutListeners.size(); i++) {
2098 | mOnLayoutListeners.get(i).onLayout(this);
2099 | }
2100 | }
2101 | }
2102 |
--------------------------------------------------------------------------------