summaryrefslogtreecommitdiffstats
path: root/dom/system/gonk/VolumeCommand.h
blob: 022965b5e02b371b7da35ed1d68d4d66dfcafcd8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_system_volumecommand_h__
#define mozilla_system_volumecommand_h__

#include "nsString.h"
#include "nsISupportsImpl.h"
#include "mozilla/RefPtr.h"
#include <algorithm>
#include <vold/ResponseCode.h>

namespace mozilla {
namespace system {

class Volume;
class VolumeCommand;

/***************************************************************************
*
*   The VolumeResponseCallback class is an abstract base class. The ResponseReceived
*   method will be called for each response received.
*
*   Depending on the command, there may be multiple responses for the
*   command. Done() will return true if this is the last response.
*
*   The responses from vold are all of the form:
*
*     <ResponseCode> <String>
*
*   Valid Response codes can be found in the vold/ResponseCode.h header.
*
***************************************************************************/

class VolumeResponseCallback
{
protected:
  virtual ~VolumeResponseCallback() {}

public:
  NS_INLINE_DECL_REFCOUNTING(VolumeResponseCallback)
  VolumeResponseCallback()
    : mResponseCode(0), mPending(false) {}

  bool Done() const
  {
    // Response codes from the 200, 400, and 500 series all indicated that
    // the command has completed.

    return (mResponseCode >= ::ResponseCode::CommandOkay)
        && (mResponseCode < ::ResponseCode::UnsolicitedInformational);
  }

  bool WasSuccessful() const
  {
    return mResponseCode == ::ResponseCode::CommandOkay;
  }

  bool              IsPending() const     { return mPending; }
  int               ResponseCode() const  { return mResponseCode; }
  const nsCString  &ResponseStr() const   { return mResponseStr; }

protected:
  virtual void ResponseReceived(const VolumeCommand* aCommand) = 0;

private:
  friend  class VolumeCommand;  // Calls HandleResponse and SetPending

  void HandleResponse(const VolumeCommand* aCommand,
                      int aResponseCode,
                      nsACString& aResponseStr)
  {
    mResponseCode = aResponseCode;
#if ANDROID_VERSION >= 17
    // There's a sequence number here that we don't care about
    // We expect it to be 0. See VolumeCommand::SetCmd
    mResponseStr = Substring(aResponseStr, 2);
#else
    mResponseStr = aResponseStr;
#endif
    if (mResponseCode >= ::ResponseCode::CommandOkay) {
      // This is a final response.
      mPending = false;
    }
    ResponseReceived(aCommand);
  }

  void SetPending(bool aPending) { mPending = aPending; }

  int       mResponseCode;  // The response code parsed from vold
  nsCString mResponseStr;   // The rest of the line.
  bool      mPending;       // Waiting for response?
};

/***************************************************************************
*
*   The VolumeCommand class is an abstract base class used to encapsulate
*   volume commands send to vold.
*
*   See VolumeManager.h for a list of the volume commands.
*
*   Commands sent to vold need an explicit null character so we add one
*   to the command to ensure that it's included in the length.
*
*   All of these commands are asynchronous in nature, and the
*   ResponseReceived callback will be called when a response is available.
*
***************************************************************************/

class VolumeCommand
{
protected:
  virtual ~VolumeCommand() {}

public:
  NS_INLINE_DECL_REFCOUNTING(VolumeCommand)

  VolumeCommand(VolumeResponseCallback* aCallback)
    : mBytesConsumed(0),
      mCallback(aCallback)
  {
    SetCmd(NS_LITERAL_CSTRING(""));
  }

  VolumeCommand(const nsACString& aCommand, VolumeResponseCallback* aCallback)
    : mBytesConsumed(0),
      mCallback(aCallback)
  {
    SetCmd(aCommand);
  }

  void SetCmd(const nsACString& aCommand)
  {
    mCmd.Truncate();
#if ANDROID_VERSION >= 17
    // JB requires a sequence number at the beginning of messages.
    // It doesn't matter what we use, so we use 0.
    mCmd = "0 ";
#endif
    mCmd.Append(aCommand);
    // Add a null character. We want this to be included in the length since
    // vold uses it to determine the end of the command.
    mCmd.Append('\0');
  }

  const char* CmdStr() const    { return mCmd.get(); }
  const char* Data() const      { return mCmd.Data() + mBytesConsumed; }
  size_t BytesConsumed() const  { return mBytesConsumed; }

  size_t BytesRemaining() const
  {
    return mCmd.Length() - std::min(mCmd.Length(), mBytesConsumed);
  }

  void ConsumeBytes(size_t aNumBytes)
  {
    mBytesConsumed += std::min(BytesRemaining(), aNumBytes);
  }

private:
  friend class VolumeManager;   // Calls SetPending & HandleResponse

  void SetPending(bool aPending)
  {
    if (mCallback) {
      mCallback->SetPending(aPending);
    }
  }

  void HandleResponse(int aResponseCode, nsACString& aResponseStr)
  {
    if (mCallback) {
      mCallback->HandleResponse(this, aResponseCode, aResponseStr);
    }
  }

  nsCString mCmd;           // Command being sent
  size_t    mBytesConsumed; // How many bytes have been sent

  // Called when a response to the command is received.
  RefPtr<VolumeResponseCallback>  mCallback;
};

class VolumeActionCommand : public VolumeCommand
{
public:
  VolumeActionCommand(Volume* aVolume, const char* aAction,
                      const char* aExtraArgs, VolumeResponseCallback* aCallback);

private:
  RefPtr<Volume>  mVolume;
};

class VolumeListCommand : public VolumeCommand
{
public:
  VolumeListCommand(VolumeResponseCallback* aCallback);
};

} // system
} // mozilla

#endif  // mozilla_system_volumecommand_h__